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