wireshark/ncp2222.py

1763 lines
51 KiB
Python
Raw Normal View History

#!/usr/bin/python
"""
Creates C code from a table of NCP type 0x2222 packet types.
(And 0x3333, which are the replies, but the packets are more commonly
refered to as type 0x2222; the 0x3333 replies are understood to be
part of the 0x2222 "family")
Data comes from "Programmer's Guide to the NetWare Core Protocol"
by Steve Conner and Dianne Conner.
Novell provides info at:
http://developer.novell.com/ndk (where you can download an *.exe file which
installs a PDF)
or
http://developer.novell.com/ndk/doc/docui/index.htm#../ncp/ncp__enu/data/
for a badly-formatted HTML version of the same PDF.
$Id: ncp2222.py,v 1.14 2002/01/21 07:36:31 guy Exp $
Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""
import sys
import string
errors = {}
groups = {}
packets = None
compcode_lists = None
ptvc_lists = None
##############################################################################
# Global containers
##############################################################################
class UniqueCollection:
"""The UniqueCollection class stores objects which can be compared to other
objects of the same class. If two objects in the collection are equivalent,
only one is stored."""
def __init__(self, name):
"Constructor"
self.name = name
self.members = []
def Add(self, object):
"""Add an object to the members lists, if a comparable object
doesn't already exist. The object that is in the member list, that is
either the object that was added or the comparable object that was
already in the member list, is returned."""
# Is 'object' a duplicate of some other member?
for member in self.members:
if member == object:
return member
# Store object in our members list.
self.members.append(object)
return object
def Members(self):
"Returns the list of members."
return self.members
def HasMember(self, object):
"Does the list of members contain the object?"
for member in self.members:
if member == object:
return 1
return 0
# This list needs to be defined before the NCP types are defined,
# because the NCP types are defined in the global scope, not inside
# a function's scope.
ptvc_lists = UniqueCollection('PTVC Lists')
##############################################################################
class NamedList:
"NamedList's keep track of PTVC's and Completion Codes"
def __init__(self, name, list):
"Constructor"
self.name = name
self.list = list
def __cmp__(self, other):
"Compare this NamedList to another"
# Python will do a deep comparison of lists within lists.
if self.list < other.list:
return -1
elif self.list > other.list:
return 1
else:
return 0
def __repr__(self):
"String representation"
return "NamedList: " + `self.list`
def Name(self, new_name = None):
"Get/Set name of list"
if new_name != None:
self.name = new_name
return self.name
def Records(self):
"Returns record lists"
return self.list
def Null(self):
"Is there no list (different from an empty list)?"
return self.list == None
def Empty(self):
"It the list empty (different from a null list)?"
assert(not self.Null())
if self.list:
return 0
else:
return 1
class PTVC(NamedList):
"""ProtoTree TVBuff Cursor List ("PTVC List") Class"""
def __init__(self, name, records):
"Constructor"
NamedList.__init__(self, name, [])
expected_offset = None
# Make a PTVCRecord object for each list in 'records'
for record in records:
offset = record[0]
length = record[1]
field = record[2]
# Check if an endianness override is given
try:
endianness = record[3]
# If no endianness was given in the record, then
# use the field's default endianness.
except IndexError:
endianness = field.Endianness()
ptvc_rec = PTVCRecord(field, length, endianness)
if expected_offset == None:
expected_offset = offset
elif expected_offset == -1:
pass
elif expected_offset != offset:
sys.stderr.write("Expected offset in %s to be %d\n" % (name,
expected_offset))
sys.exit(1)
# We can't make a PTVC list from a variable-length
# packet, unless it's FT_UINT_STRING
if type(ptvc_rec.Length()) == type(()):
if isinstance(ptvc_rec.Field(), nstring8):
expected_offset = -1
pass
else:
self.list = None
return
elif expected_offset > -1:
expected_offset = expected_offset + ptvc_rec.Length()
self.list.append(ptvc_rec)
def __str__(self):
x = "static const ptvc_record %s[] = {\n" % (self.Name())
for ptvc_rec in self.list:
x = x + "\t%s,\n" % (ptvc_rec)
x = x + "\t{ NULL, 0, 0, NULL }\n"
x = x + "};\n"
return x
class PTVCBitfield(PTVC):
def __init__(self, name, vars):
NamedList.__init__(self, name, [])
for var in vars:
ptvc_rec = PTVCRecord(var, var.Length(), var.Endianness())
self.list.append(ptvc_rec)
def ETTName(self):
return "ett_%s" % (self.Name(),)
def __str__(self):
ett_name = self.ETTName()
x = "static gint %s;\n" % (ett_name,)
x = x + "static const ptvc_record ptvc_%s[] = {\n" % (self.Name())
for ptvc_rec in self.list:
x = x + "\t%s,\n" % (ptvc_rec)
x = x + "\t{ NULL, 0, 0, NULL }\n"
x = x + "};\n"
x = x + "static const sub_ptvc_record %s = {\n" % (self.Name(),)
x = x + "\t&%s,\n" % (ett_name,)
x = x + "\tptvc_%s,\n" % (self.Name(),)
x = x + "};\n"
return x
class PTVCRecord:
def __init__(self, field, length, endianness):
"Constructor"
self.field = field
self.length = length
self.endianness = endianness
def __cmp__(self, other):
"Comparison operator"
if self.length < other.length:
return -1
elif self.length > other.length:
return 1
if self.field != other.field:
return 1
elif self.endianness != other.endianness:
return 1
else:
return 0
def __str__(self):
"String representation"
endianness = 'FALSE'
if self.endianness == LE:
endianness = 'TRUE'
# Default the length to this value
length = "PTVC_VARIABLE_LENGTH"
if type(self.length) == type(0):
length = self.length
else:
var_length = self.field.Length()
if var_length > 0:
length = var_length
sub_ptvc_name = self.field.PTVCName()
if sub_ptvc_name != "NULL":
sub_ptvc_name = "&%s" % (sub_ptvc_name,)
return "{ &%s, %s, %s, %s }" % (self.field.HFName(),
length, endianness, sub_ptvc_name)
def Offset(self):
return self.offset
def Length(self):
return self.length
def Field(self):
return self.field
##############################################################################
class NCP:
"NCP Packet class"
def __init__(self, func_code, description, group, has_length=1):
"Constructor"
self.func_code = func_code
self.description = description
self.group = group
self.codes = None
self.request_records = None
self.reply_records = None
self.has_length = has_length
if not groups.has_key(group):
sys.stderr.write("NCP 0x%x has invalid group '%s'\n" % (self.func_code, group))
sys.exit(1)
if self.HasSubFunction():
# NCP Function with SubFunction
self.start_offset = 10
else:
# Simple NCP Function
self.start_offset = 7
def FunctionCode(self, part=None):
"Returns the function code for this NCP packet."
if part == None:
return self.func_code
elif part == 'high':
if self.HasSubFunction():
return (self.func_code & 0xff00) >> 8
else:
return self.func_code
elif part == 'low':
if self.HasSubFunction():
return self.func_code & 0x00ff
else:
return 0x00
else:
sys.stderr.write("Unknown directive '%s' for function_code()\n" % (part))
sys.exit(1)
def HasSubFunction(self):
"Does this NPC packet require a subfunction field?"
if self.func_code <= 0xff:
return 0
else:
return 1
def HasLength(self):
return self.has_length
def Description(self):
return self.description
def Group(self):
return self.group
def PTVCRequest(self):
return self.ptvc_request
def PTVCReply(self):
return self.ptvc_reply
def Request(self, size, records=[]):
self.request_size = size
self.request_records = records
if self.HasSubFunction():
if self.HasLength():
self.CheckRecords(size, records, "Request", 10)
else:
self.CheckRecords(size, records, "Request", 8)
else:
self.CheckRecords(size, records, "Request", 7)
self.ptvc_request = self.MakePTVC(records, "request")
def Reply(self, size, records=[]):
self.reply_size = size
self.reply_records = records
self.CheckRecords(size, records, "Reply", 8)
self.ptvc_reply = self.MakePTVC(records, "reply")
def CheckRecords(self, size, records, descr, min_hdr_length):
"Simple sanity check"
min = size
max = size
if type(size) == type(()):
min = size[0]
max = size[1]
lower = min_hdr_length
upper = min_hdr_length
for record in records:
rec_size = record[1]
rec_lower = rec_size
rec_upper = rec_size
if type(rec_size) == type(()):
rec_lower = rec_size[0]
rec_upper = rec_size[1]
lower = lower + rec_lower
upper = upper + rec_upper
error = 0
if min != lower:
sys.stderr.write("%s records for 2222/0x%x sum to %d bytes minimum, but param1 shows %d\n" \
% (descr, self.FunctionCode(), lower, min))
error = 1
if max != upper:
sys.stderr.write("%s records for 2222/0x%x sum to %d bytes maximum, but param1 shows %d\n" \
% (descr, self.FunctionCode(), upper, max))
error = 1
if error == 1:
sys.exit(1)
def MakePTVC(self, records, name_suffix):
"""Makes a PTVC out of a request or reply record list. Possibly adds
it to the global list of PTVCs (the global list is a UniqueCollection,
so an equivalent PTVC may already be in the global list)."""
name = "%s_%s" % (self.CName(), name_suffix)
ptvc = PTVC(name, records)
return ptvc_lists.Add(ptvc)
def CName(self):
"Returns a C symbol based on the NCP function code"
return "ncp_0x%x" % (self.func_code)
def Variables(self):
"""Returns a list of variables used in the request and reply records.
A variable is listed only once, even if it is used twice (once in
the request, once in the reply)."""
variables = {}
if self.request_records:
for record in self.request_records:
var = record[2]
variables[var] = 1
sub_vars = var.SubVariables()
for sv in sub_vars:
variables[sv] = 1
if self.reply_records:
for record in self.reply_records:
var = record[2]
variables[var] = 1
sub_vars = var.SubVariables()
for sv in sub_vars:
variables[sv] = 1
return variables.keys()
def CompletionCodes(self, codes=None):
"""Sets or returns the list of completion codes. Internally, a NamedList
is used to store the completion codes, but the caller of this function
never realizes that because Python lists are the input and output."""
if codes == None:
return self.codes
# Sanity check
okay = 1
for code in codes:
if not errors.has_key(code):
sys.stderr.write("Errors table does not have key 0x%04x for NCP=0x%x\n" % (code,
self.func_code))
okay = 0
# Delay the exit until here so that the programmer can get the complete
# list of missing error codes
if not okay:
sys.exit(1)
# Create CompletionCode (NamedList) object and possible add it to
# the global list of completion code lists.
name = "%s_errors" % (self.CName())
codes.sort()
codes_list = NamedList(name, codes)
self.codes = compcode_lists.Add(codes_list)
self.Finalize()
def Finalize(self):
"""Adds the NCP object to the global collection of NCP objects. This
is done automatically after setting the CompletionCode list. Yes, this
is a shortcut, but it makes our list of NCP packet definitions look
neater, since an explicit "add to global list of packets" is not needed."""
# Add packet to global collection of packets
if packets.HasMember(self):
sys.stderr.write("Already have NCP Function Code 0x%x\n" % \
(self.func_code))
sys.exit(1)
else:
packets.Add(self)
##############################################################################
LE = 1 # Little-Endian
BE = 0 # Big-Endian
NA = -1 # Not Applicable
class Type:
" Virtual class for NCP field types"
type = "Type"
ftype = None
disp = "BASE_DEC"
endianness = NA
values = []
def __init__(self, abbrev, descr, bytes, endianness = NA):
self.abbrev = abbrev
self.descr = descr
self.bytes = bytes
def Length(self):
return self.bytes
def Abbreviation(self):
return self.abbrev
def Description(self):
return self.descr
def HFName(self):
return "hf_ncp_" + self.abbrev
def DFilter(self):
return "ncp." + self.abbrev
def EtherealFType(self):
return self.ftype
def Display(self, newval=None):
if newval != None:
self.disp = newval
return self.disp
def ValuesName(self):
return "NULL"
def Mask(self):
return 0
def Endianness(self):
return self.endianness
def SubVariables(self):
return []
def PTVCName(self):
return "NULL"
class byte(Type):
type = "byte"
ftype = "FT_UINT8"
def __init__(self, abbrev, descr):
Type.__init__(self, abbrev, descr, 1)
# Same as above. Both are provided for convenience
class uint8(Type):
type = "uint8"
ftype = "FT_UINT8"
bytes = 1
def __init__(self, abbrev, descr):
Type.__init__(self, abbrev, descr, 1)
class boolean8(uint8):
type = "boolean8"
ftype = "FT_BOOLEAN"
class uint16(Type):
type = "uint16"
ftype = "FT_UINT16"
def __init__(self, abbrev, descr, endianness = BE):
Type.__init__(self, abbrev, descr, 2, endianness)
class uint32(Type):
type = "uint32"
ftype = "FT_UINT32"
def __init__(self, abbrev, descr, endianness = BE):
Type.__init__(self, abbrev, descr, 4, endianness)
class nstring8(Type):
"""A string of up to 255 characters. The first byte
gives the string length. Thus, the total length of
this data structure is from 1 to 256 bytes, including
the first byte."""
type = "nstring8"
ftype = "FT_UINT_STRING"
def __init__(self, abbrev, descr):
Type.__init__(self, abbrev, descr, 1)
class fw_string(Type):
"""A fixed-width string of n bytes."""
type = "fw_string"
ftype = "FT_STRING"
def __init__(self, abbrev, descr, bytes):
Type.__init__(self, abbrev, descr, bytes)
class stringz(Type):
"NUL-terminated string, with a maximum length"
type = "stringz"
ftype = "FT_STRINGZ"
def __init__(self, abbrev, descr):
Type.__init__(self, abbrev, descr, -1)
class val_string(Type):
"""Abstract class for val_stringN, where N is number
of bits that key takes up."""
type = "val_string"
disp = 'BASE_HEX'
def __init__(self, abbrev, descr, val_string_array, endianness = BE):
Type.__init__(self, abbrev, descr, self.bytes, endianness)
self.values = val_string_array
def __repr__(self):
result = "static const value_string %s[] = {\n" \
% (self.ValuesCName())
for val_record in self.values:
value = val_record[0]
text = val_record[1]
value_repr = self.value_format % value
result = result + '\t{ %s,\t"%s" },\n' \
% (value_repr, text)
value_repr = self.value_format % 0
result = result + "\t{ %s,\tNULL },\n" % (value_repr)
result = result + "};\n"
return result
def ValuesCName(self):
return "ncp_%s_vals" % (self.abbrev)
def ValuesName(self):
return "VALS(%s)" % (self.ValuesCName())
class val_string8(val_string):
type = "val_string8"
ftype = "FT_UINT8"
bytes = 1
value_format = "0x%02x"
class val_string16(val_string):
type = "val_string16"
ftype = "FT_UINT16"
bytes = 2
value_format = "0x%04x"
class bytes(Type):
type = 'bytes'
ftype = 'FT_BYTES'
def __init__(self, abbrev, descr, bytes):
Type.__init__(self, abbrev, descr, bytes, NA)
class bitfield(Type):
type = "bitfield"
disp = 'BASE_HEX'
def __init__(self, vars):
var_hash = {}
for var in vars:
var_hash[var.bitmask] = var
bitmasks = var_hash.keys()
bitmasks.sort()
bitmasks.reverse()
ordered_vars = []
for bitmask in bitmasks:
var = var_hash[bitmask]
ordered_vars.append(var)
self.vars = ordered_vars
self.sub_ptvc = PTVCBitfield(self.PTVCName(), self.vars)
def SubVariables(self):
return self.vars
def SubVariablesPTVC(self):
return self.sub_ptvc
def PTVCName(self):
return "ncp_%s_bitfield" % (self.abbrev,)
class bitfield8(bitfield, uint8):
type = "bitfield8"
ftype = "FT_UINT8"
def __init__(self, abbrev, descr, vars):
uint8.__init__(self, abbrev, descr)
bitfield.__init__(self, vars)
class bf_uint(Type):
type = "bf_uint"
disp = 'BASE_HEX'
def __init__(self, bitmask, abbrev, descr):
self.bitmask = bitmask
self.abbrev = abbrev
self.descr = descr
def Mask(self):
return self.bitmask
class bf_boolean8(bf_uint, boolean8):
type = "bf_boolean8"
ftype = "FT_BOOLEAN"
disp = "8"
#class data(Type):
# type = "data"
# ftype = "FT_BYTES"
# def __init__(self, abbrev, descr):
# Type.__init__(self, abbrev, descr, -1)
#
# def length_var(self, length_var):
# self.length_var = length_var
##############################################################################
# NCP Field Types. Defined in Appendix A of "Programmer's Guide..."
##############################################################################
AcceptedMaxSize = uint16("accepted_max_size", "Accepted Max Size")
AcctVersion = byte("acct_version", "Acct Version")
BufferSize = uint16("buffer_size", "Buffer Size")
ConnectionNumber = uint32("connection_number", "Connection Number")
ConnectionsSupportedMax = uint16("connections_supported_max", "Connections Supported Max")
ConnectionsInUse = uint16("connections_in_use", "Connections In Use")
ConnectionsMaxUsed = uint16("connections_max_used", "Connections Max Used")
DirHandle = byte("dir_handle", "Directory Handle")
EchoSocket = uint16("echo_socket", "Echo Socket")
EchoSocket.Display('BASE_HEX')
FileHandle = bytes("file_handle", "File Handle", 6)
FileLock = val_string8("file_lock", "File Lock", [
[ 0x00, "Not Locked" ],
[ 0xfe, "Locked by file lock" ],
[ 0xff, "Unknown" ],
])
FileOffset = uint32("file_offset", "File Offset")
FilePath = nstring8("file_path", "File Path")
FileSize = uint32("file_size", "File Size")
InternetBridgeVersion = byte("internet_bridge_version", "Internet Bridge Version")
JobType = uint16("job_type", "Job Type")
LocalLoginInfoCcode = byte("local_login_info_ccode", "Local Login Info C Code")
LogicalLockType = val_string8("logical_lock_type", "Logical Lock Type", [
[ 0x00, "Log file" ],
[ 0x01, "Log and lock file for exclusive read/write use" ],
[ 0x03, "Log and lock with shareable read-only use" ],
])
LogicalRecordName = nstring8("logical_record_name", "Logical Record Name")
LogLockType = byte("log_lock_type", "Log Lock Type")
MaxBytes = uint16("max_bytes", "Maximum Number of Bytes")
MixedModePathFlag = byte("mixed_mode_path_flag", "Mixed Mode Path Flag")
NumBytes = uint16("num_bytes", "Number of Bytes")
ObjectFlags = val_string8("object_flags", "Object Flags", [
[ 0x00, "Dynamic object" ],
[ 0x01, "Static object" ],
])
ObjectHasProperties = val_string8("object_has_properites", "Object Has Properties", [
[ 0x00, "No properties" ],
[ 0xff, "One or more properties" ],
])
ObjectID = uint32("object_id", "Object ID")
ObjectID.Display('BASE_HEX')
ObjectName = nstring8("object_name", "Object Name")
ObjectName1 = fw_string("object_name1", "Object Name", 48)
ObjectSecurity = val_string8("object_security", "Object Security", [
[ 0x00, "Anyone can read or modify the object" ],
[ 0x01, "Client logged into the file server can read the object" ],
[ 0x02, "Client logged into the file server with the object's name, type and password can read the object" ],
[ 0x03, "Client with supervisor equivalence can read the object" ],
[ 0x04, "Only the operating system can read the object" ],
[ 0x10, "Client logged into the file server can modify the object" ],
[ 0x20, "Client logged into the file server with the object's name, type and password can modify the object" ],
[ 0x30, "Client with supervisor equivalence can modify the object" ],
[ 0x40, "Only the operating system can modify the object" ],
])
ObjectType = val_string16("object_type", "Object Type", [
[ 0x0000, "Unknown" ],
[ 0x0001, "User" ],
[ 0x0002, "User group" ],
[ 0x0003, "Print queue" ],
[ 0x0004, "NetWare file server" ],
[ 0x0005, "Job server" ],
[ 0x0006, "Gateway" ],
[ 0x0007, "Print server" ],
[ 0x0008, "Archive queue" ],
[ 0x0009, "Archive server" ],
[ 0x000a, "Job queue" ],
[ 0x000b, "Administration" ],
[ 0x0021, "NAS SNA gateway" ],
[ 0x0026, "Remote bridge server" ],
[ 0x0027, "TCP/IP gateway" ],
])
OSLanguageID = byte("os_language_id", "OS Language ID")
OSMajorVersion = byte("os_major_version", "OS Major Version")
OSMinorVersion = byte("os_minor_version", "OS Minor Version")
OSRevision = byte("os_revision", "OS Revision")
PingVersion = uint16("ping_version", "Ping Version", endianness=LE)
PingVersion.Display("BASE_HEX")
PrintServerVersion = byte("print_server_version", "Print Server Version")
ProductMajorVersion = uint16("product_major_version", "Product Major Version")
ProductMinorVersion = uint16("product_minor_version", "Product Minor Version")
ProductRevisionVersion = byte("product_revision_version", "Product Revision Version")
PropertyHasMoreSegments = val_string8("property_has_more_segments",
"Property Has More Segments", [
[ 0x00, "Is last segment" ],
[ 0xff, "More segments are available" ],
])
PropertyName = nstring8("property_name", "Property Name")
PropertyData = bytes("property_data", "Property Data", 128)
PropertySegment = uint8("property_segment", "Property Segment")
PropertyType = val_string8("property_type", "Property Type", [
[ 0x00, "Static item" ],
[ 0x01, "Dynamic item" ],
[ 0x02, "Static set" ],
[ 0x03, "Dynamic set" ],
])
ProposedMaxSize = uint16("proposed_max_size", "Proposed Max Size")
Reserved3 = bytes("reserved3", "Reserved", 3)
Reserved51 = bytes("reserved51", "Reserved", 51)
QMSVersion = byte("qms_version", "QMS Version")
# XXX - needs bitfield
SecurityFlag = byte("security_flag", "Security Flag")
SecurityRestrictionVersion = byte("security_restriction_version", "Security Restriction Version")
ServerName = stringz("server_name", "Server Name")
SFTLevel = byte("sft_level", "SFT Level")
TaskNumber = uint32("task_number", "Task Number")
TimeoutLimit = uint16("timeout_limit", "Timeout Limit")
TTSLevel = byte("tts_level", "TTS Level")
UnknownByte = byte("unknown_byte", "Unknown Byte")
VAPVersion = byte("vap_version", "VAP Version")
VirtualConsoleVersion = byte("virtual_console_version", "Virtual Console Version")
VolumesSupportedMax = uint16("volumes_supported_max", "Volumes Supported Max")
##############################################################################
# NCP Groups
##############################################################################
def define_groups():
groups['accounting'] = "Accounting"
groups['afp'] = "AFP"
groups['auditing'] = "Auditing"
groups['bindery'] = "Bindery"
groups['connection'] = "Connection"
groups['directory'] = "Directory"
groups['extended'] = "Extended Attribute"
groups['file'] = "File"
groups['fileserver'] = "File Server"
groups['message'] = "Message"
groups['migration'] = "Data Migration"
groups['misc'] = "Miscellaneous"
groups['name'] = "Name Space"
groups['nds'] = "NetWare Directory"
groups['print'] = "Print"
groups['queue'] = "Queue"
groups['sync'] = "Synchronization"
groups['tss'] = "Transaction Tracking"
groups['unknown'] = "Unknown"
##############################################################################
# NCP Errors
##############################################################################
def define_errors():
errors[0x0000] = "Ok"
errors[0x0001] = "Transaction tracking is available"
errors[0x0002] = "Ok. The data has been written"
errors[0x0100] = "One or more of the ConnectionNumbers in the send list are invalid"
errors[0x0101] = "Invalid space limit"
errors[0x0102] = "Insufficient disk space"
errors[0x0103] = "Queue server cannot add jobs"
errors[0x0104] = "Out of disk space"
errors[0x0105] = "Semaphore overflow"
errors[0x0200] = "One or more clients in the send list are not logged in"
errors[0x0201] = "Queue server cannot attach"
errors[0x0300] = "One or more clients in the send list are not accepting messages"
errors[0x0400] = "Client already has message"
errors[0x0401] = "Queue server cannot service job"
errors[0x7e00] = "NCP failed boundary check"
errors[0x8000] = "Lock fail"
errors[0x8100] = "A file handle could not be allocated by the file server"
errors[0x8200] = "Unauthorized to open the file"
errors[0x8300] = "Unable to read/write the volume. Possible bad sector on the file server"
errors[0x8400] = "Unauthorized to create the directory"
errors[0x8401] = "Unauthorized to create the file"
errors[0x8500] = "Unauthorized to delete the specified file"
errors[0x8501] = "Unauthorized to overwrite an existing file in this directory"
errors[0x8700] = "An unexpected character was encountered in the filename"
errors[0x8800] = "Invalid file handle"
errors[0x8900] = "Unauthorized to search this directory"
errors[0x8a00] = "Unauthorized to delete this directory"
errors[0x8b00] = "Unauthorized to rename a file in this directory"
errors[0x8c00] = "No set privileges"
errors[0x8c01] = "Unauthorized to modify a file in this directory"
errors[0x8c02] = "Unauthorized to change the restriction on this volume"
errors[0x8d00] = "Some of the affected files are in use by another client"
errors[0x8d01] = "The affected file is in use"
errors[0x8e00] = "All of the affected files are in use by another client"
errors[0x8f00] = "Some of the affected files are read-only"
errors[0x9000] = "An attempt to modify a read-only volume occurred"
errors[0x9001] = "All of the affected files are read-only"
errors[0x9100] = "Some of the affected files already exist"
errors[0x9200] = "Directory with the new name already exists"
errors[0x9201] = "All of the affected files already exist"
errors[0x9300] = "Unauthorized to read from this file"
errors[0x9400] = "Unauthorized to write to this file"
errors[0x9500] = "The affected file is detached"
errors[0x9600] = "The file server has run out of memory to service this request"
errors[0x9601] = "No alloc space for message"
errors[0x9800] = "The affected volume is not mounted"
errors[0x9801] = "The volume associated with VolumeNumber is not mounted"
errors[0x9802] = "The resulting voume does not exist"
errors[0x9803] = "The destination volume is not mounted"
errors[0x9900] = "The file server has run out of directory space on the affected volume"
errors[0x9a00] = "The request attempted to rename the affected file to another volume"
errors[0x9b00] = "DirHandle is not associated with a valid directory path"
errors[0x9b01] = "A resulting directory handle is not associated with a valid directory path"
errors[0x9b02] = "The directory associated with DirHandle does not exist"
errors[0x9b03] = "Bad directory handle"
errors[0x9c00] = "The resulting path is not valid"
errors[0x9c01] = "The resulting file path is not valid"
errors[0x9c02] = "The resulting directory path is not valid"
errors[0x9c03] = "Invalid path"
errors[0x9d00] = "A directory handle was not available for allocation"
errors[0x9e00] = "The name of the directory does not conform to a legal name for this name space"
errors[0x9e01] = "The new directory name does not conform to a legal name for this name space"
errors[0x9f00] = "The request attempted to delete a directory that is in use by another client"
errors[0xa000] = "The request attempted to delete a directory that is not empty"
errors[0xa100] = "An unrecoverable error occured on the affected directory"
errors[0xa200] = "The request attempted to read from a file region that is physically locked"
errors[0xa400] = "Invalid directory rename attempted"
errors[0xbf00] = "Requests for this name space are not valid on this volume"
errors[0xc000] = "Unauthorized to retrieve accounting data"
errors[0xc100] = "The ACCOUNT_BALANCE property does not exist"
errors[0xc200] = "The object has exceeded its credit limit"
errors[0xc300] = "Too many holds have been placed against this account"
errors[0xc400] = "The client account has been disabled"
errors[0xc500] = "Access to the account has been denied because of intruder detection"
errors[0xc501] = "Login lockout"
errors[0xc600] = "The caller does not have operator priviliges"
errors[0xc601] = "The client does not have operator priviliges"
errors[0xd000] = "Queue error"
errors[0xd100] = "The queue does not exist"
errors[0xd200] = "A queue server is not associated with this queue"
errors[0xd201] = "A queue server is not associated with the selected queue"
errors[0xd202] = "No queue server"
errors[0xd300] = "No queue rights"
errors[0xd400] = "The queue is full and cannot accept another request"
errors[0xd401] = "The queue associated with ObjectId is full and cannot accept another request"
errors[0xd500] = "A job does not exist in this queue"
errors[0xd501] = "No queue job"
errors[0xd502] = "The job associated with JobNumber does not exist in this queue"
errors[0xd600] = "The file server does not allow unencrypted passwords"
errors[0xd601] = "No job right"
errors[0xd700] = "Bad account"
errors[0xd701] = "The old and new password strings are identical"
errors[0xd702] = "The job is currently being serviced"
errors[0xd703] = "The queue is currently servicing a job"
errors[0xd704] = "Queue servicing"
errors[0xd800] = "Queue not active"
errors[0xd900] = "The file server cannot accept another connection as it has reached its limit"
errors[0xd901] = "The client is not security equivalent to one of the objects in the Q_SERVERS group property of the target queue"
errors[0xd902] = "Station is not a server"
errors[0xda00] = "Attempted to login to the file server during a restricted time period"
errors[0xda01] = "Queue halted"
errors[0xdb00] = "Attempted to login to the file server from an unauthorized workstation or network"
errors[0xdb01] = "The queue cannot attach another queue server"
errors[0xdb02] = "Maximum queue servers"
errors[0xde00] = "Attempted to login to the file server with an incorrect password"
errors[0xdf00] = "Attempted to login to the file server with a password that has expired"
errors[0xe700] = "No disk track"
errors[0xe800] = "Write to group"
errors[0xe900] = "The object is already a member of the group property"
errors[0xea00] = "No such member"
errors[0xea01] = "The bindery object is not a member of the set"
errors[0xea02] = "Non-existent member"
errors[0xeb00] = "The property is not a set property"
errors[0xec00] = "No such set"
errors[0xec01] = "The set property does not exist"
errors[0xed00] = "Property exists"
errors[0xed01] = "The property already exists"
errors[0xed02] = "An attempt was made to create a bindery object property that already exists"
errors[0xee00] = "The object already exists"
errors[0xee01] = "The bindery object already exists"
errors[0xef00] = "Illegal name"
errors[0xef01] = "Illegal characters in ObjectName field"
errors[0xef02] = "Invalid name"
errors[0xf000] = "A wildcard was detected in a field that does not support wildcards"
errors[0xf001] = "An illegal wildcard was detected in ObjectName"
errors[0xf100] = "The client does not have the rights to access this bindery object"
errors[0xf101] = "Bindery security"
errors[0xf102] = "Invalid bindery security"
errors[0xf200] = "Unauthorized to read from this object"
errors[0xf300] = "Unauthorized to rename this object"
errors[0xf400] = "Unauthorized to delete this object"
errors[0xf401] = "No object delete privileges"
errors[0xf402] = "Unauthorized to delete this queue"
errors[0xf500] = "Unauthorized to create this object"
errors[0xf501] = "No object create"
errors[0xf600] = "No property delete"
errors[0xf601] = "Unauthorized to delete the property of this object"
errors[0xf602] = "Unauthorized to delete this property"
errors[0xf700] = "Unauthorized to create this property"
errors[0xf701] = "No property create privilege"
errors[0xf800] = "Unauthorized to write to this property"
errors[0xf900] = "Unauthorized to read this property"
errors[0xfa00] = "Temporary remap error"
errors[0xfb00] = "No such property"
errors[0xfb01] = "The file server does not support this request"
errors[0xfb02] = "The specified property does not exist"
errors[0xfb03] = "The PASSWORD property does not exist for this bindery object"
errors[0xfb04] = "NDS NCP not available"
errors[0xfc00] = "The message queue cannot accept another message"
errors[0xfc01] = "The trustee associated with ObjectId does not exist"
errors[0xfc02] = "The specified bindery object does not exist"
errors[0xfc03] = "The bindery object associated with ObjectID does not exist"
errors[0xfc04] = "A bindery object does not exist that matches"
errors[0xfc05] = "The specified queue does not exist"
errors[0xfc06] = "No such object"
errors[0xfc07] = "The queue associated with ObjectID does not exist"
errors[0xfd00] = "Bad station number"
errors[0xfd01] = "The connection associated with ConnectionNumber is not active"
errors[0xfd02] = "Lock collision"
errors[0xfd03] = "Transacktion tracking is disabled"
errors[0xfe00] = "I/O failure"
errors[0xfe01] = "The files containing the bindery on the file server are locked"
errors[0xfe02] = "A file with the specified name already exists in this directory"
errors[0xfe03] = "No more restrictions were found"
errors[0xfe04] = "The file server was unable to lock the file within the specified time limit"
errors[0xfe05] = "The file server was unable to lock all files within the specified time limit"
errors[0xfe06] = "The bindery object associated with ObjectID is not a valid trustee"
errors[0xfe07] = "Directory locked"
errors[0xfe08] = "Bindery locked"
errors[0xfe09] = "Invalid semaphore name length"
errors[0xfe0a] = "The file server was unable to complete the operation within the specified time limit"
errors[0xfe0b] = "Transaction restart"
errors[0xfe0c] = "Bad packet"
errors[0xff00] = "Failure"
errors[0xff01] = "Lock error"
errors[0xff02] = "File not found"
errors[0xff03] = "The file not found or cannot be unlocked"
errors[0xff04] = "Record not found"
errors[0xff05] = "The logical record was not found"
errors[0xff06] = "The printer associated with PrinterNumber does not exist"
errors[0xff07] = "No such printer"
errors[0xff08] = "Unable to complete the request"
errors[0xff09] = "Unauthorized to change privileges of this trustee"
errors[0xff0a] = "No files matching the search criteria were found"
errors[0xff0b] = "A file matching the search criteria was not found"
errors[0xff0c] = "Verification failed"
errors[0xff0d] = "Object associated with ObjectID is not a manager"
errors[0xff0e] = "Invalid initial semaphore value"
errors[0xff0f] = "The semaphore handle is not valid"
errors[0xff10] = "SemaphoreHandle is not associated with a valid sempahore"
errors[0xff11] = "Invalid semaphore handle"
errors[0xff12] = "Transaction tracking is not available"
errors[0xff13] = "The transaction has not yet been written to disk"
errors[0xff14] = "Directory already exists"
errors[0xff15] = "The file already exists and the deletion flag was not set"
errors[0xff16] = "No matching files or directories were found"
errors[0xff17] = "A file or directory matching the search criteria was not found"
errors[0xff18] = "The file already exists"
errors[0xff19] = "No files found"
##############################################################################
# Produce C code
##############################################################################
def produce_code():
global errors
print "/*"
print " * Generated automatically from %s" % (sys.argv[0])
print " * Do not edit this file manually, as all changes will be lost."
print " */\n"
print """
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <glib.h>
#include <epan/packet.h>
#include <epan/conversation.h>
#include "ptvcursor.h"
#include "packet-ncp-int.h"
static int hf_ncp_func = -1;
static int hf_ncp_length = -1;
static int hf_ncp_subfunc = -1;
static int hf_ncp_completion_code = -1;
static int hf_ncp_connection_status = -1;
"""
# Look at all packet types in the packets collection, and cull information
# from them.
packet_keys = []
for packet in packets.Members():
packet_keys.append(packet.FunctionCode())
packet_keys.sort()
errors_used_list = []
errors_used_hash = {}
groups_used_list = []
groups_used_hash = {}
variables_used_hash = {}
for pkt in packets.Members():
# Determine which error codes are used.
codes = pkt.CompletionCodes()
for code in codes.Records():
if not errors_used_hash.has_key(code):
errors_used_hash[code] = len(errors_used_list)
errors_used_list.append(code)
# Determine which groups are used.
group = pkt.Group()
if not groups_used_hash.has_key(group):
groups_used_hash[group] = len(groups_used_list)
groups_used_list.append(group)
# Determine which variables are used.
vars = pkt.Variables()
for var in vars:
variables_used_hash[var] = 1
# Print the hf variable declarations
for var in variables_used_hash.keys():
print "static int " + var.HFName() + " = -1;"
# Print the value_string's
for var in variables_used_hash.keys():
if isinstance(var, val_string):
print ""
print `var`
# Determine which error codes are not used
errors_not_used = {}
# Copy the keys from the error list...
for code in errors.keys():
errors_not_used[code] = 1
# ... and remove the ones that *were* used.
for code in errors_used_list:
del errors_not_used[code]
# Print a remark showing errors not used
list_errors_not_used = errors_not_used.keys()
list_errors_not_used.sort()
for code in list_errors_not_used:
print "/* Error 0x%04x not used: %s */" % (code, errors[code])
print "\n"
# Print the errors table
print "/* Error strings. */"
print "static const char *ncp_errors[] = {"
for code in errors_used_list:
print '\t/* %02d (0x%04x) */ "%s",' % (errors_used_hash[code], code, errors[code])
print "};\n"
# Determine which groups are not used
groups_not_used = {}
# Copy the keys from the group list...
for group in groups.keys():
groups_not_used[group] = 1
# ... and remove the ones that *were* used.
for group in groups_used_list:
del groups_not_used[group]
# Print a remark showing groups not used
list_groups_not_used = groups_not_used.keys()
list_groups_not_used.sort()
for group in list_groups_not_used:
print "/* Group not used: %s = %s */" % (group, groups[group])
print "\n"
# Print the groups table
print "/* Group strings. */"
print "static const char *ncp_groups[] = {"
for group in groups_used_list:
print '\t/* %02d (%s) */ "%s",' % (groups_used_hash[group], group, groups[group])
print "};\n"
# Print the group macros
for group in groups_used_list:
name = string.upper(group)
print "#define NCP_GROUP_%s\t%d" % (name, groups_used_hash[group])
print "\n"
# Print PTVC's for bitfields
ett_list = []
print "/* PTVC records for bit-fields. */"
for var in variables_used_hash.keys():
if isinstance(var, bitfield):
sub_vars_ptvc = var.SubVariablesPTVC()
print "/* %s */" % (sub_vars_ptvc.Name())
print sub_vars_ptvc
ett_list.append(sub_vars_ptvc.ETTName())
# Print PTVC's not already printed for bitfields
print "/* PTVC records. These are re-used to save space. */"
for ptvc in ptvc_lists.Members():
if not ptvc.Null() and not ptvc.Empty():
print ptvc
# Print error_equivalency tables
print "/* Error-Equivalency Tables. These are re-used to save space. */"
for compcodes in compcode_lists.Members():
errors = compcodes.Records()
# Make sure the record for error = 0x00 comes last.
print "static const error_equivalency %s[] = {" % (compcodes.Name())
for error in errors:
error_in_packet = error >> 8;
ncp_error_index = errors_used_hash[error]
print "\t{ 0x%02x, %d }, /* 0x%04x */" % (error_in_packet,
ncp_error_index, error)
print "\t{ 0x00, -1 }\n};\n"
# Functions without length parameter
funcs_without_length = {}
# Print ncp_record packet records
print "#define SUBFUNC_WITH_LENGTH 0x02"
print "#define SUBFUNC_NO_LENGTH 0x01"
print "#define NO_SUBFUNC 0x00"
print "/* ncp_record structs for packets */"
print "static const ncp_record ncp_packets[] = {"
for pkt in packets.Members():
if pkt.HasSubFunction():
func = pkt.FunctionCode('high')
if pkt.HasLength():
subfunc_string = "SUBFUNC_WITH_LENGTH"
# Ensure that the function either has a length param or not
if funcs_without_length.has_key(func):
sys.exit("Function 0x%04x sometimes has length param, sometimes not." \
% (pkt.FunctionCode(),))
else:
subfunc_string = "SUBFUNC_NO_LENGTH"
funcs_without_length[func] = 1
else:
subfunc_string = "NO_SUBFUNC"
print '\t{ 0x%02x, 0x%02x, %s, "%s",' % (pkt.FunctionCode('high'),
pkt.FunctionCode('low'), subfunc_string, pkt.Description()),
print '\t%d /* %s */,' % (groups_used_hash[pkt.Group()], pkt.Group())
ptvc = pkt.PTVCRequest()
if not ptvc.Null() and not ptvc.Empty():
ptvc_request = ptvc.Name()
else:
ptvc_request = 'NULL'
ptvc = pkt.PTVCReply()
if not ptvc.Null() and not ptvc.Empty():
ptvc_reply = ptvc.Name()
else:
ptvc_reply = 'NULL'
errors = pkt.CompletionCodes()
print '\t\t%s, NULL, %s, NULL,' % (ptvc_request, ptvc_reply)
print '\t\t%s },\n' % (errors.Name())
print '\t{ 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL }'
print "};\n"
print "/* ncp funcs that require a subfunc */"
print "static const guint8 ncp_func_requires_subfunc[] = {"
hi_seen = {}
for pkt in packets.Members():
if pkt.HasSubFunction():
hi_func = pkt.FunctionCode('high')
if not hi_seen.has_key(hi_func):
print "\t0x%02x," % (hi_func)
hi_seen[hi_func] = 1
print "\t0"
print "};\n"
print "/* ncp funcs that have no length parameter */"
print "static const guint8 ncp_func_has_no_length_parameter[] = {"
funcs = funcs_without_length.keys()
funcs.sort()
for func in funcs:
print "\t0x%02x," % (func,)
print "\t0"
print "};\n"
# proto_register_ncp2222()
print """
void
proto_register_ncp2222(void)
{
static hf_register_info hf[] = {
{ &hf_ncp_func,
{ "Function", "ncp.func", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
{ &hf_ncp_length,
{ "Packet Length", "ncp.length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_ncp_subfunc,
{ "SubFunction", "ncp.subfunc", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
{ &hf_ncp_completion_code,
{ "Completion Code", "ncp.completion_code", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
{ &hf_ncp_connection_status,
{ "Connection Status", "ncp.connection_status", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
"""
# Print the registration code for the hf variables
for var in variables_used_hash.keys():
print "\t{ &%s," % (var.HFName())
print "\t{ \"%s\", \"%s\", %s, %s, %s, 0x%x, \"\", HFILL }},\n" % \
(var.Description(), var.DFilter(),
var.EtherealFType(), var.Display(), var.ValuesName(),
var.Mask())
print """
};
"""
# ETT's ?
if ett_list:
print """
static gint *ett[] = {
"""
for ett in ett_list:
print "\t\t&%s," % (ett,)
print """
};
"""
print """
proto_register_field_array(proto_ncp, hf, array_length(hf));
"""
if ett_list:
print """
proto_register_subtree_array(ett, array_length(ett));
"""
print "}\n"
print '#include "packet-ncp2222.inc"'
def main():
global packets
global compcode_lists
global ptvc_lists
packets = UniqueCollection('NCP Packet Descriptions')
compcode_lists = UniqueCollection('Completion Code Lists')
define_errors()
define_groups()
define_ncp2222()
produce_code()
def define_ncp2222():
##############################################################################
# NCP Packets. Here I list functions and subfunctions in hexadecimal like the
# NCP book (and I believe LanAlyzer does this too).
# However, Novell lists these in decimal in their on-line documentation.
##############################################################################
# 2222/02
pkt = NCP(0x02, "File Release Lock", 'sync')
pkt.Request(7)
pkt.Reply(8)
pkt.CompletionCodes([0x0000, 0xff00])
#
# Untested
#
# 2222/03
#pkt = NCP(0x03, "Log File", 'sync')
#pkt.request( (12, 267), [
# [ 7, 1, DirHandle ],
# [ 8, 1, LogLockType ],
# [ 9, 2, TimeoutLimit, LE ],
# [ 11, (1, 256), FilePath ],
# ])
#pkt.completion_codes([0x0000, 0x8200, 0x9600, 0xfe00, 0xff01])
#
## 2222/04
#pkt = NCP(0x04, "Lock File Set", 'sync')
#pkt.request([
# [ 7, TimeoutLimit ],
# ])
#pkt.completion_codes([0xfe, 0xff01])
#
## 2222/05
#pkt = NCP(0x05, "Release File", 'sync')
#pkt.request([
# [ 7, DirHandle ],
# [ 8, FilePath ],
# ])
#pkt.completion_codes([0x7e, 0x98, 0x9b, 0x9c, 0xff02])
#
## 2222/06
#pkt = NCP(0x06, "Release File Set", 'sync')
#pkt.request([
# [ 7, UnknownByte ],
# ])
#pkt.completion_codes()
#
## 2222/07
#pkt = NCP(0x07, "Clear File", 'sync')
#pkt.request([
# [ 7, DirHandle ],
# [ 8, FilePath ],
# ])
#pkt.completion_codes([0x7e, 0x96, 0x98, 0x9b, 0x9c,
# 0xa1, 0xfd, 0xff])
#
## 2222/08
#pkt = NCP(0x08, "Clear File Set", 'sync')
#pkt.request([
# [ 7, FileLock ],
# ])
#pkt.completion_codes([0x7e])
#
## 2222/09
#pkt = NCP(0x09, "Log Logical Record", 'sync')
#pkt.request([
# [ 7, LogicalLockType ],
# [ 8, TimeoutLimit_be ],
# [ 10, LogicalRecordName ],
# ])
#pkt.completion_codes([0x96, 0xfe, 0xff])
#
## 2222/0a
#pkt = NCP(0x0a, "Lock Logical Record Set", 'sync')
#pkt.request([
# [ 7, LogicalLockType ],
# [ 8, TimeoutLimit_le ],
# ])
#pkt.completion_codes([0xfe, 0xff])
#
## 2222/0b
#pkt = NCP(0x0b, "Clear Logical Record", 'sync')
#pkt.request([
# [7, LogicalRecordName ],
# ])
#pkt.completion_codes([0xff]
## 2222/0c
## 2222/0d
## 2222/0e
## 2222/0f
## 2222/11
#
## 2222/1100
#pkt = NCP(0x1100, "Lock Logical Record Set", 'sync')
#pkt.request([
# [ 10, var_length_data("data").length_var("packetlength") ]
# ])
#pkt.completion_codes()
#
# 2222/1711
pkt = NCP(0x1711, "Get File Server Information", 'fileserver')
pkt.Request(10)
pkt.Reply(136, [
[ 8, 48, ServerName ],
[ 56, 1, OSMajorVersion ],
[ 57, 1, OSMinorVersion ],
[ 58, 2, ConnectionsSupportedMax ],
[ 60, 2, ConnectionsInUse ],
[ 62, 2, VolumesSupportedMax ],
[ 64, 1, OSRevision ],
[ 65, 1, SFTLevel ],
[ 66, 1, TTSLevel ],
[ 67, 2, ConnectionsMaxUsed ],
[ 69, 1, AcctVersion ],
[ 70, 1, VAPVersion ],
[ 71, 1, QMSVersion ],
[ 72, 1, PrintServerVersion ],
[ 73, 1, VirtualConsoleVersion ],
[ 74, 1, SecurityRestrictionVersion ],
[ 75, 1, InternetBridgeVersion ],
[ 76, 1, MixedModePathFlag ],
[ 77, 1, LocalLoginInfoCcode ],
[ 78, 2, ProductMajorVersion ],
[ 80, 2, ProductMinorVersion ],
[ 82, 2, ProductRevisionVersion ],
[ 84, 1, OSLanguageID ],
[ 85, 51, Reserved51 ],
])
pkt.CompletionCodes([0x0000, 0x9600])
# 2222/1735
pkt = NCP(0x1735, "Get Bindery Object ID", 'bindery')
pkt.Request((13,60), [
[ 10, 2, ObjectType ],
[ 12, (1,48), ObjectName ],
])
pkt.Reply(62, [
[ 8, 4, ObjectID ],
[ 12, 2, ObjectType ],
[ 14, 48, ObjectName1 ],
])
pkt.CompletionCodes([0x0000, 0x9600, 0xef01, 0xf000, 0xfc02,
0xfe01, 0xff00])
# 2222/1737
pkt = NCP(0x1737, "Scan Bindery Object", 'bindery')
pkt.Request((17,64), [
[ 10, 4, ObjectID ],
[ 14, 2, ObjectType ],
[ 16, (1,48), ObjectName ],
])
pkt.Reply(65, [
[ 8, 4, ObjectID ],
[ 12, 2, ObjectType ],
[ 14, 48, ObjectName1 ],
[ 62, 1, ObjectFlags ],
[ 63, 1, ObjectSecurity ],
[ 64, 1, ObjectHasProperties ],
])
pkt.CompletionCodes([0x0000, 0x9600, 0xef01, 0xfc02,
0xfe01, 0xff00])
# 2222/173D
pkt = NCP(0x173D, "Read Property Value", 'bindery')
pkt.Request((15,77), [
[ 10, 2, ObjectType ],
[ 12, (1,48), ObjectName ],
[ -1, 1, PropertySegment ],
[ -1, (1,16), PropertyName ],
])
pkt.Reply(138, [
[ 8, 128, PropertyData ],
[ 136, 1, PropertyHasMoreSegments ],
[ 137, 1, PropertyType ],
])
pkt.CompletionCodes([0x0000, 0x8800, 0x9300, 0x9600, 0xec01,
0xf000, 0xf100, 0xf900, 0xfb02, 0xfc02, 0xfe01, 0xff00 ])
# 2222/177C
pkt = NCP(0x177C, "Service Queue Job", 'queue')
pkt.Request(16, [
[ 10, 4, ObjectID ],
[ 14, 2, JobType ],
])
pkt.Reply(24, [ # XXX - 76, [
[ 8, 4, ConnectionNumber ],
[ 12, 4, TaskNumber ],
[ 16, 4, ObjectID ],
[ 20, 4, ObjectID ],
# XXX - DateTime
])
# These completion codes are not documented, but guessed.
pkt.CompletionCodes([0x0000, 0x9900, 0xd000, 0xd100, 0xd201, 0xd300,
0xd401, 0xd502, 0xd601, 0xd704, 0xd800, 0xd901, 0xda01, 0xdb01,
0xff00 ])
# 2222/18
pkt = NCP(0x18, "End of Job", 'connection')
pkt.Request(7)
pkt.Reply(8)
pkt.CompletionCodes([0x0000])
# 2222/19
pkt = NCP(0x19, "Logout", 'connection')
pkt.Request(7)
pkt.Reply(8)
pkt.CompletionCodes([0x0000])
# 2222/21
pkt = NCP(0x21, "Negotiate Buffer Size", 'connection')
pkt.Request(9, [
[ 7, 2, BufferSize ],
])
pkt.Reply(10, [
[ 8, 2, BufferSize ],
])
pkt.CompletionCodes([0x0000])
# 2222/42
pkt = NCP(0x42, "Close File", 'file')
pkt.Request(13, [
[ 7, 6, FileHandle ],
])
pkt.Reply(8)
pkt.CompletionCodes([0x0000, 0xff00])
# 2222/47
pkt = NCP(0x47, "Get Current Size of File", 'file')
pkt.Request(13, [
[ 7, 6, FileHandle ],
])
pkt.Reply(12, [
[ 8, 4, FileSize ],
])
pkt.CompletionCodes([0x0000, 0x8800])
# 2222/48
pkt = NCP(0x48, "Read From A File", 'file')
pkt.Request(20, [
[ 7, 1, UnknownByte ],
[ 8, 6, FileHandle ],
[ 14, 4, FileOffset ], # my nomenclature
[ 18, 2, MaxBytes ], # my nomenclature
])
pkt.Reply(10, [ # XXX - (10,-1), [
[ 8, 2, NumBytes ], # my nomenclature
# XXX
])
pkt.CompletionCodes([0x0000, 0x8800, 0x9300, 0xff00])
# 2222/5701 - no info
# 2222/5702 - no info
# 2222/5706 - no info
# 2222/5714 - no info
# 2222/72 - no info
# 2222/61
pkt = NCP(0x61, "Get Big Packet NCP Max Packet Size", 'unknown')
pkt.Request(10, [
[ 7, 2, ProposedMaxSize ],
[ 9, 1, SecurityFlag ],
])
pkt.Reply(13, [
[ 8, 2, AcceptedMaxSize ],
[ 10, 2, EchoSocket ],
[ 12, 1, SecurityFlag ],
])
pkt.CompletionCodes([0x0000])
# 2222/6801
pkt = NCP(0x6801, "Ping for NDS NCP", "nds", has_length=0)
pkt.Request(11, [
[ 8, 3, Reserved3 ]
])
# XXX - expand, Unicode
pkt.Reply(10, [
[ 8, 2, PingVersion ],
])
pkt.CompletionCodes([0x0000, 0xfb04, 0xfe0c])
if __name__ == '__main__':
main()