Credit Michael Patton and the IEEE in the document header. Add URLs to the
[obnox/wireshark/wip.git] / ncp2222.py
1 #!/usr/bin/python
2
3 """
4 Creates C code from a table of NCP type 0x2222 packet types.
5 (And 0x3333, which are the replies, but the packets are more commonly
6 refered to as type 0x2222; the 0x3333 replies are understood to be
7 part of the 0x2222 "family")
8
9 Data comes from "Programmer's Guide to the NetWare Core Protocol"
10 by Steve Conner and Dianne Conner.
11
12 Novell provides info at:
13
14 http://developer.novell.com/ndk  (where you can download an *.exe file which
15 installs a PDF)
16
17 or
18
19 http://developer.novell.com/ndk/doc/docui/index.htm#../ncp/ncp__enu/data/
20 for a badly-formatted HTML version of the same PDF.
21
22
23 $Id: ncp2222.py,v 1.7 2000/09/22 16:37:49 gram Exp $
24
25 Copyright (c) 2000 by Gilbert Ramirez <gram@xiexie.org>
26
27 This program is free software; you can redistribute it and/or
28 modify it under the terms of the GNU General Public License
29 as published by the Free Software Foundation; either version 2
30 of the License, or (at your option) any later version.
31  
32 This program is distributed in the hope that it will be useful,
33 but WITHOUT ANY WARRANTY; without even the implied warranty of
34 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35 GNU General Public License for more details.
36  
37 You should have received a copy of the GNU General Public License
38 along with this program; if not, write to the Free Software
39 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
40 """
41
42 import sys
43
44 ##############################################################################
45 # Global containers
46 ##############################################################################
47
48 class UniqueCollection:
49         """The UniqueCollection class stores objects which can be compared to other
50         objects of the same class. If two objects in the collection are equivalent,
51         only one is stored."""
52
53         def __init__(self, name):
54                 "Constructor"
55                 self.name = name
56                 self.members = []
57
58         def Add(self, object):
59                 """Add an object to the members lists, if a comparable object
60                 doesn't already exist. The object that is in the member list, that is
61                 either the object that was added or the comparable object that was
62                 already in the member list, is returned."""
63
64                 # Is 'object' a duplicate of some other member?
65                 for member in self.members:
66                         if member == object:
67                                 return member
68
69                 # Store object in our members list.
70                 self.members.append(object)
71                 return object
72
73         def Members(self):
74                 "Returns the list of members."
75                 return self.members
76
77         def HasMember(self, object):
78                 "Does the list of members contain the object?"
79                 for member in self.members:
80                         if member == object:
81                                 return 1
82                 return 0
83
84
85 packets         = UniqueCollection('NCP Packet Descriptions')
86 compcode_lists  = UniqueCollection('Completion Code Lists')
87 ptvc_lists      = UniqueCollection('PTVC Lists')
88
89
90 ##############################################################################
91
92 class NamedList:
93         "NamedList's keep track of PTVC's and Completion Codes"
94         def __init__(self, name, list):
95                 "Constructor"
96                 self.name = name
97                 self.list = list
98
99         def __cmp__(self, other):
100                 "Compare this NamedList to another"
101
102                 # Python will do a deep comparison of lists within lists.
103                 if self.list < other.list:
104                         return -1
105                 elif self.list > other.list:
106                         return 1
107                 else:
108                         return 0
109
110         def __repr__(self):
111                 "String representation"
112                 return "NamedList: " + `self.list`
113
114         def Name(self, new_name = None):
115                 "Get/Set name of list"
116                 if new_name != None:
117                         self.name = new_name
118                 return self.name
119
120         def Records(self):
121                 "Returns record lists"
122                 return self.list
123
124         def Null(self):
125                 "Is there no list (different from an empty list)?"
126                 return self.list == None
127
128         def Empty(self):
129                 "It the list empty (different from a null list)?"
130                 assert(not self.Null())
131
132                 if self.list:
133                         return 0
134                 else:
135                         return 1
136
137
138 class PTVC(NamedList):
139         """ProtoTree TVBuff Cursor List ("PTVC List") Class"""
140
141         def __init__(self, name, records):
142                 "Constructor"
143                 self.list = []
144                 NamedList.__init__(self, name, self.list)
145
146                 expected_offset = None
147
148                 # Make a PTVCRecord object for each list in 'records'
149                 for record in records:
150                         ptvc_rec = PTVCRecord(record)
151
152                         if expected_offset == None:
153                                 expected_offset = ptvc_rec.Offset()
154
155                         elif expected_offset == -1:
156                                 pass
157
158                         elif expected_offset != ptvc_rec.Offset():
159                                 sys.stderr.write("Expected offset in %s to be %d\n" % (name,
160                                         expected_offset))
161                                 sys.exit(1)
162
163                         # We can't make a PTVC list from a variable-length
164                         # packet, unless it's FT_UINT_STRING
165                         if type(ptvc_rec.Length()) == type(()):
166                                 if isinstance(ptvc_rec.Field(), nstring8):
167                                         expected_offset = -1
168                                         pass
169                                 else:
170                                         self.list = None
171                                         return
172
173                         elif expected_offset > -1:
174                                 expected_offset = expected_offset + ptvc_rec.Length()
175
176
177                         self.list.append(ptvc_rec)
178
179 class PTVCRecord:
180         def __init__(self, record):
181                 "Constructor"
182                 self.offset     = record[0]
183                 self.length     = record[1]
184                 self.field      = record[2]
185
186                 # Small sanity check
187                 field_length = self.field.Length()
188
189 #               if type(field_length) != type(self.length):
190 #                       sys.stderr.write("Length types do not match")
191 #                       sys.exit(1)
192
193 #               if type(field_length) == type(0) and field_length > 0:
194 #                       if field_length != self.length:
195 #                               sys.stderr.write("Length %d does not match field length %d for field %s\n" % (self.length, field_length, self.field.Abbreviation()))
196 #                               sys.exit(1)
197
198                 # Check if an endianness override is given
199                 try:
200                         self.endianness = record[3]
201
202                 # If no endianness was given in the record, then
203                 # use the field's default endianness.
204                 except IndexError:
205                         self.endianness = self.field.Endianness()
206
207         def __cmp__(self, other):
208                 "Comparison operator"
209                 if self.length < other.length:
210                         return -1
211                 elif self.length > other.length:
212                         return 1
213
214                 if self.field != other.field:
215                         return 1
216                 elif self.endianness != other.endianness:
217                         return 1
218                 else:
219                         return 0
220
221         def __repr__(self):
222                 "String representation"
223                 endianness = 'FALSE'
224                 if self.endianness == LE:
225                         endianness = 'TRUE'
226
227                 length = -1
228
229                 if type(self.length) == type(0):
230                         length = self.length
231                 else:
232                         var_length = self.field.Length()
233                         if var_length > 0:
234                                 length = var_length
235
236                 if length > -1:
237                         return "{ &%s, %d, %s }" % (self.field.HFName(),
238                                         length, endianness)
239                 else:
240                         length = "PTVC_VARIABLE_LENGTH"
241                         return "{ &%s, %s, %s }" % (self.field.HFName(),
242                                         length, endianness)
243
244         def Offset(self):
245                 return self.offset
246
247         def Length(self):
248                 return self.length
249
250         def Field(self):
251                 return self.field
252
253
254 ##############################################################################
255
256 class NCP:
257         "NCP Packet class"
258         def __init__(self, func_code, description, group):
259                 "Constructor"
260                 self.func_code          = func_code
261                 self.description        = description
262                 self.group              = group
263                 self.codes              = None
264                 self.request_records    = None
265                 self.reply_records      = None
266
267                 if not groups.has_key(group):
268                         sys.stderr.write("NCP 0x%x has invalid group '%s'\n" % (self.func_code, group))
269                         sys.exit(1)
270
271                 if self.HasSubFunction():
272                         # NCP Function with SubFunction
273                         self.start_offset = 10
274                 else:
275                         # Simple NCP Function
276                         self.start_offset = 7
277
278         def FunctionCode(self, part=None):
279                 "Returns the function code for this NCP packet."
280                 if part == None:
281                         return self.func_code
282                 elif part == 'high':
283                         if self.HasSubFunction():
284                                 return (self.func_code & 0xff00) >> 8
285                         else:
286                                 return self.func_code
287                 elif part == 'low':
288                         if self.HasSubFunction():
289                                 return self.func_code & 0x00ff
290                         else:
291                                 return 0x00
292                 else:
293                         sys.stderr.write("Unknown directive '%s' for function_code()\n" % (part))
294                         sys.exit(1)
295
296         def HasSubFunction(self):
297                 "Does this NPC packet require a subfunction field?"
298                 if self.func_code <= 0xff:
299                         return 0
300                 else:
301                         return 1
302
303         def Description(self):
304                 return self.description
305
306         def Group(self):
307                 return self.group
308
309         def PTVCRequest(self):
310                 return self.ptvc_request
311
312         def PTVCReply(self):
313                 return self.ptvc_reply
314
315         def Request(self, size, records=[]):
316                 self.request_size = size
317                 self.request_records = records
318                 if self.HasSubFunction():
319                         self.CheckRecords(size, records, "Request", 10)
320                 else:
321                         self.CheckRecords(size, records, "Request", 7)
322                 self.ptvc_request = self.MakePTVC(records, "request")
323
324         def Reply(self, size, records=[]):
325                 self.reply_size = size
326                 self.reply_records = records
327                 self.CheckRecords(size, records, "Reply", 8)
328                 self.ptvc_reply = self.MakePTVC(records, "reply")
329
330         def CheckRecords(self, size, records, descr, min_hdr_length):
331                 "Simple sanity check"
332                 min = size
333                 max = size
334                 if type(size) == type(()):
335                         min = size[0]
336                         max = size[1]
337
338                 lower = min_hdr_length
339                 upper = min_hdr_length
340
341                 for record in records:
342                         rec_size = record[1]
343                         rec_lower = rec_size
344                         rec_upper = rec_size
345                         if type(rec_size) == type(()):
346                                 rec_lower = rec_size[0]
347                                 rec_upper = rec_size[1]
348
349                         lower = lower + rec_lower
350                         upper = upper + rec_upper
351
352                 error = 0
353                 if min != lower:
354                         sys.stderr.write("%s records for 2222/0x%x sum to %d bytes minimum, but param1 shows %d\n" \
355                                 % (descr, self.FunctionCode(), lower, min))
356                         error = 1
357                 if max != upper:
358                         sys.stderr.write("%s records for 2222/0x%x sum to %d bytes maximum, but param1 shows %d\n" \
359                                 % (descr, self.FunctionCode(), upper, max))
360                         error = 1
361
362                 if error == 1:
363                         sys.exit(1)
364
365
366         def MakePTVC(self, records, name_suffix):
367                 """Makes a PTVC out of a request or reply record list. Possibly adds
368                 it to the global list of PTVCs (the global list is a UniqueCollection,
369                 so an equivalent PTVC may already be in the global list)."""
370
371                 name = "%s_%s" % (self.CName(), name_suffix)
372                 ptvc = PTVC(name, records)
373                 return ptvc_lists.Add(ptvc)
374
375         def CName(self):
376                 "Returns a C symbol based on the NCP function code"
377                 return "ncp_0x%x" % (self.func_code)
378
379         def Variables(self):
380                 """Returns a list of variables used in the request and reply records.
381                 A variable is listed only once, even if it is used twice (once in
382                 the request, once in the reply)."""
383
384                 variables = {}
385                 if self.request_records:
386                         for record in self.request_records:
387                                 var = record[2]
388                                 variables[var] = 1
389
390                 if self.reply_records:
391                         for record in self.reply_records:
392                                 var = record[2]
393                                 variables[var] = 1
394
395                 return variables.keys()
396
397
398         def CompletionCodes(self, codes=None):
399                 """Sets or returns the list of completion codes. Internally, a NamedList
400                 is used to store the completion codes, but the caller of this function
401                 never realizes that because Python lists are the input and output."""
402
403                 if codes == None:
404                         return self.codes
405
406                 # Sanity check
407                 okay = 1
408                 for code in codes:
409                         if not errors.has_key(code):
410                                 sys.stderr.write("Errors table does not have key 0x%04x for NCP=0x%x\n" % (code,
411                                         self.func_code))
412                                 okay = 0
413
414                 # Delay the exit until here so that the programmer can get the complete
415                 # list of missing error codes
416                 if not okay:
417                         sys.exit(1)
418
419                 # Create CompletionCode (NamedList) object and possible add it to
420                 # the global list of completion code lists.
421                 name = "%s_errors" % (self.CName())
422                 codes.sort()
423                 codes_list = NamedList(name, codes)
424                 self.codes = compcode_lists.Add(codes_list)
425
426                 self.Finalize()
427
428         def Finalize(self):
429                 """Adds the NCP object to the global collection of NCP objects. This
430                 is done automatically after setting the CompletionCode list. Yes, this
431                 is a shortcut, but it makes our list of NCP packet definitions look
432                 neater, since an explicit "add to global list of packets" is not needed."""
433
434                 # Add packet to global collection of packets
435                 if packets.HasMember(self):
436                         sys.stderr.write("Already have NCP Function Code 0x%x\n" % \
437                                 (self.func_code))
438                         sys.exit(1)
439                 else:
440                         packets.Add(self)
441
442
443
444 ##############################################################################
445
446 LE              = 1             # Little-Endian
447 BE              = 0             # Big-Endian
448 NA              = -1            # Not Applicable
449
450 class Type:
451         " Virtual class for NCP field types"
452         type            = "Type"
453         ftype           = None
454         disp            = "BASE_DEC"
455         endianness      = NA
456         values          = []
457
458         def __init__(self, abbrev, descr, bytes, endianness = NA):
459                 self.abbrev = abbrev
460                 self.descr = descr
461                 self.bytes = bytes
462
463         def Length(self):
464                 return self.bytes
465
466         def Abbreviation(self):
467                 return self.abbrev
468
469         def Description(self):
470                 return self.descr
471
472         def HFName(self):
473                 return "hf_ncp_" + self.abbrev
474
475         def DFilter(self):
476                 return "ncp." + self.abbrev
477
478         def EtherealFType(self):
479                 return self.ftype
480
481         def Display(self, newval=None):
482                 if newval != None:
483                         self.disp = newval
484                 return self.disp
485
486         def ValuesName(self):
487                 return "NULL"
488
489         def Mask(self):
490                 return 0
491
492         def Endianness(self):
493                 return self.endianness
494
495 class byte(Type):
496         type    = "byte"
497         ftype   = "FT_UINT8"
498         def __init__(self, abbrev, descr):
499                 Type.__init__(self, abbrev, descr, 1)
500
501 # Same as above. Both are provided for convenience
502 class uint8(Type):
503         type    = "uint8"
504         ftype   = "FT_UINT8"
505         def __init__(self, abbrev, descr):
506                 Type.__init__(self, abbrev, descr, 1)
507
508 class uint16(Type):
509         type    = "uint16"
510         ftype   = "FT_UINT16"
511         def __init__(self, abbrev, descr, endianness = BE):
512                 Type.__init__(self, abbrev, descr, 2, endianness)
513
514 class uint32(Type):
515         type    = "uint32"
516         ftype   = "FT_UINT32"
517         def __init__(self, abbrev, descr, endianness = BE):
518                 Type.__init__(self, abbrev, descr, 4, endianness)
519
520 class nstring8(Type):
521         """A string of up to 255 characters. The first byte
522         gives the string length. Thus, the total length of
523         this data structure is from 1 to 256 bytes, including
524         the first byte."""
525
526         type    = "nstring8"
527         ftype   = "FT_UINT_STRING"
528         def __init__(self, abbrev, descr):
529                 Type.__init__(self, abbrev, descr, 1)
530
531 class fw_string(Type):
532         """A fixed-width string of n bytes."""
533
534         type    = "fw_string"
535         ftype   = "FT_STRING"
536
537         def __init__(self, abbrev, descr, bytes):
538                 Type.__init__(self, abbrev, descr, bytes)
539
540
541 class stringz(Type):
542         "NUL-terminated string, with a maximum length"
543
544         type    = "stringz"
545         ftype   = "FT_STRINGZ"
546         def __init__(self, abbrev, descr):
547                 Type.__init__(self, abbrev, descr, -1)
548
549 class val_string(Type):
550         """Abstract class for val_stringN, where N is number
551         of bits that key takes up."""
552
553         type    = "val_string"
554         disp    = 'BASE_HEX'
555
556         def __init__(self, abbrev, descr, val_string_array, endianness = BE):
557                 Type.__init__(self, abbrev, descr, self.bytes, endianness)
558                 self.values = val_string_array
559
560         def __repr__(self):
561                 result = "static const value_string %s[] = {\n" \
562                                 % (self.ValuesCName())
563                 for val_record in self.values:
564                         value   = val_record[0]
565                         text    = val_record[1]
566                         value_repr = self.value_format % value
567                         result = result + '\t{ %s,\t"%s" },\n' \
568                                         % (value_repr, text)
569
570                 value_repr = self.value_format % 0
571                 result = result + "\t{ %s,\tNULL },\n" % (value_repr)
572                 result = result + "};\n"
573
574                 return result
575
576         def ValuesCName(self):
577                 return "ncp_%s_vals" % (self.abbrev)
578
579         def ValuesName(self):
580                 return "VALS(%s)" % (self.ValuesCName())
581
582 class val_string8(val_string):
583         type            = "val_string8"
584         ftype           = "FT_UINT8"
585         bytes           = 1
586         value_format    = "0x%02x"
587
588 class val_string16(val_string):
589         type            = "val_string16"
590         ftype           = "FT_UINT16"
591         bytes           = 2
592         value_format    = "0x%04x"
593
594 class bytes(Type):
595         type    = 'bytes'
596         ftype   = 'FT_BYTES'
597
598         def __init__(self, abbrev, descr, bytes):
599                 Type.__init__(self, abbrev, descr, bytes, NA)
600
601 #class data(Type):
602 #       type    = "data"
603 #       ftype   = "FT_BYTES"
604 #       def __init__(self, abbrev, descr):
605 #               Type.__init__(self, abbrev, descr, -1)
606 #
607 #       def length_var(self, length_var):
608 #               self.length_var = length_var
609
610 ##############################################################################
611 # NCP Field Types. Defined in Appendix A of "Programmer's Guide..."
612 ##############################################################################
613 BufferSize      = uint16("buffer_size", "Buffer Size")
614 ConnectionNumber        = uint32("connection_number", "Connection Number")
615 DirHandle       = byte("dir_handle", "Directory Handle")
616
617 FileHandle      = bytes("file_handle", "File Handle", 6)
618
619 FileLock        = val_string8("file_lock", "File Lock", [
620         [ 0x00, "Not Locked" ],
621         [ 0xfe, "Locked by file lock" ],
622         [ 0xff, "Unknown" ],
623 ])
624
625 FileOffset      = uint32("file_offset", "File Offset")
626 FilePath        = nstring8("file_path", "File Path")
627 FileSize        = uint32("file_size", "File Size")
628 JobType         = uint16("job_type", "Job Type")
629
630 LogicalLockType = val_string8("logical_lock_type", "Logical Lock Type", [
631         [ 0x00, "Log file" ],
632         [ 0x01, "Log and lock file for exclusive read/write use" ],
633         [ 0x03, "Log and lock with shareable read-only use" ],
634 ])
635
636 LogicalRecordName       = nstring8("logical_record_name", "Logical Record Name")
637 LogLockType     = byte("log_lock_type", "Log Lock Type")
638
639 MaxBytes        = uint16("max_bytes", "Maximum Number of Bytes")
640 NumBytes        = uint16("num_bytes", "Number of Bytes")
641
642 ObjectFlags     = val_string8("object_flags", "Object Flags", [
643         [ 0x00, "Dynamic object" ],
644         [ 0x01, "Static object" ],
645 ])
646
647 ObjectHasProperties = val_string8("object_has_properites", "Object Has Properties", [
648         [ 0x00, "No properties" ],
649         [ 0xff, "One or more properties" ],
650 ])
651
652 ObjectID        = uint32("object_id", "Object ID")
653 ObjectID.Display('BASE_HEX')
654
655 ObjectName      = nstring8("object_name", "Object Name")
656 ObjectName1     = fw_string("object_name1", "Object Name", 48)
657
658 ObjectSecurity  = val_string8("object_security", "Object Security", [
659         [ 0x00, "Anyone can read or modify the object" ],
660         [ 0x01, "Client logged into the file server can read the object" ],
661         [ 0x02, "Client logged into the file server with the object's name, type and password can read the object" ],
662         [ 0x03, "Client with supervisor equivalence can read the object" ],
663         [ 0x04, "Only the operating system can read the object" ],
664         [ 0x10, "Client logged into the file server can modify the object" ],
665         [ 0x20, "Client logged into the file server with the object's name, type and password can modify the object" ],
666         [ 0x30, "Client with supervisor equivalence can modify the object" ],
667         [ 0x40, "Only the operating system can modify the object" ],
668 ])
669
670 ObjectType      = val_string16("object_type", "Object Type", [
671         [ 0x0000,       "Unknown" ],
672         [ 0x0001,       "User" ],
673         [ 0x0002,       "User group" ],
674         [ 0x0003,       "Print queue" ],
675         [ 0x0004,       "NetWare file server" ],
676         [ 0x0005,       "Job server" ],
677         [ 0x0006,       "Gateway" ],
678         [ 0x0007,       "Print server" ],
679         [ 0x0008,       "Archive queue" ],
680         [ 0x0009,       "Archive server" ],
681         [ 0x000a,       "Job queue" ],
682         [ 0x000b,       "Administration" ],
683         [ 0x0021,       "NAS SNA gateway" ],
684         [ 0x0026,       "Remote bridge server" ],
685         [ 0x0027,       "TCP/IP gateway" ],
686 ])
687
688 PropertyHasMoreSegments = val_string8("property_has_more_segments",
689         "Property Has More Segments", [
690         [ 0x00, "Is last segment" ],
691         [ 0xff, "More segments are available" ],
692 ])
693
694 PropertyName    = nstring8("property_name", "Property Name")
695 PropertyData    = bytes("property_data", "Property Data", 128)
696 PropertySegment = uint8("property_segment", "Property Segment")
697
698 PropertyType    = val_string8("property_type", "Property Type", [
699         [ 0x00, "Static item" ],
700         [ 0x01, "Dynamic item" ],
701         [ 0x02, "Static set" ],
702         [ 0x03, "Dynamic set" ],
703 ])
704
705 TaskNumber      = uint32("task_number", "Task Number")
706 TimeoutLimit    = uint16("timeout_limit", "Timeout Limit")
707 UnknownByte     = byte("unknown_byte", "Unknown Byte")
708
709
710 ##############################################################################
711 # NCP Groups
712 ##############################################################################
713 groups = {}
714 groups['accounting']    = "Accounting"
715 groups['afp']           = "AFP"
716 groups['auditing']      = "Auditing"
717 groups['bindery']       = "Bindery"
718 groups['connection']    = "Connection"
719 groups['directory']     = "Directory"
720 groups['extended']      = "Extended Attribute"
721 groups['file']          = "File"
722 groups['fileserver']    = "File Server"
723 groups['message']       = "Message"
724 groups['migration']     = "Data Migration"
725 groups['misc']          = "Miscellaneous"
726 groups['name']          = "Name Space"
727 groups['nds']           = "NetWare Directory"
728 groups['print']         = "Print"
729 groups['queue']         = "Queue"
730 groups['sync']          = "Synchronization"
731 groups['tss']           = "Transaction Tracking"
732
733 ##############################################################################
734 # NCP Errors
735 ##############################################################################
736 errors = {}
737 errors[0x0000] = "Ok"
738 errors[0x0001] = "Transaction tracking is available"
739 errors[0x0002] = "Ok. The data has been written"
740
741 errors[0x0100] = "One or more of the ConnectionNumbers in the send list are invalid"
742 errors[0x0101] = "Invalid space limit"
743 errors[0x0102] = "Insufficient disk space"
744 errors[0x0103] = "Queue server cannot add jobs"
745 errors[0x0104] = "Out of disk space"
746 errors[0x0105] = "Semaphore overflow"
747
748 errors[0x0200] = "One or more clients in the send list are not logged in"
749 errors[0x0201] = "Queue server cannot attach"
750
751 errors[0x0300] = "One or more clients in the send list are not accepting messages"
752
753 errors[0x0400] = "Client already has message"
754 errors[0x0401] = "Queue server cannot service job"
755
756 errors[0x7e00] = "NCP failed boundary check"
757
758 errors[0x8000] = "Lock fail"
759 errors[0x8100] = "A file handle could not be allocated by the file server"
760 errors[0x8200] = "Unauthorized to open the file"
761 errors[0x8300] = "Unable to read/write the volume. Possible bad sector on the file server"
762
763 errors[0x8400] = "Unauthorized to create the directory"
764 errors[0x8401] = "Unauthorized to create the file"
765
766 errors[0x8500] = "Unauthorized to delete the specified file"
767 errors[0x8501] = "Unauthorized to overwrite an existing file in this directory"
768
769 errors[0x8700] = "An unexpected character was encountered in the filename"
770 errors[0x8800] = "Invalid file handle"
771 errors[0x8900] = "Unauthorized to search this directory"
772 errors[0x8a00] = "Unauthorized to delete this directory"
773 errors[0x8b00] = "Unauthorized to rename a file in this directory"
774
775 errors[0x8c00] = "No set privileges"
776 errors[0x8c01] = "Unauthorized to modify a file in this directory"
777 errors[0x8c02] = "Unauthorized to change the restriction on this volume"
778
779 errors[0x8d00] = "Some of the affected files are in use by another client"
780 errors[0x8d01] = "The affected file is in use"
781
782 errors[0x8e00] = "All of the affected files are in use by another client"
783 errors[0x8f00] = "Some of the affected files are read-only"
784
785 errors[0x9000] = "An attempt to modify a read-only volume occurred"
786 errors[0x9001] = "All of the affected files are read-only"
787
788 errors[0x9100] = "Some of the affected files already exist"
789
790 errors[0x9200] = "Directory with the new name already exists"
791 errors[0x9201] = "All of the affected files already exist"
792
793 errors[0x9300] = "Unauthorized to read from this file"
794 errors[0x9400] = "Unauthorized to write to this file"
795 errors[0x9500] = "The affected file is detached"
796
797 errors[0x9600] = "The file server has run out of memory to service this request"
798 errors[0x9601] = "No alloc space for message"
799
800 errors[0x9800] = "The affected volume is not mounted"
801 errors[0x9801] = "The volume associated with VolumeNumber is not mounted"
802 errors[0x9802] = "The resulting voume does not exist"
803 errors[0x9803] = "The destination volume is not mounted"
804
805 errors[0x9900] = "The file server has run out of directory space on the affected volume"
806 errors[0x9a00] = "The request attempted to rename the affected file to another volume"
807
808 errors[0x9b00] = "DirHandle is not associated with a valid directory path"
809 errors[0x9b01] = "A resulting directory handle is not associated with a valid directory path"
810 errors[0x9b02] = "The directory associated with DirHandle does not exist"
811 errors[0x9b03] = "Bad directory handle"
812
813 errors[0x9c00] = "The resulting path is not valid"
814 errors[0x9c01] = "The resulting file path is not valid"
815 errors[0x9c02] = "The resulting directory path is not valid"
816 errors[0x9c03] = "Invalid path"
817
818 errors[0x9d00] = "A directory handle was not available for allocation"
819
820 errors[0x9e00] = "The name of the directory does not conform to a legal name for this name space"
821 errors[0x9e01] = "The new directory name does not conform to a legal name for this name space"
822
823 errors[0x9f00] = "The request attempted to delete a directory that is in use by another client"
824
825 errors[0xa000] = "The request attempted to delete a directory that is not empty"
826 errors[0xa100] = "An unrecoverable error occured on the affected directory"
827 errors[0xa200] = "The request attempted to read from a file region that is physically locked"
828 errors[0xa400] = "Invalid directory rename attempted"
829
830 errors[0xbf00] = "Requests for this name space are not valid on this volume"
831
832 errors[0xc000] = "Unauthorized to retrieve accounting data"
833 errors[0xc100] = "The ACCOUNT_BALANCE property does not exist"
834 errors[0xc200] = "The object has exceeded its credit limit"
835 errors[0xc300] = "Too many holds have been placed against this account"
836 errors[0xc400] = "The client account has been disabled"
837
838 errors[0xc500] = "Access to the account has been denied because of intruder detection"
839 errors[0xc501] = "Login lockout"
840
841 errors[0xc600] = "The caller does not have operator priviliges"
842 errors[0xc601] = "The client does not have operator priviliges"
843
844 errors[0xd000] = "Queue error"
845 errors[0xd100] = "The queue does not exist"
846
847 errors[0xd200] = "A queue server is not associated with this queue"
848 errors[0xd201] = "A queue server is not associated with the selected queue"
849 errors[0xd202] = "No queue server"
850
851 errors[0xd300] = "No queue rights"
852
853 errors[0xd400] = "The queue is full and cannot accept another request"
854 errors[0xd401] = "The queue associated with ObjectId is full and cannot accept another request"
855
856 errors[0xd500] = "A job does not exist in this queue"
857 errors[0xd501] = "No queue job"
858 errors[0xd502] = "The job associated with JobNumber does not exist in this queue"
859
860 errors[0xd600] = "The file server does not allow unencrypted passwords"
861 errors[0xd601] = "No job right"
862
863 errors[0xd700] = "Bad account"
864 errors[0xd701] = "The old and new password strings are identical"
865 errors[0xd702] = "The job is currently being serviced"
866 errors[0xd703] = "The queue is currently servicing a job"
867 errors[0xd704] = "Queue servicing"
868
869 errors[0xd800] = "Queue not active"
870
871 errors[0xd900] = "The file server cannot accept another connection as it has reached its limit"
872 errors[0xd901] = "The client is not security equivalent to one of the objects in the Q_SERVERS group property of the target queue"
873 errors[0xd902] = "Station is not a server"
874
875 errors[0xda00] = "Attempted to login to the file server during a restricted time period"
876 errors[0xda01] = "Queue halted"
877
878 errors[0xdb00] = "Attempted to login to the file server from an unauthorized workstation or network"
879 errors[0xdb01] = "The queue cannot attach another queue server"
880 errors[0xdb02] = "Maximum queue servers"
881
882 errors[0xde00] = "Attempted to login to the file server with an incorrect password"
883 errors[0xdf00] = "Attempted to login to the file server with a password that has expired"
884
885 errors[0xe700] = "No disk track"
886 errors[0xe800] = "Write to group"
887 errors[0xe900] = "The object is already a member of the group property"
888
889 errors[0xea00] = "No such member"
890 errors[0xea01] = "The bindery object is not a member of the set"
891 errors[0xea02] = "Non-existent member"
892
893 errors[0xeb00] = "The property is not a set property"
894
895 errors[0xec00] = "No such set"
896 errors[0xec01] = "The set property does not exist"
897
898 errors[0xed00] = "Property exists"
899 errors[0xed01] = "The property already exists"
900 errors[0xed02] = "An attempt was made to create a bindery object property that already exists"
901
902 errors[0xee00] = "The object already exists"
903 errors[0xee01] = "The bindery object already exists"
904
905 errors[0xef00] = "Illegal name"
906 errors[0xef01] = "Illegal characters in ObjectName field"
907 errors[0xef02] = "Invalid name"
908
909 errors[0xf000] = "A wildcard was detected in a field that does not support wildcards"
910 errors[0xf001] = "An illegal wildcard was detected in ObjectName"
911
912 errors[0xf100] = "The client does not have the rights to access this bindery object"
913 errors[0xf101] = "Bindery security"
914 errors[0xf102] = "Invalid bindery security"
915
916 errors[0xf200] = "Unauthorized to read from this object"
917 errors[0xf300] = "Unauthorized to rename this object"
918
919 errors[0xf400] = "Unauthorized to delete this object"
920 errors[0xf401] = "No object delete privileges"
921 errors[0xf402] = "Unauthorized to delete this queue"
922
923 errors[0xf500] = "Unauthorized to create this object"
924 errors[0xf501] = "No object create"
925
926 errors[0xf600] = "No property delete"
927 errors[0xf601] = "Unauthorized to delete the property of this object"
928 errors[0xf602] = "Unauthorized to delete this property"
929
930 errors[0xf700] = "Unauthorized to create this property"
931 errors[0xf701] = "No property create privilege"
932
933 errors[0xf800] = "Unauthorized to write to this property"
934 errors[0xf900] = "Unauthorized to read this property"
935 errors[0xfa00] = "Temporary remap error"
936
937 errors[0xfb00] = "No such property"
938 errors[0xfb01] = "The file server does not support this request"
939 errors[0xfb02] = "The specified property does not exist"
940 errors[0xfb03] = "The PASSWORD property does not exist for this bindery object"
941
942 errors[0xfc00] = "The message queue cannot accept another message"
943 errors[0xfc01] = "The trustee associated with ObjectId does not exist"
944 errors[0xfc02] = "The specified bindery object does not exist"
945 errors[0xfc03] = "The bindery object associated with ObjectID does not exist"
946 errors[0xfc04] = "A bindery object does not exist that matches"
947 errors[0xfc05] = "The specified queue does not exist"
948 errors[0xfc06] = "No such object"
949 errors[0xfc07] = "The queue associated with ObjectID does not exist"
950
951 errors[0xfd00] = "Bad station number"
952 errors[0xfd01] = "The connection associated with ConnectionNumber is not active"
953 errors[0xfd02] = "Lock collision"
954 errors[0xfd03] = "Transacktion tracking is disabled"
955
956 errors[0xfe00] = "I/O failure"
957 errors[0xfe01] = "The files containing the bindery on the file server are locked"
958 errors[0xfe02] = "A file with the specified name already exists in this directory"
959 errors[0xfe03] = "No more restrictions were found"
960 errors[0xfe04] = "The file server was unable to lock the file within the specified time limit"
961 errors[0xfe05] = "The file server was unable to lock all files within the specified time limit"
962 errors[0xfe06] = "The bindery object associated with ObjectID is not a valid trustee"
963 errors[0xfe07] = "Directory locked"
964 errors[0xfe08] = "Bindery locked"
965 errors[0xfe09] = "Invalid semaphore name length"
966 errors[0xfe0a] = "The file server was unable to complete the operation within the specified time limit"
967 errors[0xfe0b] = "Transaction restart"
968
969 errors[0xff00] = "Failure"
970 errors[0xff01] = "Lock error"
971 errors[0xff02] = "File not found"
972 errors[0xff03] = "The file not found or cannot be unlocked"
973 errors[0xff04] = "Record not found"
974 errors[0xff05] = "The logical record was not found"
975 errors[0xff06] = "The printer associated with PrinterNumber does not exist"
976 errors[0xff07] = "No such printer"
977 errors[0xff08] = "Unable to complete the request"
978 errors[0xff09] = "Unauthorized to change privileges of this trustee"
979 errors[0xff0a] = "No files matching the search criteria were found"
980 errors[0xff0b] = "A file matching the search criteria was not found"
981 errors[0xff0c] = "Verification failed"
982 errors[0xff0d] = "Object associated with ObjectID is not a manager"
983 errors[0xff0e] = "Invalid initial semaphore value"
984 errors[0xff0f] = "The semaphore handle is not valid"
985 errors[0xff10] = "SemaphoreHandle is not associated with a valid sempahore"
986 errors[0xff11] = "Invalid semaphore handle"
987 errors[0xff12] = "Transaction tracking is not available"
988 errors[0xff13] = "The transaction has not yet been written to disk"
989 errors[0xff14] = "Directory already exists"
990 errors[0xff15] = "The file already exists and the deletion flag was not set"
991 errors[0xff16] = "No matching files or directories were found"
992 errors[0xff17] = "A file or directory matching the search criteria was not found"
993 errors[0xff18] = "The file already exists"
994 errors[0xff19] = "No files found"
995
996 ##############################################################################
997 # NCP Packets. Here I list functions and subfunctions in hexadecimal like the
998 # NCP book (and I believe LanAlyzer does this too).
999 # However, Novell lists these in decimal in their on-line documentation.
1000 ##############################################################################
1001 # 2222/02
1002 pkt = NCP(0x02, "File Release Lock", 'sync')
1003 pkt.Request(7)
1004 pkt.Reply(8)
1005 pkt.CompletionCodes([0x0000, 0xff00])
1006
1007 #
1008 # Untested
1009 #
1010 # 2222/03
1011 #pkt = NCP(0x03, "Log File", 'sync')
1012 #pkt.request( (12, 267), [
1013 #       [ 7, 1, DirHandle ],
1014 #       [ 8, 1, LogLockType ],
1015 #       [ 9, 2, TimeoutLimit, LE ],
1016 #       [ 11, (1, 256), FilePath ],
1017 #       ])
1018 #pkt.completion_codes([0x0000, 0x8200, 0x9600, 0xfe00, 0xff01])
1019 #
1020 ## 2222/04
1021 #pkt = NCP(0x04, "Lock File Set", 'sync')
1022 #pkt.request([
1023 #       [ 7, TimeoutLimit ],
1024 #       ])
1025 #pkt.completion_codes([0xfe, 0xff01])
1026 #
1027 ## 2222/05
1028 #pkt = NCP(0x05, "Release File", 'sync')
1029 #pkt.request([
1030 #       [ 7, DirHandle ],
1031 #       [ 8, FilePath ],
1032 #       ])
1033 #pkt.completion_codes([0x7e, 0x98, 0x9b, 0x9c, 0xff02])
1034 #
1035 ## 2222/06
1036 #pkt = NCP(0x06, "Release File Set", 'sync')
1037 #pkt.request([
1038 #       [ 7, UnknownByte ],
1039 #       ])
1040 #pkt.completion_codes()
1041 #
1042 ## 2222/07
1043 #pkt = NCP(0x07, "Clear File", 'sync')
1044 #pkt.request([
1045 #       [ 7, DirHandle ],
1046 #       [ 8, FilePath ],
1047 #       ])
1048 #pkt.completion_codes([0x7e, 0x96, 0x98, 0x9b, 0x9c,
1049 #       0xa1, 0xfd, 0xff])
1050 #
1051 ## 2222/08
1052 #pkt = NCP(0x08, "Clear File Set", 'sync')
1053 #pkt.request([
1054 #       [ 7, FileLock ],
1055 #       ])
1056 #pkt.completion_codes([0x7e])
1057 #
1058 ## 2222/09
1059 #pkt = NCP(0x09, "Log Logical Record", 'sync')
1060 #pkt.request([
1061 #       [ 7, LogicalLockType ],
1062 #       [ 8, TimeoutLimit_be ],
1063 #       [ 10, LogicalRecordName ],
1064 #       ])
1065 #pkt.completion_codes([0x96, 0xfe, 0xff])
1066 #
1067 ## 2222/0a
1068 #pkt = NCP(0x0a, "Lock Logical Record Set", 'sync')
1069 #pkt.request([
1070 #       [ 7, LogicalLockType ],
1071 #       [ 8, TimeoutLimit_le ],
1072 #       ])
1073 #pkt.completion_codes([0xfe, 0xff])
1074 #
1075 ## 2222/0b
1076 #pkt = NCP(0x0b, "Clear Logical Record", 'sync')
1077 #pkt.request([
1078 #       [7, LogicalRecordName ],
1079 #       ])
1080 #pkt.completion_codes([0xff]
1081 ## 2222/0c
1082 ## 2222/0d
1083 ## 2222/0e
1084 ## 2222/0f
1085 ## 2222/11
1086 #
1087 ## 2222/1100
1088 #pkt = NCP(0x1100, "Lock Logical Record Set", 'sync')
1089 #pkt.request([
1090 #       [ 10, var_length_data("data").length_var("packetlength") ]
1091 #       ])
1092 #pkt.completion_codes()
1093 #
1094
1095 # 2222/1735
1096 pkt = NCP(0x1735, "Get Bindery Object ID", 'bindery')
1097 pkt.Request((13,60), [
1098         [ 10, 2, ObjectType ],
1099         [ 12, (1,48), ObjectName ],
1100 ])
1101 pkt.Reply(62, [
1102         [ 8, 4, ObjectID ],
1103         [ 12, 2, ObjectType ],
1104         [ 14, 48, ObjectName1 ],
1105 ])
1106 pkt.CompletionCodes([0x0000, 0x9600, 0xef01, 0xf000, 0xfc02,
1107         0xfe01, 0xff00])
1108
1109 # 2222/1737
1110 pkt = NCP(0x1737, "Scan Bindery Object", 'bindery')
1111 pkt.Request((17,64), [
1112         [ 10, 4, ObjectID ],
1113         [ 14, 2, ObjectType ],
1114         [ 16, (1,48), ObjectName ],
1115 ])
1116 pkt.Reply(65, [
1117         [ 8, 4, ObjectID ],
1118         [ 12, 2, ObjectType ],
1119         [ 14, 48, ObjectName1 ],
1120         [ 62, 1, ObjectFlags ],
1121         [ 63, 1, ObjectSecurity ],
1122         [ 64, 1, ObjectHasProperties ],
1123 ])
1124 pkt.CompletionCodes([0x0000, 0x9600, 0xef01, 0xfc02,
1125         0xfe01, 0xff00])
1126
1127 # 2222/173D
1128 pkt = NCP(0x173D, "Read Property Value", 'bindery')
1129 pkt.Request((15,77), [
1130         [ 10, 2, ObjectType ],
1131         [ 12, (1,48), ObjectName ],
1132         [ -1, 1, PropertySegment ],
1133         [ -1, (1,16), PropertyName ],
1134 ])
1135 pkt.Reply(138, [
1136         [ 8, 128, PropertyData ],
1137         [ 136, 1, PropertyHasMoreSegments ],
1138         [ 137, 1, PropertyType ],
1139 ])
1140 pkt.CompletionCodes([0x0000, 0x8800, 0x9300, 0x9600, 0xec01,
1141         0xf000, 0xf100, 0xf900, 0xfb02, 0xfc02, 0xfe01, 0xff00 ])
1142
1143 # 2222/177C
1144 pkt = NCP(0x177C, "Service Queue Job", 'queue')
1145 pkt.Request(16, [
1146         [ 10, 4, ObjectID ],
1147         [ 14, 2, JobType ],
1148 ])
1149 pkt.Reply(24, [ # XXX - 76, [
1150         [ 8, 4, ConnectionNumber ],
1151         [ 12, 4, TaskNumber ],
1152         [ 16, 4, ObjectID ],
1153         [ 20, 4, ObjectID ],
1154         # XXX - DateTime
1155 ])
1156 # These completion codes are not documented, but guessed.
1157 pkt.CompletionCodes([0x0000, 0x9900, 0xd000, 0xd100, 0xd201, 0xd300,
1158         0xd401, 0xd502, 0xd601, 0xd704, 0xd800, 0xd901, 0xda01, 0xdb01,
1159         0xff00 ])
1160
1161 # 2222/18
1162 pkt = NCP(0x18, "End of Job", 'connection')
1163 pkt.Request(7)
1164 pkt.Reply(8)
1165 pkt.CompletionCodes([0x0000])
1166
1167 # 2222/19
1168 pkt = NCP(0x19, "Logout", 'connection')
1169 pkt.Request(7)
1170 pkt.Reply(8)
1171 pkt.CompletionCodes([0x0000])
1172
1173 # 2222/21
1174 pkt = NCP(0x21, "Negotiate Buffer Size", 'connection')
1175 pkt.Request(9, [
1176         [ 7, 2, BufferSize ],
1177 ])
1178 pkt.Reply(10, [
1179         [ 8, 2, BufferSize ],
1180 ])
1181 pkt.CompletionCodes([0x0000])
1182
1183 # 2222/42
1184 pkt = NCP(0x42, "Close File", 'file')
1185 pkt.Request(13, [
1186         [ 7, 6, FileHandle ],
1187 ])
1188 pkt.Reply(8)
1189 pkt.CompletionCodes([0x0000, 0xff00])
1190
1191 # 2222/47
1192 pkt = NCP(0x47, "Get Current Size of File", 'file')
1193 pkt.Request(13, [
1194         [ 7, 6, FileHandle ],
1195 ])
1196 pkt.Reply(12, [
1197         [ 8, 4, FileSize ],
1198 ])
1199 pkt.CompletionCodes([0x0000, 0x8800])
1200
1201 # 2222/48
1202 pkt = NCP(0x48, "Read From A File", 'file')
1203 pkt.Request(20, [
1204         [ 7, 1, UnknownByte ],
1205         [ 8, 6, FileHandle ],
1206         [ 14, 4, FileOffset ],  # my nomenclature
1207         [ 18, 2, MaxBytes ],    # my nomenclature
1208 ])
1209 pkt.Reply(10, [ # XXX - (10,-1), [
1210         [ 8, 2, NumBytes ],     # my nomenclature
1211         # XXX
1212 ])
1213 pkt.CompletionCodes([0x0000, 0x8800, 0x9300, 0xff00])
1214
1215 # 2222/5701     - no info
1216 # 2222/5702     - no info
1217 # 2222/5706     - no info
1218 # 2222/5714     - no info
1219 # 2222/68       - no info
1220 # 2222/72       - no info
1221
1222 ##############################################################################
1223 # Produce C code
1224 ##############################################################################
1225 if __name__ == '__main__':
1226         print "/*"
1227         print " * Generated automatically from %s" % (sys.argv[0])
1228         print " * Do not edit this file manually, as all changes will be lost."
1229         print " */\n"
1230
1231         print """
1232 /*
1233  * This program is free software; you can redistribute it and/or
1234  * modify it under the terms of the GNU General Public License
1235  * as published by the Free Software Foundation; either version 2
1236  * of the License, or (at your option) any later version.
1237  * 
1238  * This program is distributed in the hope that it will be useful,
1239  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1240  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1241  * GNU General Public License for more details.
1242  * 
1243  * You should have received a copy of the GNU General Public License
1244  * along with this program; if not, write to the Free Software
1245  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
1246  */
1247
1248 #ifdef HAVE_CONFIG_H
1249 # include "config.h"
1250 #endif
1251
1252 #include <glib.h>
1253 #include "packet.h"
1254 #include "conversation.h"
1255 #include "ptvcursor.h"
1256 #include "packet-ncp-int.h"
1257     
1258 static int hf_ncp_func = -1;
1259 static int hf_ncp_length = -1;
1260 static int hf_ncp_subfunc = -1;
1261 static int hf_ncp_completion_code = -1;
1262 static int hf_ncp_connection_status = -1;
1263         """
1264
1265         # Look at all packet types in the packets collection, and cull information
1266         # from them.
1267         packet_keys = []
1268         for packet in packets.Members():
1269                 packet_keys.append(packet.FunctionCode())
1270         packet_keys.sort()
1271
1272         errors_used_list = []
1273         errors_used_hash = {}
1274         groups_used_list = []
1275         groups_used_hash = {}
1276         variables_used_hash = {}
1277
1278         for pkt in packets.Members():
1279                 # Determine which error codes are used.
1280                 codes = pkt.CompletionCodes()
1281                 for code in codes.Records():
1282                         if not errors_used_hash.has_key(code):
1283                                 errors_used_hash[code] = len(errors_used_list)
1284                                 errors_used_list.append(code)
1285
1286                 # Determine which groups are used.
1287                 group = pkt.Group()
1288                 if not groups_used_hash.has_key(group):
1289                         groups_used_hash[group] = len(groups_used_list)
1290                         groups_used_list.append(group)
1291
1292                 # Determine which variables are used.
1293                 vars = pkt.Variables()
1294                 for var in vars:
1295                         variables_used_hash[var] = 1
1296
1297
1298
1299         # Print the hf variable declarations
1300         for var in variables_used_hash.keys():
1301                 print "static int " + var.HFName() + " = -1;"
1302
1303
1304         # Print the value_string's
1305         for var in variables_used_hash.keys():
1306                 if var.type == "val_string8" or var.type == "val_string16":
1307                         print ""
1308                         print `var`
1309
1310
1311         print """
1312 void
1313 proto_register_ncp2222(void)
1314 {
1315
1316         static hf_register_info hf[] = {
1317         { &hf_ncp_func,
1318         { "Function", "ncp.func", FT_UINT8, BASE_HEX, NULL, 0x0, "" }},
1319
1320         { &hf_ncp_length,
1321         { "Packet Length", "ncp.length", FT_UINT16, BASE_DEC, NULL, 0x0, "" }},
1322
1323         { &hf_ncp_subfunc,
1324         { "SubFunction", "ncp.subfunc", FT_UINT8, BASE_HEX, NULL, 0x0, "" }},
1325
1326         { &hf_ncp_completion_code,
1327         { "Completion Code", "ncp.completion_code", FT_UINT8, BASE_HEX, NULL, 0x0, "" }},
1328
1329         { &hf_ncp_connection_status,
1330         { "Connection Status", "ncp.connection_status", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1331         """
1332
1333         # Print the registration code for the hf variables
1334         for var in variables_used_hash.keys():
1335                 print "\t{ &%s," % (var.HFName())
1336                 print "\t{ \"%s\", \"%s\", %s, %s, %s, 0x%x, \"\" }},\n" % \
1337                         (var.Description(), var.DFilter(),
1338                         var.EtherealFType(), var.Display(), var.ValuesName(),
1339                         var.Mask())
1340
1341         print """\t};
1342
1343                 proto_register_field_array(proto_ncp, hf, array_length(hf));
1344         }
1345         """
1346
1347
1348         # Determine which error codes are not used
1349         errors_not_used = {}
1350         # Copy the keys from the error list...
1351         for code in errors.keys():
1352                 errors_not_used[code] = 1
1353         # ... and remove the ones that *were* used.
1354         for code in errors_used_list:
1355                 del errors_not_used[code]
1356
1357         # Print a remark showing errors not used
1358         list_errors_not_used = errors_not_used.keys()
1359         list_errors_not_used.sort()
1360         for code in list_errors_not_used:
1361                 print "/* Error 0x%04x not used: %s */" % (code, errors[code])
1362         print "\n"
1363
1364         # Print the errors table
1365         print "/* Error strings. */"
1366         print "static const char *ncp_errors[] = {"
1367         for code in errors_used_list:
1368                 print '\t/* %02d (0x%04x) */ "%s",' % (errors_used_hash[code], code, errors[code])
1369         print "};\n"
1370
1371
1372
1373
1374         # Determine which groups are not used
1375         groups_not_used = {}
1376         # Copy the keys from the group list...
1377         for group in groups.keys():
1378                 groups_not_used[group] = 1
1379         # ... and remove the ones that *were* used.
1380         for group in groups_used_list:
1381                 del groups_not_used[group]
1382
1383         # Print a remark showing groups not used
1384         list_groups_not_used = groups_not_used.keys()
1385         list_groups_not_used.sort()
1386         for group in list_groups_not_used:
1387                 print "/* Group not used: %s = %s */" % (group, groups[group])
1388         print "\n"
1389
1390         # Print the groups table
1391         print "/* Group strings. */"
1392         print "static const char *ncp_groups[] = {"
1393         for group in groups_used_list:
1394                 print '\t/* %02d (%s) */ "%s",' % (groups_used_hash[group], group, groups[group])
1395         print "};\n"
1396
1397         # Print PTVC's
1398         print "/* PTVC records. These are re-used to save space. */"
1399         for ptvc in ptvc_lists.Members():
1400                 if not ptvc.Null() and not ptvc.Empty():
1401                         print "static const ptvc_record %s[] = {" % (ptvc.Name())
1402                         records = ptvc.Records()
1403                         for ptvc_rec in records:
1404                                 print "\t%s," % (ptvc_rec)
1405                         print "\t{ NULL, 0, 0 }"
1406                         print "};\n"
1407
1408         # Print error_equivalency tables
1409         print "/* Error-Equivalency Tables. These are re-used to save space. */"
1410         for compcodes in compcode_lists.Members():
1411                 errors = compcodes.Records()
1412                 # Make sure the record for error = 0x00 comes last.
1413                 print "static const error_equivalency %s[] = {" % (compcodes.Name())
1414                 for error in errors:
1415                         error_in_packet = error >> 8;
1416                         ncp_error_index = errors_used_hash[error]
1417                         print "\t{ 0x%02x, %d }, /* 0x%04x */" % (error_in_packet,
1418                                 ncp_error_index, error)
1419                 print "\t{ 0x00, -1 }\n};\n"
1420
1421
1422         # Print ncp_record packet records
1423         print "#define SUBFUNC 0xff"
1424         print "#define NOSUB   0x00"
1425
1426         print "/* ncp_record structs for packets */"
1427         print "static const ncp_record ncp_packets[] = {"
1428         for pkt in packets.Members():
1429                 if pkt.HasSubFunction():
1430                         subfunc_string = "SUBFUNC"
1431                 else:
1432                         subfunc_string = "NOSUB"
1433                 print '\t{ 0x%02x, 0x%02x, %s, "%s",' % (pkt.FunctionCode('high'),
1434                         pkt.FunctionCode('low'), subfunc_string, pkt.Description()),
1435
1436                 print '\t%d /* %s */,' % (groups_used_hash[pkt.Group()], pkt.Group())
1437
1438                 ptvc = pkt.PTVCRequest()
1439                 if not ptvc.Null() and not ptvc.Empty():
1440                         ptvc_request = ptvc.Name()
1441                 else:
1442                         ptvc_request = 'NULL'
1443
1444                 ptvc = pkt.PTVCReply()
1445                 if not ptvc.Null() and not ptvc.Empty():
1446                         ptvc_reply = ptvc.Name()
1447                 else:
1448                         ptvc_reply = 'NULL'
1449
1450                 errors = pkt.CompletionCodes()
1451                 print '\t\t%s, NULL, %s, NULL,' % (ptvc_request, ptvc_reply)
1452                 print '\t\t%s },\n' % (errors.Name())
1453
1454         print '\t{ 0, 0, 0, NULL }'
1455         print "};\n"
1456
1457         print "/* ncp funcs that require a subfunc */"
1458         print "static const guint8 ncp_func_requires_subfunc[] = {"
1459         hi_seen = {}
1460         for pkt in packets.Members():
1461                 if pkt.HasSubFunction():
1462                         hi_func = pkt.FunctionCode('high')
1463                         if not hi_seen.has_key(hi_func):
1464                                 print "\t0x%02x," % (hi_func)
1465                                 hi_seen[hi_func] = 1
1466         print "\t0"
1467         print "};\n"
1468
1469
1470         print '#include "packet-ncp2222.inc"'
1471
1472