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.7 2000/09/22 16:37:49 gram Exp $
25 Copyright (c) 2000 by Gilbert Ramirez <gram@xiexie.org>
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.
44 ##############################################################################
46 ##############################################################################
48 class UniqueCollection:
49 """The UniqueCollection class stores objects which can be compared to other
50 objects of the same class. If two objects in the collection are equivalent,
51 only one is stored."""
53 def __init__(self, name):
58 def Add(self, object):
59 """Add an object to the members lists, if a comparable object
60 doesn't already exist. The object that is in the member list, that is
61 either the object that was added or the comparable object that was
62 already in the member list, is returned."""
64 # Is 'object' a duplicate of some other member?
65 for member in self.members:
69 # Store object in our members list.
70 self.members.append(object)
74 "Returns the list of members."
77 def HasMember(self, object):
78 "Does the list of members contain the object?"
79 for member in self.members:
85 packets = UniqueCollection('NCP Packet Descriptions')
86 compcode_lists = UniqueCollection('Completion Code Lists')
87 ptvc_lists = UniqueCollection('PTVC Lists')
90 ##############################################################################
93 "NamedList's keep track of PTVC's and Completion Codes"
94 def __init__(self, name, list):
99 def __cmp__(self, other):
100 "Compare this NamedList to another"
102 # Python will do a deep comparison of lists within lists.
103 if self.list < other.list:
105 elif self.list > other.list:
111 "String representation"
112 return "NamedList: " + `self.list`
114 def Name(self, new_name = None):
115 "Get/Set name of list"
121 "Returns record lists"
125 "Is there no list (different from an empty list)?"
126 return self.list == None
129 "It the list empty (different from a null list)?"
130 assert(not self.Null())
138 class PTVC(NamedList):
139 """ProtoTree TVBuff Cursor List ("PTVC List") Class"""
141 def __init__(self, name, records):
144 NamedList.__init__(self, name, self.list)
146 expected_offset = None
148 # Make a PTVCRecord object for each list in 'records'
149 for record in records:
150 ptvc_rec = PTVCRecord(record)
152 if expected_offset == None:
153 expected_offset = ptvc_rec.Offset()
155 elif expected_offset == -1:
158 elif expected_offset != ptvc_rec.Offset():
159 sys.stderr.write("Expected offset in %s to be %d\n" % (name,
163 # We can't make a PTVC list from a variable-length
164 # packet, unless it's FT_UINT_STRING
165 if type(ptvc_rec.Length()) == type(()):
166 if isinstance(ptvc_rec.Field(), nstring8):
173 elif expected_offset > -1:
174 expected_offset = expected_offset + ptvc_rec.Length()
177 self.list.append(ptvc_rec)
180 def __init__(self, record):
182 self.offset = record[0]
183 self.length = record[1]
184 self.field = record[2]
187 field_length = self.field.Length()
189 # if type(field_length) != type(self.length):
190 # sys.stderr.write("Length types do not match")
193 # if type(field_length) == type(0) and field_length > 0:
194 # if field_length != self.length:
195 # sys.stderr.write("Length %d does not match field length %d for field %s\n" % (self.length, field_length, self.field.Abbreviation()))
198 # Check if an endianness override is given
200 self.endianness = record[3]
202 # If no endianness was given in the record, then
203 # use the field's default endianness.
205 self.endianness = self.field.Endianness()
207 def __cmp__(self, other):
208 "Comparison operator"
209 if self.length < other.length:
211 elif self.length > other.length:
214 if self.field != other.field:
216 elif self.endianness != other.endianness:
222 "String representation"
224 if self.endianness == LE:
229 if type(self.length) == type(0):
232 var_length = self.field.Length()
237 return "{ &%s, %d, %s }" % (self.field.HFName(),
240 length = "PTVC_VARIABLE_LENGTH"
241 return "{ &%s, %s, %s }" % (self.field.HFName(),
254 ##############################################################################
258 def __init__(self, func_code, description, group):
260 self.func_code = func_code
261 self.description = description
264 self.request_records = None
265 self.reply_records = None
267 if not groups.has_key(group):
268 sys.stderr.write("NCP 0x%x has invalid group '%s'\n" % (self.func_code, group))
271 if self.HasSubFunction():
272 # NCP Function with SubFunction
273 self.start_offset = 10
275 # Simple NCP Function
276 self.start_offset = 7
278 def FunctionCode(self, part=None):
279 "Returns the function code for this NCP packet."
281 return self.func_code
283 if self.HasSubFunction():
284 return (self.func_code & 0xff00) >> 8
286 return self.func_code
288 if self.HasSubFunction():
289 return self.func_code & 0x00ff
293 sys.stderr.write("Unknown directive '%s' for function_code()\n" % (part))
296 def HasSubFunction(self):
297 "Does this NPC packet require a subfunction field?"
298 if self.func_code <= 0xff:
303 def Description(self):
304 return self.description
309 def PTVCRequest(self):
310 return self.ptvc_request
313 return self.ptvc_reply
315 def Request(self, size, records=[]):
316 self.request_size = size
317 self.request_records = records
318 if self.HasSubFunction():
319 self.CheckRecords(size, records, "Request", 10)
321 self.CheckRecords(size, records, "Request", 7)
322 self.ptvc_request = self.MakePTVC(records, "request")
324 def Reply(self, size, records=[]):
325 self.reply_size = size
326 self.reply_records = records
327 self.CheckRecords(size, records, "Reply", 8)
328 self.ptvc_reply = self.MakePTVC(records, "reply")
330 def CheckRecords(self, size, records, descr, min_hdr_length):
331 "Simple sanity check"
334 if type(size) == type(()):
338 lower = min_hdr_length
339 upper = min_hdr_length
341 for record in records:
345 if type(rec_size) == type(()):
346 rec_lower = rec_size[0]
347 rec_upper = rec_size[1]
349 lower = lower + rec_lower
350 upper = upper + rec_upper
354 sys.stderr.write("%s records for 2222/0x%x sum to %d bytes minimum, but param1 shows %d\n" \
355 % (descr, self.FunctionCode(), lower, min))
358 sys.stderr.write("%s records for 2222/0x%x sum to %d bytes maximum, but param1 shows %d\n" \
359 % (descr, self.FunctionCode(), upper, max))
366 def MakePTVC(self, records, name_suffix):
367 """Makes a PTVC out of a request or reply record list. Possibly adds
368 it to the global list of PTVCs (the global list is a UniqueCollection,
369 so an equivalent PTVC may already be in the global list)."""
371 name = "%s_%s" % (self.CName(), name_suffix)
372 ptvc = PTVC(name, records)
373 return ptvc_lists.Add(ptvc)
376 "Returns a C symbol based on the NCP function code"
377 return "ncp_0x%x" % (self.func_code)
380 """Returns a list of variables used in the request and reply records.
381 A variable is listed only once, even if it is used twice (once in
382 the request, once in the reply)."""
385 if self.request_records:
386 for record in self.request_records:
390 if self.reply_records:
391 for record in self.reply_records:
395 return variables.keys()
398 def CompletionCodes(self, codes=None):
399 """Sets or returns the list of completion codes. Internally, a NamedList
400 is used to store the completion codes, but the caller of this function
401 never realizes that because Python lists are the input and output."""
409 if not errors.has_key(code):
410 sys.stderr.write("Errors table does not have key 0x%04x for NCP=0x%x\n" % (code,
414 # Delay the exit until here so that the programmer can get the complete
415 # list of missing error codes
419 # Create CompletionCode (NamedList) object and possible add it to
420 # the global list of completion code lists.
421 name = "%s_errors" % (self.CName())
423 codes_list = NamedList(name, codes)
424 self.codes = compcode_lists.Add(codes_list)
429 """Adds the NCP object to the global collection of NCP objects. This
430 is done automatically after setting the CompletionCode list. Yes, this
431 is a shortcut, but it makes our list of NCP packet definitions look
432 neater, since an explicit "add to global list of packets" is not needed."""
434 # Add packet to global collection of packets
435 if packets.HasMember(self):
436 sys.stderr.write("Already have NCP Function Code 0x%x\n" % \
444 ##############################################################################
446 LE = 1 # Little-Endian
448 NA = -1 # Not Applicable
451 " Virtual class for NCP field types"
458 def __init__(self, abbrev, descr, bytes, endianness = NA):
466 def Abbreviation(self):
469 def Description(self):
473 return "hf_ncp_" + self.abbrev
476 return "ncp." + self.abbrev
478 def EtherealFType(self):
481 def Display(self, newval=None):
486 def ValuesName(self):
492 def Endianness(self):
493 return self.endianness
498 def __init__(self, abbrev, descr):
499 Type.__init__(self, abbrev, descr, 1)
501 # Same as above. Both are provided for convenience
505 def __init__(self, abbrev, descr):
506 Type.__init__(self, abbrev, descr, 1)
511 def __init__(self, abbrev, descr, endianness = BE):
512 Type.__init__(self, abbrev, descr, 2, endianness)
517 def __init__(self, abbrev, descr, endianness = BE):
518 Type.__init__(self, abbrev, descr, 4, endianness)
520 class nstring8(Type):
521 """A string of up to 255 characters. The first byte
522 gives the string length. Thus, the total length of
523 this data structure is from 1 to 256 bytes, including
527 ftype = "FT_UINT_STRING"
528 def __init__(self, abbrev, descr):
529 Type.__init__(self, abbrev, descr, 1)
531 class fw_string(Type):
532 """A fixed-width string of n bytes."""
537 def __init__(self, abbrev, descr, bytes):
538 Type.__init__(self, abbrev, descr, bytes)
542 "NUL-terminated string, with a maximum length"
546 def __init__(self, abbrev, descr):
547 Type.__init__(self, abbrev, descr, -1)
549 class val_string(Type):
550 """Abstract class for val_stringN, where N is number
551 of bits that key takes up."""
556 def __init__(self, abbrev, descr, val_string_array, endianness = BE):
557 Type.__init__(self, abbrev, descr, self.bytes, endianness)
558 self.values = val_string_array
561 result = "static const value_string %s[] = {\n" \
562 % (self.ValuesCName())
563 for val_record in self.values:
564 value = val_record[0]
566 value_repr = self.value_format % value
567 result = result + '\t{ %s,\t"%s" },\n' \
570 value_repr = self.value_format % 0
571 result = result + "\t{ %s,\tNULL },\n" % (value_repr)
572 result = result + "};\n"
576 def ValuesCName(self):
577 return "ncp_%s_vals" % (self.abbrev)
579 def ValuesName(self):
580 return "VALS(%s)" % (self.ValuesCName())
582 class val_string8(val_string):
586 value_format = "0x%02x"
588 class val_string16(val_string):
589 type = "val_string16"
592 value_format = "0x%04x"
598 def __init__(self, abbrev, descr, bytes):
599 Type.__init__(self, abbrev, descr, bytes, NA)
604 # def __init__(self, abbrev, descr):
605 # Type.__init__(self, abbrev, descr, -1)
607 # def length_var(self, length_var):
608 # self.length_var = length_var
610 ##############################################################################
611 # NCP Field Types. Defined in Appendix A of "Programmer's Guide..."
612 ##############################################################################
613 BufferSize = uint16("buffer_size", "Buffer Size")
614 ConnectionNumber = uint32("connection_number", "Connection Number")
615 DirHandle = byte("dir_handle", "Directory Handle")
617 FileHandle = bytes("file_handle", "File Handle", 6)
619 FileLock = val_string8("file_lock", "File Lock", [
620 [ 0x00, "Not Locked" ],
621 [ 0xfe, "Locked by file lock" ],
625 FileOffset = uint32("file_offset", "File Offset")
626 FilePath = nstring8("file_path", "File Path")
627 FileSize = uint32("file_size", "File Size")
628 JobType = uint16("job_type", "Job Type")
630 LogicalLockType = val_string8("logical_lock_type", "Logical Lock Type", [
631 [ 0x00, "Log file" ],
632 [ 0x01, "Log and lock file for exclusive read/write use" ],
633 [ 0x03, "Log and lock with shareable read-only use" ],
636 LogicalRecordName = nstring8("logical_record_name", "Logical Record Name")
637 LogLockType = byte("log_lock_type", "Log Lock Type")
639 MaxBytes = uint16("max_bytes", "Maximum Number of Bytes")
640 NumBytes = uint16("num_bytes", "Number of Bytes")
642 ObjectFlags = val_string8("object_flags", "Object Flags", [
643 [ 0x00, "Dynamic object" ],
644 [ 0x01, "Static object" ],
647 ObjectHasProperties = val_string8("object_has_properites", "Object Has Properties", [
648 [ 0x00, "No properties" ],
649 [ 0xff, "One or more properties" ],
652 ObjectID = uint32("object_id", "Object ID")
653 ObjectID.Display('BASE_HEX')
655 ObjectName = nstring8("object_name", "Object Name")
656 ObjectName1 = fw_string("object_name1", "Object Name", 48)
658 ObjectSecurity = val_string8("object_security", "Object Security", [
659 [ 0x00, "Anyone can read or modify the object" ],
660 [ 0x01, "Client logged into the file server can read the object" ],
661 [ 0x02, "Client logged into the file server with the object's name, type and password can read the object" ],
662 [ 0x03, "Client with supervisor equivalence can read the object" ],
663 [ 0x04, "Only the operating system can read the object" ],
664 [ 0x10, "Client logged into the file server can modify the object" ],
665 [ 0x20, "Client logged into the file server with the object's name, type and password can modify the object" ],
666 [ 0x30, "Client with supervisor equivalence can modify the object" ],
667 [ 0x40, "Only the operating system can modify the object" ],
670 ObjectType = val_string16("object_type", "Object Type", [
671 [ 0x0000, "Unknown" ],
673 [ 0x0002, "User group" ],
674 [ 0x0003, "Print queue" ],
675 [ 0x0004, "NetWare file server" ],
676 [ 0x0005, "Job server" ],
677 [ 0x0006, "Gateway" ],
678 [ 0x0007, "Print server" ],
679 [ 0x0008, "Archive queue" ],
680 [ 0x0009, "Archive server" ],
681 [ 0x000a, "Job queue" ],
682 [ 0x000b, "Administration" ],
683 [ 0x0021, "NAS SNA gateway" ],
684 [ 0x0026, "Remote bridge server" ],
685 [ 0x0027, "TCP/IP gateway" ],
688 PropertyHasMoreSegments = val_string8("property_has_more_segments",
689 "Property Has More Segments", [
690 [ 0x00, "Is last segment" ],
691 [ 0xff, "More segments are available" ],
694 PropertyName = nstring8("property_name", "Property Name")
695 PropertyData = bytes("property_data", "Property Data", 128)
696 PropertySegment = uint8("property_segment", "Property Segment")
698 PropertyType = val_string8("property_type", "Property Type", [
699 [ 0x00, "Static item" ],
700 [ 0x01, "Dynamic item" ],
701 [ 0x02, "Static set" ],
702 [ 0x03, "Dynamic set" ],
705 TaskNumber = uint32("task_number", "Task Number")
706 TimeoutLimit = uint16("timeout_limit", "Timeout Limit")
707 UnknownByte = byte("unknown_byte", "Unknown Byte")
710 ##############################################################################
712 ##############################################################################
714 groups['accounting'] = "Accounting"
715 groups['afp'] = "AFP"
716 groups['auditing'] = "Auditing"
717 groups['bindery'] = "Bindery"
718 groups['connection'] = "Connection"
719 groups['directory'] = "Directory"
720 groups['extended'] = "Extended Attribute"
721 groups['file'] = "File"
722 groups['fileserver'] = "File Server"
723 groups['message'] = "Message"
724 groups['migration'] = "Data Migration"
725 groups['misc'] = "Miscellaneous"
726 groups['name'] = "Name Space"
727 groups['nds'] = "NetWare Directory"
728 groups['print'] = "Print"
729 groups['queue'] = "Queue"
730 groups['sync'] = "Synchronization"
731 groups['tss'] = "Transaction Tracking"
733 ##############################################################################
735 ##############################################################################
737 errors[0x0000] = "Ok"
738 errors[0x0001] = "Transaction tracking is available"
739 errors[0x0002] = "Ok. The data has been written"
741 errors[0x0100] = "One or more of the ConnectionNumbers in the send list are invalid"
742 errors[0x0101] = "Invalid space limit"
743 errors[0x0102] = "Insufficient disk space"
744 errors[0x0103] = "Queue server cannot add jobs"
745 errors[0x0104] = "Out of disk space"
746 errors[0x0105] = "Semaphore overflow"
748 errors[0x0200] = "One or more clients in the send list are not logged in"
749 errors[0x0201] = "Queue server cannot attach"
751 errors[0x0300] = "One or more clients in the send list are not accepting messages"
753 errors[0x0400] = "Client already has message"
754 errors[0x0401] = "Queue server cannot service job"
756 errors[0x7e00] = "NCP failed boundary check"
758 errors[0x8000] = "Lock fail"
759 errors[0x8100] = "A file handle could not be allocated by the file server"
760 errors[0x8200] = "Unauthorized to open the file"
761 errors[0x8300] = "Unable to read/write the volume. Possible bad sector on the file server"
763 errors[0x8400] = "Unauthorized to create the directory"
764 errors[0x8401] = "Unauthorized to create the file"
766 errors[0x8500] = "Unauthorized to delete the specified file"
767 errors[0x8501] = "Unauthorized to overwrite an existing file in this directory"
769 errors[0x8700] = "An unexpected character was encountered in the filename"
770 errors[0x8800] = "Invalid file handle"
771 errors[0x8900] = "Unauthorized to search this directory"
772 errors[0x8a00] = "Unauthorized to delete this directory"
773 errors[0x8b00] = "Unauthorized to rename a file in this directory"
775 errors[0x8c00] = "No set privileges"
776 errors[0x8c01] = "Unauthorized to modify a file in this directory"
777 errors[0x8c02] = "Unauthorized to change the restriction on this volume"
779 errors[0x8d00] = "Some of the affected files are in use by another client"
780 errors[0x8d01] = "The affected file is in use"
782 errors[0x8e00] = "All of the affected files are in use by another client"
783 errors[0x8f00] = "Some of the affected files are read-only"
785 errors[0x9000] = "An attempt to modify a read-only volume occurred"
786 errors[0x9001] = "All of the affected files are read-only"
788 errors[0x9100] = "Some of the affected files already exist"
790 errors[0x9200] = "Directory with the new name already exists"
791 errors[0x9201] = "All of the affected files already exist"
793 errors[0x9300] = "Unauthorized to read from this file"
794 errors[0x9400] = "Unauthorized to write to this file"
795 errors[0x9500] = "The affected file is detached"
797 errors[0x9600] = "The file server has run out of memory to service this request"
798 errors[0x9601] = "No alloc space for message"
800 errors[0x9800] = "The affected volume is not mounted"
801 errors[0x9801] = "The volume associated with VolumeNumber is not mounted"
802 errors[0x9802] = "The resulting voume does not exist"
803 errors[0x9803] = "The destination volume is not mounted"
805 errors[0x9900] = "The file server has run out of directory space on the affected volume"
806 errors[0x9a00] = "The request attempted to rename the affected file to another volume"
808 errors[0x9b00] = "DirHandle is not associated with a valid directory path"
809 errors[0x9b01] = "A resulting directory handle is not associated with a valid directory path"
810 errors[0x9b02] = "The directory associated with DirHandle does not exist"
811 errors[0x9b03] = "Bad directory handle"
813 errors[0x9c00] = "The resulting path is not valid"
814 errors[0x9c01] = "The resulting file path is not valid"
815 errors[0x9c02] = "The resulting directory path is not valid"
816 errors[0x9c03] = "Invalid path"
818 errors[0x9d00] = "A directory handle was not available for allocation"
820 errors[0x9e00] = "The name of the directory does not conform to a legal name for this name space"
821 errors[0x9e01] = "The new directory name does not conform to a legal name for this name space"
823 errors[0x9f00] = "The request attempted to delete a directory that is in use by another client"
825 errors[0xa000] = "The request attempted to delete a directory that is not empty"
826 errors[0xa100] = "An unrecoverable error occured on the affected directory"
827 errors[0xa200] = "The request attempted to read from a file region that is physically locked"
828 errors[0xa400] = "Invalid directory rename attempted"
830 errors[0xbf00] = "Requests for this name space are not valid on this volume"
832 errors[0xc000] = "Unauthorized to retrieve accounting data"
833 errors[0xc100] = "The ACCOUNT_BALANCE property does not exist"
834 errors[0xc200] = "The object has exceeded its credit limit"
835 errors[0xc300] = "Too many holds have been placed against this account"
836 errors[0xc400] = "The client account has been disabled"
838 errors[0xc500] = "Access to the account has been denied because of intruder detection"
839 errors[0xc501] = "Login lockout"
841 errors[0xc600] = "The caller does not have operator priviliges"
842 errors[0xc601] = "The client does not have operator priviliges"
844 errors[0xd000] = "Queue error"
845 errors[0xd100] = "The queue does not exist"
847 errors[0xd200] = "A queue server is not associated with this queue"
848 errors[0xd201] = "A queue server is not associated with the selected queue"
849 errors[0xd202] = "No queue server"
851 errors[0xd300] = "No queue rights"
853 errors[0xd400] = "The queue is full and cannot accept another request"
854 errors[0xd401] = "The queue associated with ObjectId is full and cannot accept another request"
856 errors[0xd500] = "A job does not exist in this queue"
857 errors[0xd501] = "No queue job"
858 errors[0xd502] = "The job associated with JobNumber does not exist in this queue"
860 errors[0xd600] = "The file server does not allow unencrypted passwords"
861 errors[0xd601] = "No job right"
863 errors[0xd700] = "Bad account"
864 errors[0xd701] = "The old and new password strings are identical"
865 errors[0xd702] = "The job is currently being serviced"
866 errors[0xd703] = "The queue is currently servicing a job"
867 errors[0xd704] = "Queue servicing"
869 errors[0xd800] = "Queue not active"
871 errors[0xd900] = "The file server cannot accept another connection as it has reached its limit"
872 errors[0xd901] = "The client is not security equivalent to one of the objects in the Q_SERVERS group property of the target queue"
873 errors[0xd902] = "Station is not a server"
875 errors[0xda00] = "Attempted to login to the file server during a restricted time period"
876 errors[0xda01] = "Queue halted"
878 errors[0xdb00] = "Attempted to login to the file server from an unauthorized workstation or network"
879 errors[0xdb01] = "The queue cannot attach another queue server"
880 errors[0xdb02] = "Maximum queue servers"
882 errors[0xde00] = "Attempted to login to the file server with an incorrect password"
883 errors[0xdf00] = "Attempted to login to the file server with a password that has expired"
885 errors[0xe700] = "No disk track"
886 errors[0xe800] = "Write to group"
887 errors[0xe900] = "The object is already a member of the group property"
889 errors[0xea00] = "No such member"
890 errors[0xea01] = "The bindery object is not a member of the set"
891 errors[0xea02] = "Non-existent member"
893 errors[0xeb00] = "The property is not a set property"
895 errors[0xec00] = "No such set"
896 errors[0xec01] = "The set property does not exist"
898 errors[0xed00] = "Property exists"
899 errors[0xed01] = "The property already exists"
900 errors[0xed02] = "An attempt was made to create a bindery object property that already exists"
902 errors[0xee00] = "The object already exists"
903 errors[0xee01] = "The bindery object already exists"
905 errors[0xef00] = "Illegal name"
906 errors[0xef01] = "Illegal characters in ObjectName field"
907 errors[0xef02] = "Invalid name"
909 errors[0xf000] = "A wildcard was detected in a field that does not support wildcards"
910 errors[0xf001] = "An illegal wildcard was detected in ObjectName"
912 errors[0xf100] = "The client does not have the rights to access this bindery object"
913 errors[0xf101] = "Bindery security"
914 errors[0xf102] = "Invalid bindery security"
916 errors[0xf200] = "Unauthorized to read from this object"
917 errors[0xf300] = "Unauthorized to rename this object"
919 errors[0xf400] = "Unauthorized to delete this object"
920 errors[0xf401] = "No object delete privileges"
921 errors[0xf402] = "Unauthorized to delete this queue"
923 errors[0xf500] = "Unauthorized to create this object"
924 errors[0xf501] = "No object create"
926 errors[0xf600] = "No property delete"
927 errors[0xf601] = "Unauthorized to delete the property of this object"
928 errors[0xf602] = "Unauthorized to delete this property"
930 errors[0xf700] = "Unauthorized to create this property"
931 errors[0xf701] = "No property create privilege"
933 errors[0xf800] = "Unauthorized to write to this property"
934 errors[0xf900] = "Unauthorized to read this property"
935 errors[0xfa00] = "Temporary remap error"
937 errors[0xfb00] = "No such property"
938 errors[0xfb01] = "The file server does not support this request"
939 errors[0xfb02] = "The specified property does not exist"
940 errors[0xfb03] = "The PASSWORD property does not exist for this bindery object"
942 errors[0xfc00] = "The message queue cannot accept another message"
943 errors[0xfc01] = "The trustee associated with ObjectId does not exist"
944 errors[0xfc02] = "The specified bindery object does not exist"
945 errors[0xfc03] = "The bindery object associated with ObjectID does not exist"
946 errors[0xfc04] = "A bindery object does not exist that matches"
947 errors[0xfc05] = "The specified queue does not exist"
948 errors[0xfc06] = "No such object"
949 errors[0xfc07] = "The queue associated with ObjectID does not exist"
951 errors[0xfd00] = "Bad station number"
952 errors[0xfd01] = "The connection associated with ConnectionNumber is not active"
953 errors[0xfd02] = "Lock collision"
954 errors[0xfd03] = "Transacktion tracking is disabled"
956 errors[0xfe00] = "I/O failure"
957 errors[0xfe01] = "The files containing the bindery on the file server are locked"
958 errors[0xfe02] = "A file with the specified name already exists in this directory"
959 errors[0xfe03] = "No more restrictions were found"
960 errors[0xfe04] = "The file server was unable to lock the file within the specified time limit"
961 errors[0xfe05] = "The file server was unable to lock all files within the specified time limit"
962 errors[0xfe06] = "The bindery object associated with ObjectID is not a valid trustee"
963 errors[0xfe07] = "Directory locked"
964 errors[0xfe08] = "Bindery locked"
965 errors[0xfe09] = "Invalid semaphore name length"
966 errors[0xfe0a] = "The file server was unable to complete the operation within the specified time limit"
967 errors[0xfe0b] = "Transaction restart"
969 errors[0xff00] = "Failure"
970 errors[0xff01] = "Lock error"
971 errors[0xff02] = "File not found"
972 errors[0xff03] = "The file not found or cannot be unlocked"
973 errors[0xff04] = "Record not found"
974 errors[0xff05] = "The logical record was not found"
975 errors[0xff06] = "The printer associated with PrinterNumber does not exist"
976 errors[0xff07] = "No such printer"
977 errors[0xff08] = "Unable to complete the request"
978 errors[0xff09] = "Unauthorized to change privileges of this trustee"
979 errors[0xff0a] = "No files matching the search criteria were found"
980 errors[0xff0b] = "A file matching the search criteria was not found"
981 errors[0xff0c] = "Verification failed"
982 errors[0xff0d] = "Object associated with ObjectID is not a manager"
983 errors[0xff0e] = "Invalid initial semaphore value"
984 errors[0xff0f] = "The semaphore handle is not valid"
985 errors[0xff10] = "SemaphoreHandle is not associated with a valid sempahore"
986 errors[0xff11] = "Invalid semaphore handle"
987 errors[0xff12] = "Transaction tracking is not available"
988 errors[0xff13] = "The transaction has not yet been written to disk"
989 errors[0xff14] = "Directory already exists"
990 errors[0xff15] = "The file already exists and the deletion flag was not set"
991 errors[0xff16] = "No matching files or directories were found"
992 errors[0xff17] = "A file or directory matching the search criteria was not found"
993 errors[0xff18] = "The file already exists"
994 errors[0xff19] = "No files found"
996 ##############################################################################
997 # NCP Packets. Here I list functions and subfunctions in hexadecimal like the
998 # NCP book (and I believe LanAlyzer does this too).
999 # However, Novell lists these in decimal in their on-line documentation.
1000 ##############################################################################
1002 pkt = NCP(0x02, "File Release Lock", 'sync')
1005 pkt.CompletionCodes([0x0000, 0xff00])
1011 #pkt = NCP(0x03, "Log File", 'sync')
1012 #pkt.request( (12, 267), [
1013 # [ 7, 1, DirHandle ],
1014 # [ 8, 1, LogLockType ],
1015 # [ 9, 2, TimeoutLimit, LE ],
1016 # [ 11, (1, 256), FilePath ],
1018 #pkt.completion_codes([0x0000, 0x8200, 0x9600, 0xfe00, 0xff01])
1021 #pkt = NCP(0x04, "Lock File Set", 'sync')
1023 # [ 7, TimeoutLimit ],
1025 #pkt.completion_codes([0xfe, 0xff01])
1028 #pkt = NCP(0x05, "Release File", 'sync')
1033 #pkt.completion_codes([0x7e, 0x98, 0x9b, 0x9c, 0xff02])
1036 #pkt = NCP(0x06, "Release File Set", 'sync')
1038 # [ 7, UnknownByte ],
1040 #pkt.completion_codes()
1043 #pkt = NCP(0x07, "Clear File", 'sync')
1048 #pkt.completion_codes([0x7e, 0x96, 0x98, 0x9b, 0x9c,
1049 # 0xa1, 0xfd, 0xff])
1052 #pkt = NCP(0x08, "Clear File Set", 'sync')
1056 #pkt.completion_codes([0x7e])
1059 #pkt = NCP(0x09, "Log Logical Record", 'sync')
1061 # [ 7, LogicalLockType ],
1062 # [ 8, TimeoutLimit_be ],
1063 # [ 10, LogicalRecordName ],
1065 #pkt.completion_codes([0x96, 0xfe, 0xff])
1068 #pkt = NCP(0x0a, "Lock Logical Record Set", 'sync')
1070 # [ 7, LogicalLockType ],
1071 # [ 8, TimeoutLimit_le ],
1073 #pkt.completion_codes([0xfe, 0xff])
1076 #pkt = NCP(0x0b, "Clear Logical Record", 'sync')
1078 # [7, LogicalRecordName ],
1080 #pkt.completion_codes([0xff]
1088 #pkt = NCP(0x1100, "Lock Logical Record Set", 'sync')
1090 # [ 10, var_length_data("data").length_var("packetlength") ]
1092 #pkt.completion_codes()
1096 pkt = NCP(0x1735, "Get Bindery Object ID", 'bindery')
1097 pkt.Request((13,60), [
1098 [ 10, 2, ObjectType ],
1099 [ 12, (1,48), ObjectName ],
1103 [ 12, 2, ObjectType ],
1104 [ 14, 48, ObjectName1 ],
1106 pkt.CompletionCodes([0x0000, 0x9600, 0xef01, 0xf000, 0xfc02,
1110 pkt = NCP(0x1737, "Scan Bindery Object", 'bindery')
1111 pkt.Request((17,64), [
1112 [ 10, 4, ObjectID ],
1113 [ 14, 2, ObjectType ],
1114 [ 16, (1,48), ObjectName ],
1118 [ 12, 2, ObjectType ],
1119 [ 14, 48, ObjectName1 ],
1120 [ 62, 1, ObjectFlags ],
1121 [ 63, 1, ObjectSecurity ],
1122 [ 64, 1, ObjectHasProperties ],
1124 pkt.CompletionCodes([0x0000, 0x9600, 0xef01, 0xfc02,
1128 pkt = NCP(0x173D, "Read Property Value", 'bindery')
1129 pkt.Request((15,77), [
1130 [ 10, 2, ObjectType ],
1131 [ 12, (1,48), ObjectName ],
1132 [ -1, 1, PropertySegment ],
1133 [ -1, (1,16), PropertyName ],
1136 [ 8, 128, PropertyData ],
1137 [ 136, 1, PropertyHasMoreSegments ],
1138 [ 137, 1, PropertyType ],
1140 pkt.CompletionCodes([0x0000, 0x8800, 0x9300, 0x9600, 0xec01,
1141 0xf000, 0xf100, 0xf900, 0xfb02, 0xfc02, 0xfe01, 0xff00 ])
1144 pkt = NCP(0x177C, "Service Queue Job", 'queue')
1146 [ 10, 4, ObjectID ],
1149 pkt.Reply(24, [ # XXX - 76, [
1150 [ 8, 4, ConnectionNumber ],
1151 [ 12, 4, TaskNumber ],
1152 [ 16, 4, ObjectID ],
1153 [ 20, 4, ObjectID ],
1156 # These completion codes are not documented, but guessed.
1157 pkt.CompletionCodes([0x0000, 0x9900, 0xd000, 0xd100, 0xd201, 0xd300,
1158 0xd401, 0xd502, 0xd601, 0xd704, 0xd800, 0xd901, 0xda01, 0xdb01,
1162 pkt = NCP(0x18, "End of Job", 'connection')
1165 pkt.CompletionCodes([0x0000])
1168 pkt = NCP(0x19, "Logout", 'connection')
1171 pkt.CompletionCodes([0x0000])
1174 pkt = NCP(0x21, "Negotiate Buffer Size", 'connection')
1176 [ 7, 2, BufferSize ],
1179 [ 8, 2, BufferSize ],
1181 pkt.CompletionCodes([0x0000])
1184 pkt = NCP(0x42, "Close File", 'file')
1186 [ 7, 6, FileHandle ],
1189 pkt.CompletionCodes([0x0000, 0xff00])
1192 pkt = NCP(0x47, "Get Current Size of File", 'file')
1194 [ 7, 6, FileHandle ],
1199 pkt.CompletionCodes([0x0000, 0x8800])
1202 pkt = NCP(0x48, "Read From A File", 'file')
1204 [ 7, 1, UnknownByte ],
1205 [ 8, 6, FileHandle ],
1206 [ 14, 4, FileOffset ], # my nomenclature
1207 [ 18, 2, MaxBytes ], # my nomenclature
1209 pkt.Reply(10, [ # XXX - (10,-1), [
1210 [ 8, 2, NumBytes ], # my nomenclature
1213 pkt.CompletionCodes([0x0000, 0x8800, 0x9300, 0xff00])
1215 # 2222/5701 - no info
1216 # 2222/5702 - no info
1217 # 2222/5706 - no info
1218 # 2222/5714 - no info
1222 ##############################################################################
1224 ##############################################################################
1225 if __name__ == '__main__':
1227 print " * Generated automatically from %s" % (sys.argv[0])
1228 print " * Do not edit this file manually, as all changes will be lost."
1233 * This program is free software; you can redistribute it and/or
1234 * modify it under the terms of the GNU General Public License
1235 * as published by the Free Software Foundation; either version 2
1236 * of the License, or (at your option) any later version.
1238 * This program is distributed in the hope that it will be useful,
1239 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1240 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1241 * GNU General Public License for more details.
1243 * You should have received a copy of the GNU General Public License
1244 * along with this program; if not, write to the Free Software
1245 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1248 #ifdef HAVE_CONFIG_H
1249 # include "config.h"
1254 #include "conversation.h"
1255 #include "ptvcursor.h"
1256 #include "packet-ncp-int.h"
1258 static int hf_ncp_func = -1;
1259 static int hf_ncp_length = -1;
1260 static int hf_ncp_subfunc = -1;
1261 static int hf_ncp_completion_code = -1;
1262 static int hf_ncp_connection_status = -1;
1265 # Look at all packet types in the packets collection, and cull information
1268 for packet in packets.Members():
1269 packet_keys.append(packet.FunctionCode())
1272 errors_used_list = []
1273 errors_used_hash = {}
1274 groups_used_list = []
1275 groups_used_hash = {}
1276 variables_used_hash = {}
1278 for pkt in packets.Members():
1279 # Determine which error codes are used.
1280 codes = pkt.CompletionCodes()
1281 for code in codes.Records():
1282 if not errors_used_hash.has_key(code):
1283 errors_used_hash[code] = len(errors_used_list)
1284 errors_used_list.append(code)
1286 # Determine which groups are used.
1288 if not groups_used_hash.has_key(group):
1289 groups_used_hash[group] = len(groups_used_list)
1290 groups_used_list.append(group)
1292 # Determine which variables are used.
1293 vars = pkt.Variables()
1295 variables_used_hash[var] = 1
1299 # Print the hf variable declarations
1300 for var in variables_used_hash.keys():
1301 print "static int " + var.HFName() + " = -1;"
1304 # Print the value_string's
1305 for var in variables_used_hash.keys():
1306 if var.type == "val_string8" or var.type == "val_string16":
1313 proto_register_ncp2222(void)
1316 static hf_register_info hf[] = {
1318 { "Function", "ncp.func", FT_UINT8, BASE_HEX, NULL, 0x0, "" }},
1321 { "Packet Length", "ncp.length", FT_UINT16, BASE_DEC, NULL, 0x0, "" }},
1324 { "SubFunction", "ncp.subfunc", FT_UINT8, BASE_HEX, NULL, 0x0, "" }},
1326 { &hf_ncp_completion_code,
1327 { "Completion Code", "ncp.completion_code", FT_UINT8, BASE_HEX, NULL, 0x0, "" }},
1329 { &hf_ncp_connection_status,
1330 { "Connection Status", "ncp.connection_status", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1333 # Print the registration code for the hf variables
1334 for var in variables_used_hash.keys():
1335 print "\t{ &%s," % (var.HFName())
1336 print "\t{ \"%s\", \"%s\", %s, %s, %s, 0x%x, \"\" }},\n" % \
1337 (var.Description(), var.DFilter(),
1338 var.EtherealFType(), var.Display(), var.ValuesName(),
1343 proto_register_field_array(proto_ncp, hf, array_length(hf));
1348 # Determine which error codes are not used
1349 errors_not_used = {}
1350 # Copy the keys from the error list...
1351 for code in errors.keys():
1352 errors_not_used[code] = 1
1353 # ... and remove the ones that *were* used.
1354 for code in errors_used_list:
1355 del errors_not_used[code]
1357 # Print a remark showing errors not used
1358 list_errors_not_used = errors_not_used.keys()
1359 list_errors_not_used.sort()
1360 for code in list_errors_not_used:
1361 print "/* Error 0x%04x not used: %s */" % (code, errors[code])
1364 # Print the errors table
1365 print "/* Error strings. */"
1366 print "static const char *ncp_errors[] = {"
1367 for code in errors_used_list:
1368 print '\t/* %02d (0x%04x) */ "%s",' % (errors_used_hash[code], code, errors[code])
1374 # Determine which groups are not used
1375 groups_not_used = {}
1376 # Copy the keys from the group list...
1377 for group in groups.keys():
1378 groups_not_used[group] = 1
1379 # ... and remove the ones that *were* used.
1380 for group in groups_used_list:
1381 del groups_not_used[group]
1383 # Print a remark showing groups not used
1384 list_groups_not_used = groups_not_used.keys()
1385 list_groups_not_used.sort()
1386 for group in list_groups_not_used:
1387 print "/* Group not used: %s = %s */" % (group, groups[group])
1390 # Print the groups table
1391 print "/* Group strings. */"
1392 print "static const char *ncp_groups[] = {"
1393 for group in groups_used_list:
1394 print '\t/* %02d (%s) */ "%s",' % (groups_used_hash[group], group, groups[group])
1398 print "/* PTVC records. These are re-used to save space. */"
1399 for ptvc in ptvc_lists.Members():
1400 if not ptvc.Null() and not ptvc.Empty():
1401 print "static const ptvc_record %s[] = {" % (ptvc.Name())
1402 records = ptvc.Records()
1403 for ptvc_rec in records:
1404 print "\t%s," % (ptvc_rec)
1405 print "\t{ NULL, 0, 0 }"
1408 # Print error_equivalency tables
1409 print "/* Error-Equivalency Tables. These are re-used to save space. */"
1410 for compcodes in compcode_lists.Members():
1411 errors = compcodes.Records()
1412 # Make sure the record for error = 0x00 comes last.
1413 print "static const error_equivalency %s[] = {" % (compcodes.Name())
1414 for error in errors:
1415 error_in_packet = error >> 8;
1416 ncp_error_index = errors_used_hash[error]
1417 print "\t{ 0x%02x, %d }, /* 0x%04x */" % (error_in_packet,
1418 ncp_error_index, error)
1419 print "\t{ 0x00, -1 }\n};\n"
1422 # Print ncp_record packet records
1423 print "#define SUBFUNC 0xff"
1424 print "#define NOSUB 0x00"
1426 print "/* ncp_record structs for packets */"
1427 print "static const ncp_record ncp_packets[] = {"
1428 for pkt in packets.Members():
1429 if pkt.HasSubFunction():
1430 subfunc_string = "SUBFUNC"
1432 subfunc_string = "NOSUB"
1433 print '\t{ 0x%02x, 0x%02x, %s, "%s",' % (pkt.FunctionCode('high'),
1434 pkt.FunctionCode('low'), subfunc_string, pkt.Description()),
1436 print '\t%d /* %s */,' % (groups_used_hash[pkt.Group()], pkt.Group())
1438 ptvc = pkt.PTVCRequest()
1439 if not ptvc.Null() and not ptvc.Empty():
1440 ptvc_request = ptvc.Name()
1442 ptvc_request = 'NULL'
1444 ptvc = pkt.PTVCReply()
1445 if not ptvc.Null() and not ptvc.Empty():
1446 ptvc_reply = ptvc.Name()
1450 errors = pkt.CompletionCodes()
1451 print '\t\t%s, NULL, %s, NULL,' % (ptvc_request, ptvc_reply)
1452 print '\t\t%s },\n' % (errors.Name())
1454 print '\t{ 0, 0, 0, NULL }'
1457 print "/* ncp funcs that require a subfunc */"
1458 print "static const guint8 ncp_func_requires_subfunc[] = {"
1460 for pkt in packets.Members():
1461 if pkt.HasSubFunction():
1462 hi_func = pkt.FunctionCode('high')
1463 if not hi_seen.has_key(hi_func):
1464 print "\t0x%02x," % (hi_func)
1465 hi_seen[hi_func] = 1
1470 print '#include "packet-ncp2222.inc"'