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")
9 Data comes from "Programmer's Guide to the NetWare Core Protocol"
10 by Steve Conner and Dianne Conner.
12 Novell provides info at:
14 http://developer.novell.com/ndk (where you can download an *.exe file which
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.
23 $Id: ncp2222.py,v 1.14 2002/01/21 07:36:31 guy Exp $
25 Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
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.
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.
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.
51 ##############################################################################
53 ##############################################################################
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."""
60 def __init__(self, name):
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."""
71 # Is 'object' a duplicate of some other member?
72 for member in self.members:
76 # Store object in our members list.
77 self.members.append(object)
81 "Returns the list of members."
84 def HasMember(self, object):
85 "Does the list of members contain the object?"
86 for member in self.members:
92 # This list needs to be defined before the NCP types are defined,
93 # because the NCP types are defined in the global scope, not inside
95 ptvc_lists = UniqueCollection('PTVC Lists')
97 ##############################################################################
100 "NamedList's keep track of PTVC's and Completion Codes"
101 def __init__(self, name, list):
106 def __cmp__(self, other):
107 "Compare this NamedList to another"
109 # Python will do a deep comparison of lists within lists.
110 if self.list < other.list:
112 elif self.list > other.list:
118 "String representation"
119 return "NamedList: " + `self.list`
121 def Name(self, new_name = None):
122 "Get/Set name of list"
128 "Returns record lists"
132 "Is there no list (different from an empty list)?"
133 return self.list == None
136 "It the list empty (different from a null list)?"
137 assert(not self.Null())
145 class PTVC(NamedList):
146 """ProtoTree TVBuff Cursor List ("PTVC List") Class"""
148 def __init__(self, name, records):
150 NamedList.__init__(self, name, [])
152 expected_offset = None
154 # Make a PTVCRecord object for each list in 'records'
155 for record in records:
160 # Check if an endianness override is given
162 endianness = record[3]
164 # If no endianness was given in the record, then
165 # use the field's default endianness.
167 endianness = field.Endianness()
169 ptvc_rec = PTVCRecord(field, length, endianness)
171 if expected_offset == None:
172 expected_offset = offset
174 elif expected_offset == -1:
177 elif expected_offset != offset:
178 sys.stderr.write("Expected offset in %s to be %d\n" % (name,
182 # We can't make a PTVC list from a variable-length
183 # packet, unless it's FT_UINT_STRING
184 if type(ptvc_rec.Length()) == type(()):
185 if isinstance(ptvc_rec.Field(), nstring8):
192 elif expected_offset > -1:
193 expected_offset = expected_offset + ptvc_rec.Length()
196 self.list.append(ptvc_rec)
199 x = "static const ptvc_record %s[] = {\n" % (self.Name())
200 for ptvc_rec in self.list:
201 x = x + "\t%s,\n" % (ptvc_rec)
202 x = x + "\t{ NULL, 0, 0, NULL }\n"
207 class PTVCBitfield(PTVC):
208 def __init__(self, name, vars):
209 NamedList.__init__(self, name, [])
212 ptvc_rec = PTVCRecord(var, var.Length(), var.Endianness())
213 self.list.append(ptvc_rec)
216 return "ett_%s" % (self.Name(),)
218 ett_name = self.ETTName()
219 x = "static gint %s;\n" % (ett_name,)
221 x = x + "static const ptvc_record ptvc_%s[] = {\n" % (self.Name())
222 for ptvc_rec in self.list:
223 x = x + "\t%s,\n" % (ptvc_rec)
224 x = x + "\t{ NULL, 0, 0, NULL }\n"
227 x = x + "static const sub_ptvc_record %s = {\n" % (self.Name(),)
228 x = x + "\t&%s,\n" % (ett_name,)
229 x = x + "\tptvc_%s,\n" % (self.Name(),)
234 def __init__(self, field, length, endianness):
238 self.endianness = endianness
240 def __cmp__(self, other):
241 "Comparison operator"
242 if self.length < other.length:
244 elif self.length > other.length:
247 if self.field != other.field:
249 elif self.endianness != other.endianness:
255 "String representation"
257 if self.endianness == LE:
260 # Default the length to this value
261 length = "PTVC_VARIABLE_LENGTH"
263 if type(self.length) == type(0):
266 var_length = self.field.Length()
270 sub_ptvc_name = self.field.PTVCName()
271 if sub_ptvc_name != "NULL":
272 sub_ptvc_name = "&%s" % (sub_ptvc_name,)
274 return "{ &%s, %s, %s, %s }" % (self.field.HFName(),
275 length, endianness, sub_ptvc_name)
286 ##############################################################################
290 def __init__(self, func_code, description, group, has_length=1):
292 self.func_code = func_code
293 self.description = description
296 self.request_records = None
297 self.reply_records = None
298 self.has_length = has_length
300 if not groups.has_key(group):
301 sys.stderr.write("NCP 0x%x has invalid group '%s'\n" % (self.func_code, group))
304 if self.HasSubFunction():
305 # NCP Function with SubFunction
306 self.start_offset = 10
308 # Simple NCP Function
309 self.start_offset = 7
311 def FunctionCode(self, part=None):
312 "Returns the function code for this NCP packet."
314 return self.func_code
316 if self.HasSubFunction():
317 return (self.func_code & 0xff00) >> 8
319 return self.func_code
321 if self.HasSubFunction():
322 return self.func_code & 0x00ff
326 sys.stderr.write("Unknown directive '%s' for function_code()\n" % (part))
329 def HasSubFunction(self):
330 "Does this NPC packet require a subfunction field?"
331 if self.func_code <= 0xff:
337 return self.has_length
339 def Description(self):
340 return self.description
345 def PTVCRequest(self):
346 return self.ptvc_request
349 return self.ptvc_reply
351 def Request(self, size, records=[]):
352 self.request_size = size
353 self.request_records = records
354 if self.HasSubFunction():
356 self.CheckRecords(size, records, "Request", 10)
358 self.CheckRecords(size, records, "Request", 8)
360 self.CheckRecords(size, records, "Request", 7)
361 self.ptvc_request = self.MakePTVC(records, "request")
363 def Reply(self, size, records=[]):
364 self.reply_size = size
365 self.reply_records = records
366 self.CheckRecords(size, records, "Reply", 8)
367 self.ptvc_reply = self.MakePTVC(records, "reply")
369 def CheckRecords(self, size, records, descr, min_hdr_length):
370 "Simple sanity check"
373 if type(size) == type(()):
377 lower = min_hdr_length
378 upper = min_hdr_length
380 for record in records:
384 if type(rec_size) == type(()):
385 rec_lower = rec_size[0]
386 rec_upper = rec_size[1]
388 lower = lower + rec_lower
389 upper = upper + rec_upper
393 sys.stderr.write("%s records for 2222/0x%x sum to %d bytes minimum, but param1 shows %d\n" \
394 % (descr, self.FunctionCode(), lower, min))
397 sys.stderr.write("%s records for 2222/0x%x sum to %d bytes maximum, but param1 shows %d\n" \
398 % (descr, self.FunctionCode(), upper, max))
405 def MakePTVC(self, records, name_suffix):
406 """Makes a PTVC out of a request or reply record list. Possibly adds
407 it to the global list of PTVCs (the global list is a UniqueCollection,
408 so an equivalent PTVC may already be in the global list)."""
410 name = "%s_%s" % (self.CName(), name_suffix)
411 ptvc = PTVC(name, records)
412 return ptvc_lists.Add(ptvc)
415 "Returns a C symbol based on the NCP function code"
416 return "ncp_0x%x" % (self.func_code)
419 """Returns a list of variables used in the request and reply records.
420 A variable is listed only once, even if it is used twice (once in
421 the request, once in the reply)."""
424 if self.request_records:
425 for record in self.request_records:
429 sub_vars = var.SubVariables()
433 if self.reply_records:
434 for record in self.reply_records:
438 sub_vars = var.SubVariables()
442 return variables.keys()
445 def CompletionCodes(self, codes=None):
446 """Sets or returns the list of completion codes. Internally, a NamedList
447 is used to store the completion codes, but the caller of this function
448 never realizes that because Python lists are the input and output."""
456 if not errors.has_key(code):
457 sys.stderr.write("Errors table does not have key 0x%04x for NCP=0x%x\n" % (code,
461 # Delay the exit until here so that the programmer can get the complete
462 # list of missing error codes
466 # Create CompletionCode (NamedList) object and possible add it to
467 # the global list of completion code lists.
468 name = "%s_errors" % (self.CName())
470 codes_list = NamedList(name, codes)
471 self.codes = compcode_lists.Add(codes_list)
476 """Adds the NCP object to the global collection of NCP objects. This
477 is done automatically after setting the CompletionCode list. Yes, this
478 is a shortcut, but it makes our list of NCP packet definitions look
479 neater, since an explicit "add to global list of packets" is not needed."""
481 # Add packet to global collection of packets
482 if packets.HasMember(self):
483 sys.stderr.write("Already have NCP Function Code 0x%x\n" % \
491 ##############################################################################
493 LE = 1 # Little-Endian
495 NA = -1 # Not Applicable
498 " Virtual class for NCP field types"
505 def __init__(self, abbrev, descr, bytes, endianness = NA):
513 def Abbreviation(self):
516 def Description(self):
520 return "hf_ncp_" + self.abbrev
523 return "ncp." + self.abbrev
525 def EtherealFType(self):
528 def Display(self, newval=None):
533 def ValuesName(self):
539 def Endianness(self):
540 return self.endianness
542 def SubVariables(self):
551 def __init__(self, abbrev, descr):
552 Type.__init__(self, abbrev, descr, 1)
554 # Same as above. Both are provided for convenience
559 def __init__(self, abbrev, descr):
560 Type.__init__(self, abbrev, descr, 1)
562 class boolean8(uint8):
569 def __init__(self, abbrev, descr, endianness = BE):
570 Type.__init__(self, abbrev, descr, 2, endianness)
575 def __init__(self, abbrev, descr, endianness = BE):
576 Type.__init__(self, abbrev, descr, 4, endianness)
578 class nstring8(Type):
579 """A string of up to 255 characters. The first byte
580 gives the string length. Thus, the total length of
581 this data structure is from 1 to 256 bytes, including
585 ftype = "FT_UINT_STRING"
586 def __init__(self, abbrev, descr):
587 Type.__init__(self, abbrev, descr, 1)
589 class fw_string(Type):
590 """A fixed-width string of n bytes."""
595 def __init__(self, abbrev, descr, bytes):
596 Type.__init__(self, abbrev, descr, bytes)
600 "NUL-terminated string, with a maximum length"
604 def __init__(self, abbrev, descr):
605 Type.__init__(self, abbrev, descr, -1)
607 class val_string(Type):
608 """Abstract class for val_stringN, where N is number
609 of bits that key takes up."""
614 def __init__(self, abbrev, descr, val_string_array, endianness = BE):
615 Type.__init__(self, abbrev, descr, self.bytes, endianness)
616 self.values = val_string_array
619 result = "static const value_string %s[] = {\n" \
620 % (self.ValuesCName())
621 for val_record in self.values:
622 value = val_record[0]
624 value_repr = self.value_format % value
625 result = result + '\t{ %s,\t"%s" },\n' \
628 value_repr = self.value_format % 0
629 result = result + "\t{ %s,\tNULL },\n" % (value_repr)
630 result = result + "};\n"
634 def ValuesCName(self):
635 return "ncp_%s_vals" % (self.abbrev)
637 def ValuesName(self):
638 return "VALS(%s)" % (self.ValuesCName())
640 class val_string8(val_string):
644 value_format = "0x%02x"
646 class val_string16(val_string):
647 type = "val_string16"
650 value_format = "0x%04x"
656 def __init__(self, abbrev, descr, bytes):
657 Type.__init__(self, abbrev, descr, bytes, NA)
660 class bitfield(Type):
664 def __init__(self, vars):
667 var_hash[var.bitmask] = var
669 bitmasks = var_hash.keys()
674 for bitmask in bitmasks:
675 var = var_hash[bitmask]
676 ordered_vars.append(var)
678 self.vars = ordered_vars
679 self.sub_ptvc = PTVCBitfield(self.PTVCName(), self.vars)
681 def SubVariables(self):
684 def SubVariablesPTVC(self):
688 return "ncp_%s_bitfield" % (self.abbrev,)
690 class bitfield8(bitfield, uint8):
694 def __init__(self, abbrev, descr, vars):
695 uint8.__init__(self, abbrev, descr)
696 bitfield.__init__(self, vars)
702 def __init__(self, bitmask, abbrev, descr):
703 self.bitmask = bitmask
710 class bf_boolean8(bf_uint, boolean8):
718 # def __init__(self, abbrev, descr):
719 # Type.__init__(self, abbrev, descr, -1)
721 # def length_var(self, length_var):
722 # self.length_var = length_var
724 ##############################################################################
725 # NCP Field Types. Defined in Appendix A of "Programmer's Guide..."
726 ##############################################################################
727 AcceptedMaxSize = uint16("accepted_max_size", "Accepted Max Size")
728 AcctVersion = byte("acct_version", "Acct Version")
729 BufferSize = uint16("buffer_size", "Buffer Size")
730 ConnectionNumber = uint32("connection_number", "Connection Number")
731 ConnectionsSupportedMax = uint16("connections_supported_max", "Connections Supported Max")
732 ConnectionsInUse = uint16("connections_in_use", "Connections In Use")
733 ConnectionsMaxUsed = uint16("connections_max_used", "Connections Max Used")
734 DirHandle = byte("dir_handle", "Directory Handle")
736 EchoSocket = uint16("echo_socket", "Echo Socket")
737 EchoSocket.Display('BASE_HEX')
739 FileHandle = bytes("file_handle", "File Handle", 6)
741 FileLock = val_string8("file_lock", "File Lock", [
742 [ 0x00, "Not Locked" ],
743 [ 0xfe, "Locked by file lock" ],
747 FileOffset = uint32("file_offset", "File Offset")
748 FilePath = nstring8("file_path", "File Path")
749 FileSize = uint32("file_size", "File Size")
750 InternetBridgeVersion = byte("internet_bridge_version", "Internet Bridge Version")
751 JobType = uint16("job_type", "Job Type")
753 LocalLoginInfoCcode = byte("local_login_info_ccode", "Local Login Info C Code")
754 LogicalLockType = val_string8("logical_lock_type", "Logical Lock Type", [
755 [ 0x00, "Log file" ],
756 [ 0x01, "Log and lock file for exclusive read/write use" ],
757 [ 0x03, "Log and lock with shareable read-only use" ],
760 LogicalRecordName = nstring8("logical_record_name", "Logical Record Name")
761 LogLockType = byte("log_lock_type", "Log Lock Type")
763 MaxBytes = uint16("max_bytes", "Maximum Number of Bytes")
764 MixedModePathFlag = byte("mixed_mode_path_flag", "Mixed Mode Path Flag")
765 NumBytes = uint16("num_bytes", "Number of Bytes")
767 ObjectFlags = val_string8("object_flags", "Object Flags", [
768 [ 0x00, "Dynamic object" ],
769 [ 0x01, "Static object" ],
772 ObjectHasProperties = val_string8("object_has_properites", "Object Has Properties", [
773 [ 0x00, "No properties" ],
774 [ 0xff, "One or more properties" ],
777 ObjectID = uint32("object_id", "Object ID")
778 ObjectID.Display('BASE_HEX')
780 ObjectName = nstring8("object_name", "Object Name")
781 ObjectName1 = fw_string("object_name1", "Object Name", 48)
783 ObjectSecurity = val_string8("object_security", "Object Security", [
784 [ 0x00, "Anyone can read or modify the object" ],
785 [ 0x01, "Client logged into the file server can read the object" ],
786 [ 0x02, "Client logged into the file server with the object's name, type and password can read the object" ],
787 [ 0x03, "Client with supervisor equivalence can read the object" ],
788 [ 0x04, "Only the operating system can read the object" ],
789 [ 0x10, "Client logged into the file server can modify the object" ],
790 [ 0x20, "Client logged into the file server with the object's name, type and password can modify the object" ],
791 [ 0x30, "Client with supervisor equivalence can modify the object" ],
792 [ 0x40, "Only the operating system can modify the object" ],
795 ObjectType = val_string16("object_type", "Object Type", [
796 [ 0x0000, "Unknown" ],
798 [ 0x0002, "User group" ],
799 [ 0x0003, "Print queue" ],
800 [ 0x0004, "NetWare file server" ],
801 [ 0x0005, "Job server" ],
802 [ 0x0006, "Gateway" ],
803 [ 0x0007, "Print server" ],
804 [ 0x0008, "Archive queue" ],
805 [ 0x0009, "Archive server" ],
806 [ 0x000a, "Job queue" ],
807 [ 0x000b, "Administration" ],
808 [ 0x0021, "NAS SNA gateway" ],
809 [ 0x0026, "Remote bridge server" ],
810 [ 0x0027, "TCP/IP gateway" ],
813 OSLanguageID = byte("os_language_id", "OS Language ID")
814 OSMajorVersion = byte("os_major_version", "OS Major Version")
815 OSMinorVersion = byte("os_minor_version", "OS Minor Version")
816 OSRevision = byte("os_revision", "OS Revision")
817 PingVersion = uint16("ping_version", "Ping Version", endianness=LE)
818 PingVersion.Display("BASE_HEX")
820 PrintServerVersion = byte("print_server_version", "Print Server Version")
821 ProductMajorVersion = uint16("product_major_version", "Product Major Version")
822 ProductMinorVersion = uint16("product_minor_version", "Product Minor Version")
823 ProductRevisionVersion = byte("product_revision_version", "Product Revision Version")
825 PropertyHasMoreSegments = val_string8("property_has_more_segments",
826 "Property Has More Segments", [
827 [ 0x00, "Is last segment" ],
828 [ 0xff, "More segments are available" ],
831 PropertyName = nstring8("property_name", "Property Name")
832 PropertyData = bytes("property_data", "Property Data", 128)
833 PropertySegment = uint8("property_segment", "Property Segment")
835 PropertyType = val_string8("property_type", "Property Type", [
836 [ 0x00, "Static item" ],
837 [ 0x01, "Dynamic item" ],
838 [ 0x02, "Static set" ],
839 [ 0x03, "Dynamic set" ],
842 ProposedMaxSize = uint16("proposed_max_size", "Proposed Max Size")
844 Reserved3 = bytes("reserved3", "Reserved", 3)
845 Reserved51 = bytes("reserved51", "Reserved", 51)
847 QMSVersion = byte("qms_version", "QMS Version")
849 # XXX - needs bitfield
850 SecurityFlag = byte("security_flag", "Security Flag")
851 SecurityRestrictionVersion = byte("security_restriction_version", "Security Restriction Version")
853 ServerName = stringz("server_name", "Server Name")
854 SFTLevel = byte("sft_level", "SFT Level")
856 TaskNumber = uint32("task_number", "Task Number")
857 TimeoutLimit = uint16("timeout_limit", "Timeout Limit")
858 TTSLevel = byte("tts_level", "TTS Level")
859 UnknownByte = byte("unknown_byte", "Unknown Byte")
861 VAPVersion = byte("vap_version", "VAP Version")
862 VirtualConsoleVersion = byte("virtual_console_version", "Virtual Console Version")
863 VolumesSupportedMax = uint16("volumes_supported_max", "Volumes Supported Max")
865 ##############################################################################
867 ##############################################################################
869 groups['accounting'] = "Accounting"
870 groups['afp'] = "AFP"
871 groups['auditing'] = "Auditing"
872 groups['bindery'] = "Bindery"
873 groups['connection'] = "Connection"
874 groups['directory'] = "Directory"
875 groups['extended'] = "Extended Attribute"
876 groups['file'] = "File"
877 groups['fileserver'] = "File Server"
878 groups['message'] = "Message"
879 groups['migration'] = "Data Migration"
880 groups['misc'] = "Miscellaneous"
881 groups['name'] = "Name Space"
882 groups['nds'] = "NetWare Directory"
883 groups['print'] = "Print"
884 groups['queue'] = "Queue"
885 groups['sync'] = "Synchronization"
886 groups['tss'] = "Transaction Tracking"
887 groups['unknown'] = "Unknown"
889 ##############################################################################
891 ##############################################################################
893 errors[0x0000] = "Ok"
894 errors[0x0001] = "Transaction tracking is available"
895 errors[0x0002] = "Ok. The data has been written"
897 errors[0x0100] = "One or more of the ConnectionNumbers in the send list are invalid"
898 errors[0x0101] = "Invalid space limit"
899 errors[0x0102] = "Insufficient disk space"
900 errors[0x0103] = "Queue server cannot add jobs"
901 errors[0x0104] = "Out of disk space"
902 errors[0x0105] = "Semaphore overflow"
904 errors[0x0200] = "One or more clients in the send list are not logged in"
905 errors[0x0201] = "Queue server cannot attach"
907 errors[0x0300] = "One or more clients in the send list are not accepting messages"
909 errors[0x0400] = "Client already has message"
910 errors[0x0401] = "Queue server cannot service job"
912 errors[0x7e00] = "NCP failed boundary check"
914 errors[0x8000] = "Lock fail"
915 errors[0x8100] = "A file handle could not be allocated by the file server"
916 errors[0x8200] = "Unauthorized to open the file"
917 errors[0x8300] = "Unable to read/write the volume. Possible bad sector on the file server"
919 errors[0x8400] = "Unauthorized to create the directory"
920 errors[0x8401] = "Unauthorized to create the file"
922 errors[0x8500] = "Unauthorized to delete the specified file"
923 errors[0x8501] = "Unauthorized to overwrite an existing file in this directory"
925 errors[0x8700] = "An unexpected character was encountered in the filename"
926 errors[0x8800] = "Invalid file handle"
927 errors[0x8900] = "Unauthorized to search this directory"
928 errors[0x8a00] = "Unauthorized to delete this directory"
929 errors[0x8b00] = "Unauthorized to rename a file in this directory"
931 errors[0x8c00] = "No set privileges"
932 errors[0x8c01] = "Unauthorized to modify a file in this directory"
933 errors[0x8c02] = "Unauthorized to change the restriction on this volume"
935 errors[0x8d00] = "Some of the affected files are in use by another client"
936 errors[0x8d01] = "The affected file is in use"
938 errors[0x8e00] = "All of the affected files are in use by another client"
939 errors[0x8f00] = "Some of the affected files are read-only"
941 errors[0x9000] = "An attempt to modify a read-only volume occurred"
942 errors[0x9001] = "All of the affected files are read-only"
944 errors[0x9100] = "Some of the affected files already exist"
946 errors[0x9200] = "Directory with the new name already exists"
947 errors[0x9201] = "All of the affected files already exist"
949 errors[0x9300] = "Unauthorized to read from this file"
950 errors[0x9400] = "Unauthorized to write to this file"
951 errors[0x9500] = "The affected file is detached"
953 errors[0x9600] = "The file server has run out of memory to service this request"
954 errors[0x9601] = "No alloc space for message"
956 errors[0x9800] = "The affected volume is not mounted"
957 errors[0x9801] = "The volume associated with VolumeNumber is not mounted"
958 errors[0x9802] = "The resulting voume does not exist"
959 errors[0x9803] = "The destination volume is not mounted"
961 errors[0x9900] = "The file server has run out of directory space on the affected volume"
962 errors[0x9a00] = "The request attempted to rename the affected file to another volume"
964 errors[0x9b00] = "DirHandle is not associated with a valid directory path"
965 errors[0x9b01] = "A resulting directory handle is not associated with a valid directory path"
966 errors[0x9b02] = "The directory associated with DirHandle does not exist"
967 errors[0x9b03] = "Bad directory handle"
969 errors[0x9c00] = "The resulting path is not valid"
970 errors[0x9c01] = "The resulting file path is not valid"
971 errors[0x9c02] = "The resulting directory path is not valid"
972 errors[0x9c03] = "Invalid path"
974 errors[0x9d00] = "A directory handle was not available for allocation"
976 errors[0x9e00] = "The name of the directory does not conform to a legal name for this name space"
977 errors[0x9e01] = "The new directory name does not conform to a legal name for this name space"
979 errors[0x9f00] = "The request attempted to delete a directory that is in use by another client"
981 errors[0xa000] = "The request attempted to delete a directory that is not empty"
982 errors[0xa100] = "An unrecoverable error occured on the affected directory"
983 errors[0xa200] = "The request attempted to read from a file region that is physically locked"
984 errors[0xa400] = "Invalid directory rename attempted"
986 errors[0xbf00] = "Requests for this name space are not valid on this volume"
988 errors[0xc000] = "Unauthorized to retrieve accounting data"
989 errors[0xc100] = "The ACCOUNT_BALANCE property does not exist"
990 errors[0xc200] = "The object has exceeded its credit limit"
991 errors[0xc300] = "Too many holds have been placed against this account"
992 errors[0xc400] = "The client account has been disabled"
994 errors[0xc500] = "Access to the account has been denied because of intruder detection"
995 errors[0xc501] = "Login lockout"
997 errors[0xc600] = "The caller does not have operator priviliges"
998 errors[0xc601] = "The client does not have operator priviliges"
1000 errors[0xd000] = "Queue error"
1001 errors[0xd100] = "The queue does not exist"
1003 errors[0xd200] = "A queue server is not associated with this queue"
1004 errors[0xd201] = "A queue server is not associated with the selected queue"
1005 errors[0xd202] = "No queue server"
1007 errors[0xd300] = "No queue rights"
1009 errors[0xd400] = "The queue is full and cannot accept another request"
1010 errors[0xd401] = "The queue associated with ObjectId is full and cannot accept another request"
1012 errors[0xd500] = "A job does not exist in this queue"
1013 errors[0xd501] = "No queue job"
1014 errors[0xd502] = "The job associated with JobNumber does not exist in this queue"
1016 errors[0xd600] = "The file server does not allow unencrypted passwords"
1017 errors[0xd601] = "No job right"
1019 errors[0xd700] = "Bad account"
1020 errors[0xd701] = "The old and new password strings are identical"
1021 errors[0xd702] = "The job is currently being serviced"
1022 errors[0xd703] = "The queue is currently servicing a job"
1023 errors[0xd704] = "Queue servicing"
1025 errors[0xd800] = "Queue not active"
1027 errors[0xd900] = "The file server cannot accept another connection as it has reached its limit"
1028 errors[0xd901] = "The client is not security equivalent to one of the objects in the Q_SERVERS group property of the target queue"
1029 errors[0xd902] = "Station is not a server"
1031 errors[0xda00] = "Attempted to login to the file server during a restricted time period"
1032 errors[0xda01] = "Queue halted"
1034 errors[0xdb00] = "Attempted to login to the file server from an unauthorized workstation or network"
1035 errors[0xdb01] = "The queue cannot attach another queue server"
1036 errors[0xdb02] = "Maximum queue servers"
1038 errors[0xde00] = "Attempted to login to the file server with an incorrect password"
1039 errors[0xdf00] = "Attempted to login to the file server with a password that has expired"
1041 errors[0xe700] = "No disk track"
1042 errors[0xe800] = "Write to group"
1043 errors[0xe900] = "The object is already a member of the group property"
1045 errors[0xea00] = "No such member"
1046 errors[0xea01] = "The bindery object is not a member of the set"
1047 errors[0xea02] = "Non-existent member"
1049 errors[0xeb00] = "The property is not a set property"
1051 errors[0xec00] = "No such set"
1052 errors[0xec01] = "The set property does not exist"
1054 errors[0xed00] = "Property exists"
1055 errors[0xed01] = "The property already exists"
1056 errors[0xed02] = "An attempt was made to create a bindery object property that already exists"
1058 errors[0xee00] = "The object already exists"
1059 errors[0xee01] = "The bindery object already exists"
1061 errors[0xef00] = "Illegal name"
1062 errors[0xef01] = "Illegal characters in ObjectName field"
1063 errors[0xef02] = "Invalid name"
1065 errors[0xf000] = "A wildcard was detected in a field that does not support wildcards"
1066 errors[0xf001] = "An illegal wildcard was detected in ObjectName"
1068 errors[0xf100] = "The client does not have the rights to access this bindery object"
1069 errors[0xf101] = "Bindery security"
1070 errors[0xf102] = "Invalid bindery security"
1072 errors[0xf200] = "Unauthorized to read from this object"
1073 errors[0xf300] = "Unauthorized to rename this object"
1075 errors[0xf400] = "Unauthorized to delete this object"
1076 errors[0xf401] = "No object delete privileges"
1077 errors[0xf402] = "Unauthorized to delete this queue"
1079 errors[0xf500] = "Unauthorized to create this object"
1080 errors[0xf501] = "No object create"
1082 errors[0xf600] = "No property delete"
1083 errors[0xf601] = "Unauthorized to delete the property of this object"
1084 errors[0xf602] = "Unauthorized to delete this property"
1086 errors[0xf700] = "Unauthorized to create this property"
1087 errors[0xf701] = "No property create privilege"
1089 errors[0xf800] = "Unauthorized to write to this property"
1090 errors[0xf900] = "Unauthorized to read this property"
1091 errors[0xfa00] = "Temporary remap error"
1093 errors[0xfb00] = "No such property"
1094 errors[0xfb01] = "The file server does not support this request"
1095 errors[0xfb02] = "The specified property does not exist"
1096 errors[0xfb03] = "The PASSWORD property does not exist for this bindery object"
1097 errors[0xfb04] = "NDS NCP not available"
1099 errors[0xfc00] = "The message queue cannot accept another message"
1100 errors[0xfc01] = "The trustee associated with ObjectId does not exist"
1101 errors[0xfc02] = "The specified bindery object does not exist"
1102 errors[0xfc03] = "The bindery object associated with ObjectID does not exist"
1103 errors[0xfc04] = "A bindery object does not exist that matches"
1104 errors[0xfc05] = "The specified queue does not exist"
1105 errors[0xfc06] = "No such object"
1106 errors[0xfc07] = "The queue associated with ObjectID does not exist"
1108 errors[0xfd00] = "Bad station number"
1109 errors[0xfd01] = "The connection associated with ConnectionNumber is not active"
1110 errors[0xfd02] = "Lock collision"
1111 errors[0xfd03] = "Transacktion tracking is disabled"
1113 errors[0xfe00] = "I/O failure"
1114 errors[0xfe01] = "The files containing the bindery on the file server are locked"
1115 errors[0xfe02] = "A file with the specified name already exists in this directory"
1116 errors[0xfe03] = "No more restrictions were found"
1117 errors[0xfe04] = "The file server was unable to lock the file within the specified time limit"
1118 errors[0xfe05] = "The file server was unable to lock all files within the specified time limit"
1119 errors[0xfe06] = "The bindery object associated with ObjectID is not a valid trustee"
1120 errors[0xfe07] = "Directory locked"
1121 errors[0xfe08] = "Bindery locked"
1122 errors[0xfe09] = "Invalid semaphore name length"
1123 errors[0xfe0a] = "The file server was unable to complete the operation within the specified time limit"
1124 errors[0xfe0b] = "Transaction restart"
1125 errors[0xfe0c] = "Bad packet"
1127 errors[0xff00] = "Failure"
1128 errors[0xff01] = "Lock error"
1129 errors[0xff02] = "File not found"
1130 errors[0xff03] = "The file not found or cannot be unlocked"
1131 errors[0xff04] = "Record not found"
1132 errors[0xff05] = "The logical record was not found"
1133 errors[0xff06] = "The printer associated with PrinterNumber does not exist"
1134 errors[0xff07] = "No such printer"
1135 errors[0xff08] = "Unable to complete the request"
1136 errors[0xff09] = "Unauthorized to change privileges of this trustee"
1137 errors[0xff0a] = "No files matching the search criteria were found"
1138 errors[0xff0b] = "A file matching the search criteria was not found"
1139 errors[0xff0c] = "Verification failed"
1140 errors[0xff0d] = "Object associated with ObjectID is not a manager"
1141 errors[0xff0e] = "Invalid initial semaphore value"
1142 errors[0xff0f] = "The semaphore handle is not valid"
1143 errors[0xff10] = "SemaphoreHandle is not associated with a valid sempahore"
1144 errors[0xff11] = "Invalid semaphore handle"
1145 errors[0xff12] = "Transaction tracking is not available"
1146 errors[0xff13] = "The transaction has not yet been written to disk"
1147 errors[0xff14] = "Directory already exists"
1148 errors[0xff15] = "The file already exists and the deletion flag was not set"
1149 errors[0xff16] = "No matching files or directories were found"
1150 errors[0xff17] = "A file or directory matching the search criteria was not found"
1151 errors[0xff18] = "The file already exists"
1152 errors[0xff19] = "No files found"
1155 ##############################################################################
1157 ##############################################################################
1163 print " * Generated automatically from %s" % (sys.argv[0])
1164 print " * Do not edit this file manually, as all changes will be lost."
1169 * This program is free software; you can redistribute it and/or
1170 * modify it under the terms of the GNU General Public License
1171 * as published by the Free Software Foundation; either version 2
1172 * of the License, or (at your option) any later version.
1174 * This program is distributed in the hope that it will be useful,
1175 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1176 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1177 * GNU General Public License for more details.
1179 * You should have received a copy of the GNU General Public License
1180 * along with this program; if not, write to the Free Software
1181 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1184 #ifdef HAVE_CONFIG_H
1185 # include "config.h"
1189 #include <epan/packet.h>
1190 #include <epan/conversation.h>
1191 #include "ptvcursor.h"
1192 #include "packet-ncp-int.h"
1194 static int hf_ncp_func = -1;
1195 static int hf_ncp_length = -1;
1196 static int hf_ncp_subfunc = -1;
1197 static int hf_ncp_completion_code = -1;
1198 static int hf_ncp_connection_status = -1;
1201 # Look at all packet types in the packets collection, and cull information
1204 for packet in packets.Members():
1205 packet_keys.append(packet.FunctionCode())
1208 errors_used_list = []
1209 errors_used_hash = {}
1210 groups_used_list = []
1211 groups_used_hash = {}
1212 variables_used_hash = {}
1214 for pkt in packets.Members():
1215 # Determine which error codes are used.
1216 codes = pkt.CompletionCodes()
1217 for code in codes.Records():
1218 if not errors_used_hash.has_key(code):
1219 errors_used_hash[code] = len(errors_used_list)
1220 errors_used_list.append(code)
1222 # Determine which groups are used.
1224 if not groups_used_hash.has_key(group):
1225 groups_used_hash[group] = len(groups_used_list)
1226 groups_used_list.append(group)
1228 # Determine which variables are used.
1229 vars = pkt.Variables()
1231 variables_used_hash[var] = 1
1235 # Print the hf variable declarations
1236 for var in variables_used_hash.keys():
1237 print "static int " + var.HFName() + " = -1;"
1240 # Print the value_string's
1241 for var in variables_used_hash.keys():
1242 if isinstance(var, val_string):
1247 # Determine which error codes are not used
1248 errors_not_used = {}
1249 # Copy the keys from the error list...
1250 for code in errors.keys():
1251 errors_not_used[code] = 1
1252 # ... and remove the ones that *were* used.
1253 for code in errors_used_list:
1254 del errors_not_used[code]
1256 # Print a remark showing errors not used
1257 list_errors_not_used = errors_not_used.keys()
1258 list_errors_not_used.sort()
1259 for code in list_errors_not_used:
1260 print "/* Error 0x%04x not used: %s */" % (code, errors[code])
1263 # Print the errors table
1264 print "/* Error strings. */"
1265 print "static const char *ncp_errors[] = {"
1266 for code in errors_used_list:
1267 print '\t/* %02d (0x%04x) */ "%s",' % (errors_used_hash[code], code, errors[code])
1273 # Determine which groups are not used
1274 groups_not_used = {}
1275 # Copy the keys from the group list...
1276 for group in groups.keys():
1277 groups_not_used[group] = 1
1278 # ... and remove the ones that *were* used.
1279 for group in groups_used_list:
1280 del groups_not_used[group]
1282 # Print a remark showing groups not used
1283 list_groups_not_used = groups_not_used.keys()
1284 list_groups_not_used.sort()
1285 for group in list_groups_not_used:
1286 print "/* Group not used: %s = %s */" % (group, groups[group])
1289 # Print the groups table
1290 print "/* Group strings. */"
1291 print "static const char *ncp_groups[] = {"
1292 for group in groups_used_list:
1293 print '\t/* %02d (%s) */ "%s",' % (groups_used_hash[group], group, groups[group])
1296 # Print the group macros
1297 for group in groups_used_list:
1298 name = string.upper(group)
1299 print "#define NCP_GROUP_%s\t%d" % (name, groups_used_hash[group])
1302 # Print PTVC's for bitfields
1304 print "/* PTVC records for bit-fields. */"
1305 for var in variables_used_hash.keys():
1306 if isinstance(var, bitfield):
1307 sub_vars_ptvc = var.SubVariablesPTVC()
1308 print "/* %s */" % (sub_vars_ptvc.Name())
1310 ett_list.append(sub_vars_ptvc.ETTName())
1312 # Print PTVC's not already printed for bitfields
1313 print "/* PTVC records. These are re-used to save space. */"
1314 for ptvc in ptvc_lists.Members():
1315 if not ptvc.Null() and not ptvc.Empty():
1318 # Print error_equivalency tables
1319 print "/* Error-Equivalency Tables. These are re-used to save space. */"
1320 for compcodes in compcode_lists.Members():
1321 errors = compcodes.Records()
1322 # Make sure the record for error = 0x00 comes last.
1323 print "static const error_equivalency %s[] = {" % (compcodes.Name())
1324 for error in errors:
1325 error_in_packet = error >> 8;
1326 ncp_error_index = errors_used_hash[error]
1327 print "\t{ 0x%02x, %d }, /* 0x%04x */" % (error_in_packet,
1328 ncp_error_index, error)
1329 print "\t{ 0x00, -1 }\n};\n"
1332 # Functions without length parameter
1333 funcs_without_length = {}
1336 # Print ncp_record packet records
1337 print "#define SUBFUNC_WITH_LENGTH 0x02"
1338 print "#define SUBFUNC_NO_LENGTH 0x01"
1339 print "#define NO_SUBFUNC 0x00"
1341 print "/* ncp_record structs for packets */"
1342 print "static const ncp_record ncp_packets[] = {"
1343 for pkt in packets.Members():
1344 if pkt.HasSubFunction():
1345 func = pkt.FunctionCode('high')
1347 subfunc_string = "SUBFUNC_WITH_LENGTH"
1348 # Ensure that the function either has a length param or not
1349 if funcs_without_length.has_key(func):
1350 sys.exit("Function 0x%04x sometimes has length param, sometimes not." \
1351 % (pkt.FunctionCode(),))
1353 subfunc_string = "SUBFUNC_NO_LENGTH"
1354 funcs_without_length[func] = 1
1356 subfunc_string = "NO_SUBFUNC"
1357 print '\t{ 0x%02x, 0x%02x, %s, "%s",' % (pkt.FunctionCode('high'),
1358 pkt.FunctionCode('low'), subfunc_string, pkt.Description()),
1360 print '\t%d /* %s */,' % (groups_used_hash[pkt.Group()], pkt.Group())
1362 ptvc = pkt.PTVCRequest()
1363 if not ptvc.Null() and not ptvc.Empty():
1364 ptvc_request = ptvc.Name()
1366 ptvc_request = 'NULL'
1368 ptvc = pkt.PTVCReply()
1369 if not ptvc.Null() and not ptvc.Empty():
1370 ptvc_reply = ptvc.Name()
1374 errors = pkt.CompletionCodes()
1375 print '\t\t%s, NULL, %s, NULL,' % (ptvc_request, ptvc_reply)
1376 print '\t\t%s },\n' % (errors.Name())
1378 print '\t{ 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL }'
1381 print "/* ncp funcs that require a subfunc */"
1382 print "static const guint8 ncp_func_requires_subfunc[] = {"
1384 for pkt in packets.Members():
1385 if pkt.HasSubFunction():
1386 hi_func = pkt.FunctionCode('high')
1387 if not hi_seen.has_key(hi_func):
1388 print "\t0x%02x," % (hi_func)
1389 hi_seen[hi_func] = 1
1394 print "/* ncp funcs that have no length parameter */"
1395 print "static const guint8 ncp_func_has_no_length_parameter[] = {"
1396 funcs = funcs_without_length.keys()
1399 print "\t0x%02x," % (func,)
1403 # proto_register_ncp2222()
1406 proto_register_ncp2222(void)
1409 static hf_register_info hf[] = {
1411 { "Function", "ncp.func", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1414 { "Packet Length", "ncp.length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1417 { "SubFunction", "ncp.subfunc", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1419 { &hf_ncp_completion_code,
1420 { "Completion Code", "ncp.completion_code", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1422 { &hf_ncp_connection_status,
1423 { "Connection Status", "ncp.connection_status", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1426 # Print the registration code for the hf variables
1427 for var in variables_used_hash.keys():
1428 print "\t{ &%s," % (var.HFName())
1429 print "\t{ \"%s\", \"%s\", %s, %s, %s, 0x%x, \"\", HFILL }},\n" % \
1430 (var.Description(), var.DFilter(),
1431 var.EtherealFType(), var.Display(), var.ValuesName(),
1441 static gint *ett[] = {
1444 for ett in ett_list:
1445 print "\t\t&%s," % (ett,)
1452 proto_register_field_array(proto_ncp, hf, array_length(hf));
1457 proto_register_subtree_array(ett, array_length(ett));
1461 print '#include "packet-ncp2222.inc"'
1466 global compcode_lists
1469 packets = UniqueCollection('NCP Packet Descriptions')
1470 compcode_lists = UniqueCollection('Completion Code Lists')
1478 def define_ncp2222():
1479 ##############################################################################
1480 # NCP Packets. Here I list functions and subfunctions in hexadecimal like the
1481 # NCP book (and I believe LanAlyzer does this too).
1482 # However, Novell lists these in decimal in their on-line documentation.
1483 ##############################################################################
1485 pkt = NCP(0x02, "File Release Lock", 'sync')
1488 pkt.CompletionCodes([0x0000, 0xff00])
1494 #pkt = NCP(0x03, "Log File", 'sync')
1495 #pkt.request( (12, 267), [
1496 # [ 7, 1, DirHandle ],
1497 # [ 8, 1, LogLockType ],
1498 # [ 9, 2, TimeoutLimit, LE ],
1499 # [ 11, (1, 256), FilePath ],
1501 #pkt.completion_codes([0x0000, 0x8200, 0x9600, 0xfe00, 0xff01])
1504 #pkt = NCP(0x04, "Lock File Set", 'sync')
1506 # [ 7, TimeoutLimit ],
1508 #pkt.completion_codes([0xfe, 0xff01])
1511 #pkt = NCP(0x05, "Release File", 'sync')
1516 #pkt.completion_codes([0x7e, 0x98, 0x9b, 0x9c, 0xff02])
1519 #pkt = NCP(0x06, "Release File Set", 'sync')
1521 # [ 7, UnknownByte ],
1523 #pkt.completion_codes()
1526 #pkt = NCP(0x07, "Clear File", 'sync')
1531 #pkt.completion_codes([0x7e, 0x96, 0x98, 0x9b, 0x9c,
1532 # 0xa1, 0xfd, 0xff])
1535 #pkt = NCP(0x08, "Clear File Set", 'sync')
1539 #pkt.completion_codes([0x7e])
1542 #pkt = NCP(0x09, "Log Logical Record", 'sync')
1544 # [ 7, LogicalLockType ],
1545 # [ 8, TimeoutLimit_be ],
1546 # [ 10, LogicalRecordName ],
1548 #pkt.completion_codes([0x96, 0xfe, 0xff])
1551 #pkt = NCP(0x0a, "Lock Logical Record Set", 'sync')
1553 # [ 7, LogicalLockType ],
1554 # [ 8, TimeoutLimit_le ],
1556 #pkt.completion_codes([0xfe, 0xff])
1559 #pkt = NCP(0x0b, "Clear Logical Record", 'sync')
1561 # [7, LogicalRecordName ],
1563 #pkt.completion_codes([0xff]
1571 #pkt = NCP(0x1100, "Lock Logical Record Set", 'sync')
1573 # [ 10, var_length_data("data").length_var("packetlength") ]
1575 #pkt.completion_codes()
1579 pkt = NCP(0x1711, "Get File Server Information", 'fileserver')
1582 [ 8, 48, ServerName ],
1583 [ 56, 1, OSMajorVersion ],
1584 [ 57, 1, OSMinorVersion ],
1585 [ 58, 2, ConnectionsSupportedMax ],
1586 [ 60, 2, ConnectionsInUse ],
1587 [ 62, 2, VolumesSupportedMax ],
1588 [ 64, 1, OSRevision ],
1589 [ 65, 1, SFTLevel ],
1590 [ 66, 1, TTSLevel ],
1591 [ 67, 2, ConnectionsMaxUsed ],
1592 [ 69, 1, AcctVersion ],
1593 [ 70, 1, VAPVersion ],
1594 [ 71, 1, QMSVersion ],
1595 [ 72, 1, PrintServerVersion ],
1596 [ 73, 1, VirtualConsoleVersion ],
1597 [ 74, 1, SecurityRestrictionVersion ],
1598 [ 75, 1, InternetBridgeVersion ],
1599 [ 76, 1, MixedModePathFlag ],
1600 [ 77, 1, LocalLoginInfoCcode ],
1601 [ 78, 2, ProductMajorVersion ],
1602 [ 80, 2, ProductMinorVersion ],
1603 [ 82, 2, ProductRevisionVersion ],
1604 [ 84, 1, OSLanguageID ],
1605 [ 85, 51, Reserved51 ],
1607 pkt.CompletionCodes([0x0000, 0x9600])
1611 pkt = NCP(0x1735, "Get Bindery Object ID", 'bindery')
1612 pkt.Request((13,60), [
1613 [ 10, 2, ObjectType ],
1614 [ 12, (1,48), ObjectName ],
1618 [ 12, 2, ObjectType ],
1619 [ 14, 48, ObjectName1 ],
1621 pkt.CompletionCodes([0x0000, 0x9600, 0xef01, 0xf000, 0xfc02,
1625 pkt = NCP(0x1737, "Scan Bindery Object", 'bindery')
1626 pkt.Request((17,64), [
1627 [ 10, 4, ObjectID ],
1628 [ 14, 2, ObjectType ],
1629 [ 16, (1,48), ObjectName ],
1633 [ 12, 2, ObjectType ],
1634 [ 14, 48, ObjectName1 ],
1635 [ 62, 1, ObjectFlags ],
1636 [ 63, 1, ObjectSecurity ],
1637 [ 64, 1, ObjectHasProperties ],
1639 pkt.CompletionCodes([0x0000, 0x9600, 0xef01, 0xfc02,
1643 pkt = NCP(0x173D, "Read Property Value", 'bindery')
1644 pkt.Request((15,77), [
1645 [ 10, 2, ObjectType ],
1646 [ 12, (1,48), ObjectName ],
1647 [ -1, 1, PropertySegment ],
1648 [ -1, (1,16), PropertyName ],
1651 [ 8, 128, PropertyData ],
1652 [ 136, 1, PropertyHasMoreSegments ],
1653 [ 137, 1, PropertyType ],
1655 pkt.CompletionCodes([0x0000, 0x8800, 0x9300, 0x9600, 0xec01,
1656 0xf000, 0xf100, 0xf900, 0xfb02, 0xfc02, 0xfe01, 0xff00 ])
1659 pkt = NCP(0x177C, "Service Queue Job", 'queue')
1661 [ 10, 4, ObjectID ],
1664 pkt.Reply(24, [ # XXX - 76, [
1665 [ 8, 4, ConnectionNumber ],
1666 [ 12, 4, TaskNumber ],
1667 [ 16, 4, ObjectID ],
1668 [ 20, 4, ObjectID ],
1671 # These completion codes are not documented, but guessed.
1672 pkt.CompletionCodes([0x0000, 0x9900, 0xd000, 0xd100, 0xd201, 0xd300,
1673 0xd401, 0xd502, 0xd601, 0xd704, 0xd800, 0xd901, 0xda01, 0xdb01,
1677 pkt = NCP(0x18, "End of Job", 'connection')
1680 pkt.CompletionCodes([0x0000])
1683 pkt = NCP(0x19, "Logout", 'connection')
1686 pkt.CompletionCodes([0x0000])
1689 pkt = NCP(0x21, "Negotiate Buffer Size", 'connection')
1691 [ 7, 2, BufferSize ],
1694 [ 8, 2, BufferSize ],
1696 pkt.CompletionCodes([0x0000])
1699 pkt = NCP(0x42, "Close File", 'file')
1701 [ 7, 6, FileHandle ],
1704 pkt.CompletionCodes([0x0000, 0xff00])
1707 pkt = NCP(0x47, "Get Current Size of File", 'file')
1709 [ 7, 6, FileHandle ],
1714 pkt.CompletionCodes([0x0000, 0x8800])
1717 pkt = NCP(0x48, "Read From A File", 'file')
1719 [ 7, 1, UnknownByte ],
1720 [ 8, 6, FileHandle ],
1721 [ 14, 4, FileOffset ], # my nomenclature
1722 [ 18, 2, MaxBytes ], # my nomenclature
1724 pkt.Reply(10, [ # XXX - (10,-1), [
1725 [ 8, 2, NumBytes ], # my nomenclature
1728 pkt.CompletionCodes([0x0000, 0x8800, 0x9300, 0xff00])
1730 # 2222/5701 - no info
1731 # 2222/5702 - no info
1732 # 2222/5706 - no info
1733 # 2222/5714 - no info
1737 pkt = NCP(0x61, "Get Big Packet NCP Max Packet Size", 'unknown')
1739 [ 7, 2, ProposedMaxSize ],
1740 [ 9, 1, SecurityFlag ],
1743 [ 8, 2, AcceptedMaxSize ],
1744 [ 10, 2, EchoSocket ],
1745 [ 12, 1, SecurityFlag ],
1747 pkt.CompletionCodes([0x0000])
1750 pkt = NCP(0x6801, "Ping for NDS NCP", "nds", has_length=0)
1754 # XXX - expand, Unicode
1756 [ 8, 2, PingVersion ],
1758 pkt.CompletionCodes([0x0000, 0xfb04, 0xfe0c])
1761 if __name__ == '__main__':