Ethereal-dev: [ethereal-dev] Snapshot of new NCP dissector
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Gilbert Ramirez <gram@xxxxxxxxxx>
Date: Thu, 13 Jul 2000 23:54:13 -0500
In my hiatus from tvbuffifying the dissectors, I've dusted off my work on the re-write of the NetWare Core Protocol dissector. I thought I'd share it with ethereal-dev, as it's quickly shaping up to be very usable. In the Python program, I define classes for different NCP field types (which will become dfilterable fields). Then for each request/reply packet, I define its contents. I also have to declare which error messages are used for each packet. Unfortunately, an error code has multiple meanings depending on which type of NCP packet it's in. The program then collates all this info and creates C code. It will produce two different types of code, depending on the complexity of the dissection for the particular NCP packet. For fixed length packets, a simple table of fields is created. For variable length packets, a series of proto_tree_add_item() calls will be created. This latter code is not written into the Python program. I will also optimize the C code; lots of the tables will be the same, so I'll save space by referring to the same table for each packet that needs it. Files: packet-ncp2222.c Sample generated code ncp2222.py The python program ncp2222.c Helper code #included in packet-ncp2222.c ptvcursor.h "proto_tree tvbuff cursor" ptvcursor.c "proto_tree tvbuff cursor" packet-ncp.c Modified dissector. packet-ncp-int.h Header internal to dissector The last 2 files are some convenience functions that I'm using to run multiple proto_tree_add_item() calls sequentially. The ptvcursor_t type keeps track of the tvbuff, the proto_tree, and the current offset in the tvbuff. Whenever ptvcursor_add() is called, the offset is automatically updated. Since I'm writing this in Python, the plan is for developers (i.e., those that build from CVS) to have python installed. Users who build from official releases won't need Python since the generated source will be included in the distribution. Are there any objections to Python? I could translate the program to Perl, but it's a whole lot easier to read in Python, and if it's easier to read, it's easier to maintain. --gilbert
/* * Generated automatically from /home/gram/prj/ethereal/src/ncp2222.py * Do not edit this file manually, as all changes will be lost. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include <glib.h> #include "packet.h" #include "conversation.h" #include "ptvcursor.h" #include "packet-ncp-int.h" static int hf_ncp_func = -1; static int hf_ncp_completion_code = -1; static int hf_ncp_connection_status = -1; static int hf_ncp_buffersize = -1; void proto_register_ncp2222(void) { static hf_register_info hf[] = { { &hf_ncp_func, { "Function", "ncp.func", FT_UINT8, BASE_HEX, NULL, 0x0, "" }}, { &hf_ncp_completion_code, { "Completion Code", "ncp.completion_code", FT_UINT8, BASE_HEX, NULL, 0x0, "" }}, { &hf_ncp_connection_status, { "Connection Status", "ncp.connection_status", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, { &hf_ncp_buffersize, { "Buffer Size", "ncp.buffersize", FT_UINT16, BASE_DEC, NULL, 0x0, "" }}, }; proto_register_field_array(proto_ncp, hf, array_length(hf)); } /* Error 0x0001 not used: Transaction tracking is available */ /* Error 0x0002 not used: Ok. The data has been written */ /* Error 0x0100 not used: One or more of the ConnectionNumbers in the send list are invalid */ /* Error 0x0101 not used: Invalid space limit */ /* Error 0x0102 not used: Insufficient disk space */ /* Error 0x0103 not used: Queue server cannot add jobs */ /* Error 0x0104 not used: Out of disk space */ /* Error 0x0105 not used: Semaphore overflow */ /* Error 0x0200 not used: One or more clients in the send list are not logged in */ /* Error 0x0201 not used: Queue server cannot attach */ /* Error 0x0300 not used: One or more clients in the send list are not accepting messages */ /* Error 0x0400 not used: Client already has message */ /* Error 0x0401 not used: Queue server cannot service job */ /* Error 0x7e00 not used: NCP failed boundary check */ /* Error 0x8000 not used: Lock fail */ /* Error 0x8100 not used: A file handle could not be allocated by the file server */ /* Error 0x8200 not used: Unauthorized to open the file */ /* Error 0x8300 not used: Unable to read/write the volume. Possible bad sector on the file server */ /* Error 0x8400 not used: Unauthorized to create the directory */ /* Error 0x8401 not used: Unauthorized to create the file */ /* Error 0x8500 not used: Unauthorized to delete the specified file */ /* Error 0x8501 not used: Unauthorized to overwrite an existing file in this directory */ /* Error 0x8700 not used: An unexpected character was encountered in the filename */ /* Error 0x8800 not used: Invalid file handle */ /* Error 0x8900 not used: Unauthorized to search this directory */ /* Error 0x8a00 not used: Unauthorized to delete this directory */ /* Error 0x8b00 not used: Unauthorized to rename a file in this directory */ /* Error 0x8c00 not used: No set privileges */ /* Error 0x8c01 not used: Unauthorized to modify a file in this directory */ /* Error 0x8c02 not used: Unauthorized to change the restriction on this volume */ /* Error 0x8d00 not used: Some of the affected files are in use by another client */ /* Error 0x8d01 not used: The affected file is in use */ /* Error 0x8e00 not used: All of the affected files are in use by another client */ /* Error 0x8f00 not used: Some of the affected files are read-only */ /* Error 0x9000 not used: An attempt to modify a read-only volume occurred */ /* Error 0x9001 not used: All of the affected files are read-only */ /* Error 0x9100 not used: Some of the affected files already exist */ /* Error 0x9200 not used: Directory with the new name already exists */ /* Error 0x9201 not used: All of the affected files already exist */ /* Error 0x9300 not used: Unauthorized to read from this file */ /* Error 0x9400 not used: Unauthorized to write to this file */ /* Error 0x9500 not used: The affected file is detached */ /* Error 0x9600 not used: The file server has run out of memory to service this request */ /* Error 0x9601 not used: No alloc space for message */ /* Error 0x9800 not used: The affected volume is not mounted */ /* Error 0x9801 not used: The volume associated with VolumeNumber is not mounted */ /* Error 0x9802 not used: The resulting voume does not exist */ /* Error 0x9803 not used: The destination volume is not mounted */ /* Error 0x9900 not used: The file server has run out of directory space on the affected volume */ /* Error 0x9a00 not used: The request attempted to rename the affected file to another volume */ /* Error 0x9b00 not used: DirHandle is not associated with a valid directory path */ /* Error 0x9b01 not used: A resulting directory handle is not associated with a valid directory path */ /* Error 0x9b02 not used: The directory associated with DirHandle does not exist */ /* Error 0x9b03 not used: Bad directory handle */ /* Error 0x9c00 not used: The resulting path is not valid */ /* Error 0x9c01 not used: The resulting file path is not valid */ /* Error 0x9c02 not used: The resulting directory path is not valid */ /* Error 0x9c03 not used: Invalid path */ /* Error 0x9d00 not used: A directory handle was not available for allocation */ /* Error 0x9e00 not used: The name of the directory does not conform to a legal name for this name space */ /* Error 0x9e01 not used: The new directory name does not conform to a legal name for this name space */ /* Error 0x9f00 not used: The request attempted to delete a directory that is in use by another client */ /* Error 0xa000 not used: The request attempted to delete a directory that is not empty */ /* Error 0xa100 not used: An unrecoverable error occured on the affected directory */ /* Error 0xa200 not used: The request attempted to read from a file region that is physically locked */ /* Error 0xa400 not used: Invalid directory rename attempted */ /* Error 0xbf00 not used: Requests for this name space are not valid on this volume */ /* Error 0xc000 not used: Unauthorized to retrieve accounting data */ /* Error 0xc100 not used: The ACCOUNT_BALANCE property does not exist */ /* Error 0xc200 not used: The object has exceeded its credit limit */ /* Error 0xc300 not used: Too many holds have been placed against this account */ /* Error 0xc400 not used: The client account has been disabled */ /* Error 0xc500 not used: Access to the account has been denied because of intruder detection */ /* Error 0xc501 not used: Login lockout */ /* Error 0xc600 not used: The caller does not have operator priviliges */ /* Error 0xc601 not used: The client does not have operator priviliges */ /* Error 0xd000 not used: Queue error */ /* Error 0xd100 not used: The queue does not exist */ /* Error 0xd200 not used: A queue server is not associated with this queue */ /* Error 0xd201 not used: A queue server is not associated with the selected queue */ /* Error 0xd202 not used: No queue server */ /* Error 0xd300 not used: No queue rights */ /* Error 0xd400 not used: The queue is full and cannot accept another request */ /* Error 0xd401 not used: The queue associated with ObjectId is full and cannot accept another request */ /* Error 0xd500 not used: A job does not exist in this queue */ /* Error 0xd501 not used: No queue job */ /* Error 0xd502 not used: The job associated with JobNumber does not exist in this queue */ /* Error 0xd600 not used: The file server does not allow unencrypted passwords */ /* Error 0xd601 not used: No job right */ /* Error 0xd700 not used: Bad account */ /* Error 0xd701 not used: The old and new password strings are identical */ /* Error 0xd702 not used: The job is currently being serviced */ /* Error 0xd703 not used: The queue is currently servicing a job */ /* Error 0xd704 not used: Queue servicing */ /* Error 0xd800 not used: Queue not active */ /* Error 0xd900 not used: The file server cannot accept another connection as it has reached its limit */ /* Error 0xd901 not used: The client is not security equivalent to one of the objects in the Q_SERVERS group property of the target queue */ /* Error 0xd902 not used: Station is not a server */ /* Error 0xda00 not used: Attempted to login to the file server during a restricted time period */ /* Error 0xda01 not used: Queue halted */ /* Error 0xdb00 not used: Attempted to login to the file server from an unauthorized workstation or network */ /* Error 0xdb01 not used: The queue cannot attach another queue server */ /* Error 0xdb02 not used: Maximum queue servers */ /* Error 0xde00 not used: Attempted to login to the file server with an incorrect password */ /* Error 0xdf00 not used: Attempted to login to the file server with a password that has expired */ /* Error 0xe700 not used: No disk track */ /* Error 0xe800 not used: Write to group */ /* Error 0xe900 not used: The object is already a member of the group property */ /* Error 0xea00 not used: No such member */ /* Error 0xea01 not used: The bindery object is not a member of the set */ /* Error 0xea02 not used: Non-existent member */ /* Error 0xeb00 not used: The property is not a set property */ /* Error 0xec00 not used: No such set */ /* Error 0xec01 not used: The set property does not exist */ /* Error 0xed00 not used: Property exists */ /* Error 0xed01 not used: The property already exists */ /* Error 0xed02 not used: An attempt was made to create a bindery object property that already exists */ /* Error 0xee00 not used: The object already exists */ /* Error 0xee01 not used: The bindery object already exists */ /* Error 0xef00 not used: Illegal name */ /* Error 0xef01 not used: Illegal characters in ObjectName field */ /* Error 0xef02 not used: Invalid name */ /* Error 0xf000 not used: A wildcard was detected in a field that does not support wildcards */ /* Error 0xf001 not used: An illegal wildcard was detected in ObjectName */ /* Error 0xf100 not used: The client does not have the rights to access this bindery object */ /* Error 0xf101 not used: Bindery security */ /* Error 0xf102 not used: Invalid bindery security */ /* Error 0xf200 not used: Unauthorized to read from this object */ /* Error 0xf300 not used: Unauthorized to rename this object */ /* Error 0xf400 not used: Unauthorized to delete this object */ /* Error 0xf401 not used: No object delete privileges */ /* Error 0xf402 not used: Unauthorized to delete this queue */ /* Error 0xf500 not used: Unauthorized to create this object */ /* Error 0xf501 not used: No object create */ /* Error 0xf600 not used: No property delete */ /* Error 0xf601 not used: Unauthorized to delete the property of this object */ /* Error 0xf602 not used: Unauthorized to delete this property */ /* Error 0xf700 not used: Unauthorized to create this property */ /* Error 0xf701 not used: No property create privilege */ /* Error 0xf800 not used: Unauthorized to write to this property */ /* Error 0xf900 not used: Unauthorized to read this property */ /* Error 0xfa00 not used: Temporary remap error */ /* Error 0xfb00 not used: No such property */ /* Error 0xfb01 not used: The file server does not support this request */ /* Error 0xfb02 not used: The specified property does not exist */ /* Error 0xfb03 not used: The PASSWORD property does not exist for this bindery object */ /* Error 0xfc00 not used: The message queue cannot accept another message */ /* Error 0xfc01 not used: The trustee associated with ObjectId does not exist */ /* Error 0xfc02 not used: The specified bindery object does not exist */ /* Error 0xfc03 not used: The bindery object associated with ObjectID does not exist */ /* Error 0xfc04 not used: A bindery object does not exist that matches */ /* Error 0xfc05 not used: The specified queue does not exist */ /* Error 0xfc06 not used: No such object */ /* Error 0xfc07 not used: The queue associated with ObjectID does not exist */ /* Error 0xfd00 not used: Bad station number */ /* Error 0xfd01 not used: The connection associated with ConnectionNumber is not active */ /* Error 0xfd02 not used: Lock collision */ /* Error 0xfd03 not used: Transacktion tracking is disabled */ /* Error 0xfe00 not used: I/O failure */ /* Error 0xfe01 not used: The files containing the bindery on the file server are locked */ /* Error 0xfe02 not used: A file with the specified name already exists in this directory */ /* Error 0xfe03 not used: No more restrictions were found */ /* Error 0xfe04 not used: The file server was unable to lock the file within the specified time limit */ /* Error 0xfe05 not used: The file server was unable to lock all files within the specified time limit */ /* Error 0xfe06 not used: The bindery object associated with ObjectID is not a valid trustee */ /* Error 0xfe07 not used: Directory locked */ /* Error 0xfe08 not used: Bindery locked */ /* Error 0xfe09 not used: Invalid semaphore name length */ /* Error 0xfe0a not used: The file server was unable to complete the operation within the specified time limit */ /* Error 0xfe0b not used: Transaction restart */ /* Error 0xff01 not used: Lock error */ /* Error 0xff02 not used: File not found */ /* Error 0xff03 not used: The file not found or cannot be unlocked */ /* Error 0xff04 not used: Record not found */ /* Error 0xff05 not used: The logical record was not found */ /* Error 0xff06 not used: The printer associated with PrinterNumber does not exist */ /* Error 0xff07 not used: No such printer */ /* Error 0xff08 not used: Unable to complete the request */ /* Error 0xff09 not used: Unauthorized to change privileges of this trustee */ /* Error 0xff0a not used: No files matching the search criteria were found */ /* Error 0xff0b not used: A file matching the search criteria was not found */ /* Error 0xff0c not used: Verification failed */ /* Error 0xff0d not used: Object associated with ObjectID is not a manager */ /* Error 0xff0e not used: Invalid initial semaphore value */ /* Error 0xff0f not used: The semaphore handle is not valid */ /* Error 0xff10 not used: SemaphoreHandle is not associated with a valid sempahore */ /* Error 0xff11 not used: Invalid semaphore handle */ /* Error 0xff12 not used: Transaction tracking is not available */ /* Error 0xff13 not used: The transaction has not yet been written to disk */ /* Error 0xff14 not used: Directory already exists */ /* Error 0xff15 not used: The file already exists and the deletion flag was not set */ /* Error 0xff16 not used: No matching files or directories were found */ /* Error 0xff17 not used: A file or directory matching the search criteria was not found */ /* Error 0xff18 not used: The file already exists */ /* Error 0xff19 not used: No files found */ /* Error strings. */ static const char *ncp_errors[] = { /* 00 (0x0000) */ "Ok", /* 01 (0xff00) */ "Failure", }; /* Group not used: accounting = Accounting */ /* Group not used: afp = AFP */ /* Group not used: auditing = Auditing */ /* Group not used: bindery = Bindery */ /* Group not used: directory = Directory */ /* Group not used: extended = Extended Attribute */ /* Group not used: file = File */ /* Group not used: fileserver = File Server */ /* Group not used: message = Message */ /* Group not used: migration = Data Migration */ /* Group not used: misc = Miscellaneous */ /* Group not used: name = Name Space */ /* Group not used: nds = NetWare Directory */ /* Group not used: print = Print */ /* Group not used: queue = Queue */ /* Group not used: tss = Transaction Tracking */ /* Group strings. */ static const char *ncp_groups[] = { /* 00 (sync) */ "Synchronization", /* 01 (connection) */ "Connection", }; /* PTVC records */ static const ptvc_record ncp_0x21_request[] = { { &hf_ncp_buffersize, 2, FALSE }, { NULL, 0, 0 } }; static const ptvc_record ncp_0x21_reply[] = { { &hf_ncp_buffersize, 2, FALSE }, { NULL, 0, 0 } }; /* error equivalency tables */ static const error_equivalency ncp_0x2_errors[] = { { 0x00, 0 }, /* 0x0000 */ { 0xff, 1 }, /* 0xff00 */ { 0x00, -1 } }; static const error_equivalency ncp_0x21_errors[] = { { 0x00, 0 }, /* 0x0000 */ { 0x00, -1 } }; #define SUBFUNC 0xff #define NOSUB 0x00 /* ncp_record structs for packets */ static const ncp_record ncp_packets[] = { { 0x02, 0x00, NOSUB, "File Release Lock", 0 /* sync */, NULL, NULL, NULL, NULL, ncp_0x2_errors }, { 0x21, 0x00, NOSUB, "Negotiate Buffer Size", 1 /* connection */, ncp_0x21_request, NULL, ncp_0x21_reply, NULL, ncp_0x21_errors }, { 0, 0, 0, NULL } }; /* ncp funcs that require a subfunc */ static const guint8 ncp_func_requires_subfunc[] = { 0 }; #include "ncp2222.c"
#!/usr/bin/python # # ncp.py # # 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. # # Copyright (c) 2000 by Gilbert Ramirez <gram@xxxxxxxxxx> # # $Id$ import sys ############################################################################## # Global containers ############################################################################## packets = {} ############################################################################## # Classes for NCP field types ############################################################################## LE = 1 BE = 0 class Type: type = "Type" ft = None disp = 'BASE_DEC' def __init__(self, abbrev, descr, bytes): 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 hf_name(self): return "hf_ncp_" + self.abbrev def dfilter(self): return "ncp." + self.abbrev def ftype(self): return self.ft def display(self, newval=None): if newval != None: self.disp = newval return self.disp def values(self): return 'NULL' def mask(self): return 0 class byte(Type): type = "byte" ft = 'FT_UINT8' def __init__(self, abbrev, descr): Type.__init__(self, abbrev, descr, 1) class uint16(Type): type = "uint16" ft = 'FT_UINT16' def __init__(self, abbrev, descr): Type.__init__(self, abbrev, descr, 2) # 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. class nstring(Type): type = "nstring" ft = 'FT_STRING' def __init__(self, abbrev, descr): Type.__init__(self, abbrev, descr, -1) # Abstract class for val_stringN, where N is number # of bits that key takes up class val_string(Type): type = "val_string" def set_vals(self, val_string_array): self.values = val_string_array class val_string8(val_string): type = "val_string8" ft = 'FT_UINT8' def __init__(self, abbrev, descr): val_string.__init__(self, abbrev, descr, 1) class data(Type): type = "data" ft = '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 Fields (using instantiations of field types) ############################################################################## UnknownByte = byte("unknownbyte", "Unknown Byte") DirHandle = byte("dirhandle", "Directory Handle") LogLockType = byte("loglocktype", "Log Lock Type") TimeoutLimit = uint16("timeout", "Timeout Limit") BufferSize = uint16("buffersize", "Buffer Size") FilePath = nstring("filepath", "File Path") FileLock = val_string8("filelock", "File Lock") FileLock.set_vals([ [ 0x00, "Not Locked" ], [ 0xfe, "Locked by file lock" ], [ 0xff, "Unknown" ], ]) LogicalLockType = val_string8("logicallocktype", "Logical Lock Type") LogicalLockType.set_vals([ [ 0x00, "Log file" ], [ 0x01, "Log and lock file for exclusive read/write use" ], [ 0x03, "Log and lock with shareable read-only use" ], ]) LogicalRecordName = nstring("logicalrecordname", "Logical Record Name") ############################################################################## # Packet structure classes ############################################################################## class NCP: def __init__(self, NCPFunctionCode, description, group): self.NCPFunctionCode = NCPFunctionCode self.description = description self.group = group self.codes = None self.request_records = None self.reply_records = None if not groups.has_key(group): print "NCP 0x%x has invalid group '%s'" % (self.NCPFunctionCode, group) sys.exit() if self.subfunc(): # NCP Function with SubFunction self.start_offset = 10 else: # Simple NCP Function self.start_offset = 7 def function_code(self, part=None): if part == None: return self.NCPFunctionCode elif part == 'high': if self.subfunc(): return (self.NCPFunctionCode & 0xff00) / 256 else: return self.NCPFunctionCode elif part == 'low': if self.subfunc(): return self.NCPFunctionCode & 0x00ff else: return 0x00 else: print "Unknown directive '%s' for function_code()" % (part) sys.exit() def subfunc(self): if self.NCPFunctionCode <= 0xff: return 0 else: return 1 def get_description(self): return self.description def get_group(self): return self.group def request(self, size, records=[]): self.request_size = size self.request_records = records def reply(self, size, records=[]): self.reply_size = size self.reply_records = records def c_name(self): return "ncp_0x%x" % (self.NCPFunctionCode) def variables(self): variables = {} if self.request_records: for record in self.request_records: var = record[2] variables[var] = 1 if self.reply_records: for record in self.reply_records: var = record[2] variables[var] = 1 return variables.keys() def completion_codes(self, codes=None): if codes == None: return self.codes # Sanity check okay = 1 for code in codes: if not errors.has_key(code): print "Errors table does not have key 0x%04x for NCP=0x%x" % (code, self.NCPFunctionCode) okay = 0 if not okay: sys.exit() self.codes = codes # Add packet to global collection of packets if packets.has_key(self.NCPFunctionCode): print "Already have NCP Function Code 0x%x" % \ (self.NCPFunctionCode) sys.exit() else: packets[self.NCPFunctionCode] = self # Create PTVC's self.ptvc_request = PTVC(self.c_name() + "_request", self.request_records) self.ptvc_reply = PTVC(self.c_name() + "_reply", self.reply_records) class PTVC: def __init__(self, name, records): self.ptvc_list = [] self.ptvc_name = name for record in records: length = record[1] var = record[2] try: endianness = record[3] except IndexError: endianness = BE # We can't make a PTVC list from a variable-length # packet. if type(length) == type(()): self.ptvc_list = None return self.ptvc_list.append( [var, length, endianness] ) def null(self): if self.ptvc_list == None: return 1 else: return 0 def name(self): return self.ptvc_name def records(self): return self.ptvc_list def empty(self): if self.ptvc_list: return 0 else: return 1 ##################################################### ##################################################### ##################################################### ###################### DATA ######################### ##################################################### ##################################################### ##################################################### ############################################################################## # NCP Groups ############################################################################## 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" ############################################################################## # NCP Errors ############################################################################## 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[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[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" ############################################################################## # NCP Packets ############################################################################## # 2222/02 pkt = NCP(0x02, "File Release Lock", 'sync') pkt.request(7) pkt.reply(8) pkt.completion_codes([0x0000, 0xff00]) # 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/21 pkt = NCP(0x21, "Negotiate Buffer Size", 'connection') pkt.request( 9, [ [ 7, 2, BufferSize ], ]) pkt.reply( 10, [ [ 8, 2, BufferSize ], ]) pkt.completion_codes([0x0000]) ## 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() # ############################################################################## # Produce C code ############################################################################## 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 """ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include <glib.h> #include "packet.h" #include "conversation.h" #include "ptvcursor.h" #include "packet-ncp-int.h" static int hf_ncp_func = -1; static int hf_ncp_completion_code = -1; static int hf_ncp_connection_status = -1; """ # Look at all packet types in the packets hash, and cull information # from them. packet_keys = packets.keys() packet_keys.sort() errors_used_list = [] errors_used_hash = {} groups_used_list = [] groups_used_hash = {} variables_used_hash = {} ptvc_list = [] for pkt in packets.values(): # Determine which error codes are used. codes = pkt.completion_codes() for code in codes: 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.get_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 # Record and determine PTVC's for ptvc in [ pkt.ptvc_request, pkt.ptvc_reply ]: if not ptvc.null(): ptvc_list.append(ptvc) # Print the hf variable declarations for var in variables_used_hash.keys(): print "static int " + var.hf_name() + " = -1;" print """ void proto_register_ncp2222(void) { static hf_register_info hf[] = { { &hf_ncp_func, { "Function", "ncp.func", FT_UINT8, BASE_HEX, NULL, 0x0, "" }}, { &hf_ncp_completion_code, { "Completion Code", "ncp.completion_code", FT_UINT8, BASE_HEX, NULL, 0x0, "" }}, { &hf_ncp_connection_status, { "Connection Status", "ncp.connection_status", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, """ # Print the registration code for the hf variables for var in variables_used_hash.keys(): print "\t{ &%s," % (var.hf_name()) print "\t{ \"%s\", \"%s\", %s, %s, %s, 0x%x, \"\" }},\n" % \ (var.description(), var.dfilter(), var.ftype(), var.display(), var.values(), var.mask()) print """\t}; proto_register_field_array(proto_ncp, hf, array_length(hf)); } """ # 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 PTVC's print "/* PTVC records */" for ptvc in ptvc_list: if not ptvc.empty(): print "static const ptvc_record %s[] = {" % (ptvc.name()) records = ptvc.records() for record in records: if record[2] == BE: endianness = 'FALSE' else: endianness = 'TRUE' print "\t{ &%s, %d, %s }," % (record[0].hf_name(), record[1], endianness) print "\t{ NULL, 0, 0 }" print "};\n" # Print error_equivalency tables print "/* error equivalency tables */" for packet_key in packet_keys: pkt = packets[packet_key] errors = pkt.completion_codes() # Make sure the record for error = 0x00 comes last. print "static const error_equivalency %s_errors[] = {" % (pkt.c_name()) for error in errors: error_in_packet = error / 256; 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" # Print ncp_record packet records print "#define SUBFUNC 0xff" print "#define NOSUB 0x00" print "/* ncp_record structs for packets */" print "static const ncp_record ncp_packets[] = {" for packet_key in packet_keys: pkt = packets[packet_key] if pkt.subfunc(): subfunc_string = "SUBFUNC" else: subfunc_string = "NOSUB" print '\t{ 0x%02x, 0x%02x, %s, "%s",' % (pkt.function_code('high'), pkt.function_code('low'), subfunc_string, pkt.get_description()), print '\t%d /* %s */,' % (groups_used_hash[pkt.group], pkt.group) ptvc = pkt.ptvc_request if not ptvc.null() and not ptvc.empty(): ptvc_request = ptvc.name() else: ptvc_request = 'NULL' ptvc = pkt.ptvc_reply if not ptvc.null() and not ptvc.empty(): ptvc_reply = ptvc.name() else: ptvc_reply = 'NULL' error_table = "%s_errors" % (pkt.c_name()) print '\t\t%s, NULL, %s, NULL,' % (ptvc_request, ptvc_reply) print '\t\t%s },\n' % (error_table) print '\t{ 0, 0, 0, NULL }' print "};\n" print "/* ncp funcs that require a subfunc */" print "static const guint8 ncp_func_requires_subfunc[] = {" for packet_key in packet_keys: pkt = packets[packet_key] if pkt.subfunc(): print "\t0x%02x," % (pkt.function_code('high')) print "\t0" print "};\n" print '#include "ncp2222.c"'
static gboolean ncp_requires_subfunc(guint8 func) { const guint8 *ncp_func_requirement = ncp_func_requires_subfunc; while (*ncp_func_requirement != 0) { if (*ncp_func_requirement == func) { return TRUE; } ncp_func_requirement++; } return FALSE; } static const ncp_record * ncp_record_find(guint8 func, guint8 subfunc) { const ncp_record *ncp_rec = ncp_packets; while(ncp_rec->func != 0 || ncp_rec->subfunc != 0 || ncp_rec->name != NULL ) { if (ncp_rec->func == func && ncp_rec->subfunc == (subfunc & ncp_rec->submask)) { return ncp_rec; } ncp_rec++; } return NULL; } static void process_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec) { while(rec->hf_ptr != NULL) { ptvcursor_add(ptvc, *rec->hf_ptr, rec->length, rec->endianness); rec++; } } static const char* ncp_error_string(error_equivalency *errors, guint8 completion_code) { while (errors->ncp_error_index != -1) { if (errors->error_in_packet == completion_code) { return ncp_errors[errors->ncp_error_index]; } } return "Unknown"; } void dissect_ncp2222_request(tvbuff_t *tvb, packet_info *pinfo, guint16 nw_connection, guint8 sequence, guint16 type, proto_tree *ncp_tree, proto_tree *tree) { guint8 func, subfunc = 0; gboolean requires_subfunc; const ncp_record *ncp_rec; conversation_t *conversation; ptvcursor_t *ptvc = NULL; func = tvb_get_guint8(tvb, 6); requires_subfunc = ncp_requires_subfunc(func); if (requires_subfunc) { subfunc = tvb_get_guint8(tvb, 9); } ncp_rec = ncp_record_find(func, subfunc); if (check_col(pinfo->fd, COL_INFO)) { if (ncp_rec) { col_add_fstr(pinfo->fd, COL_INFO, "C %s", ncp_rec->name); } else { if (requires_subfunc) { col_add_fstr(pinfo->fd, COL_INFO, "C Unknown Function 0x%02X/0x%02x", func, subfunc); } else { col_add_fstr(pinfo->fd, COL_INFO, "C Unknown Function 0x%02x", func); } } } if (!pinfo->fd->flags.visited) { /* This is the first time we've looked at this packet. Keep track of the address and connection whence the request came, and the address and connection to which the request is being sent, so that we can match up calls with replies. (We don't include the sequence number, as we may want to have all packets over the same connection treated as being part of a single conversation so that we can let the user select that conversation to be displayed.) */ conversation = find_conversation(&pi.src, &pi.dst, PT_NCP, nw_connection, nw_connection); if (conversation == NULL) { /* It's not part of any conversation - create a new one. */ conversation = conversation_new(&pi.src, &pi.dst, PT_NCP, nw_connection, nw_connection, NULL); } ncp_hash_insert(conversation, sequence, 0x2222, ncp_rec); } if (ncp_tree) { if (requires_subfunc) { proto_tree_add_uint(ncp_tree, hf_ncp_func, tvb, 6, 1, func); ptvc = ptvcursor_new(ncp_tree, tvb, 9); } else { proto_tree_add_uint_format(ncp_tree, hf_ncp_func, tvb, 6, 1, func, "Function Code: 0x%02X (%s)", func, ncp_rec ? ncp_rec->name : "Unknown"); ptvc = ptvcursor_new(ncp_tree, tvb, 7); } if (ncp_rec && ncp_rec->request_ptvc) { process_ptvc_record(ptvc, ncp_rec->request_ptvc); } ptvcursor_free(ptvc); } } void dissect_ncp3333_reply(tvbuff_t *tvb, packet_info *pinfo, guint16 nw_connection, guint8 sequence, proto_tree *ncp_tree, proto_tree *tree) { conversation_t *conversation; const ncp_record *ncp_rec = NULL; guint16 ncp_type; gboolean found_request = FALSE; guint8 completion_code; guint length; ptvcursor_t *ptvc = NULL; const char *error_string; /* Find the conversation whence the request would have come. */ conversation = find_conversation(&pi.src, &pi.dst, PT_NCP, nw_connection, nw_connection); if (conversation != NULL) { /* find the record telling us the request made that caused this reply */ found_request = ncp_hash_lookup(conversation, sequence, &ncp_type, &ncp_rec); } /* else... we haven't seen an NCP Request for that conversation and sequence. */ /* A completion code of 0 always means OK. Non-zero means failure, * but each non-zero value has a different meaning. And the same value * can have different meanings, depending on the ncp.func (and ncp.subfunc) * value. */ completion_code = tvb_get_guint8(tvb, 6); if (ncp_rec && ncp_rec->errors) { error_string = ncp_error_string(ncp_rec->errors, completion_code); } else if (completion_code == 0) { error_string = "OK"; } else { error_string = "Not OK"; } if (check_col(pinfo->fd, COL_INFO)) { col_add_fstr(pinfo->fd, COL_INFO, "R %s", error_string); } if (ncp_tree) { proto_tree_add_uint_format(ncp_tree, hf_ncp_completion_code, tvb, 6, 1, completion_code, "Completion Code: 0x%02x (%s)", completion_code, error_string); proto_tree_add_item(ncp_tree, hf_ncp_connection_status, tvb, 7, 1, FALSE); length = tvb_length(tvb); if (!ncp_rec && length > 8) { proto_tree_add_text(ncp_tree, tvb, 8, length - 8, "No request record found. Parsing is impossible."); } else if (ncp_rec && ncp_rec->reply_ptvc) { ptvc = ptvcursor_new(ncp_tree, tvb, 8); process_ptvc_record(ptvc, ncp_rec->reply_ptvc); ptvcursor_free(ptvc); } } }
/* packet-ncp.c * Routines for NetWare Core Protocol * Gilbert Ramirez <gram@xxxxxxxxxx> * Modified to allow NCP over TCP/IP decodes by James Coe <jammer@xxxxxxx> * * $Id: packet-ncp.c,v 1.37 2000/05/31 05:07:22 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@xxxxxxxx> * Copyright 1998 Gerald Combs * * * 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 #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> #endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif #include <glib.h> #include "packet.h" #include "conversation.h" #include "prefs.h" #include "packet-ipx.h" #include "packet-ncp-int.h" int proto_ncp = -1; static int hf_ncp_ip_ver = -1; static int hf_ncp_ip_length = -1; static int hf_ncp_ip_rplybufsize = -1; static int hf_ncp_ip_sig = -1; static int hf_ncp_type = -1; static int hf_ncp_seq = -1; static int hf_ncp_connection = -1; static int hf_ncp_task = -1; static gint ett_ncp = -1; static gint ett_ncp_request_fields = -1; static gint ett_ncp_reply_fields = -1; #define TCP_PORT_NCP 524 #define UDP_PORT_NCP 524 #define NCP_RQST_HDR_LENGTH 7 #define NCP_RPLY_HDR_LENGTH 8 /* Hash functions */ gint ncp_equal (gconstpointer v, gconstpointer v2); guint ncp_hash (gconstpointer v); static guint ncp_packet_init_count = 200; /* These are the header structures to handle NCP over IP */ #define NCPIP_RQST 0x446d6454 /* "DmdT" */ #define NCPIP_RPLY 0x744e6350 /* "tNcP" */ struct ncp_ip_header { guint32 signature; guint32 length; }; /* This header only appears on NCP over IP request packets */ struct ncp_ip_rqhdr { guint32 version; guint32 rplybufsize; }; static const value_string ncp_ip_signature[] = { { NCPIP_RQST, "Demand Transport (Request)" }, { NCPIP_RPLY, "Transport is NCP (Reply)" }, }; /* The information in this module comes from: NetWare LAN Analysis, Second Edition Laura A. Chappell and Dan E. Hakes (c) 1994 Novell, Inc. Novell Press, San Jose. ISBN: 0-7821-1362-1 And from the ncpfs source code by Volker Lendecke And: Programmer's Guide to the NetWare Core Protocol Steve Conner & Diane Conner (c) 1996 by Steve Conner & Diane Conner Published by Annabooks, San Diego, California ISBN: 0-929392-31-0 */ /* Every NCP packet has this common header */ struct ncp_common_header { guint16 type; guint8 sequence; guint8 conn_low; guint8 task; guint8 conn_high; /* type=0x5555 doesn't have this */ }; static value_string ncp_type_vals[] = { { 0x1111, "Create a service connection" }, { 0x2222, "Service request" }, { 0x3333, "Service reply" }, { 0x5555, "Destroy service connection" }, { 0x7777, "Burst mode transfer" }, { 0x9999, "Request being processed" }, { 0x0000, NULL } }; /* NCP packets come in request/reply pairs. The request packets tell the type * of NCP request and give a sequence ID. The response, unfortunately, only * identifies itself via the sequence ID; you have to know what type of NCP * request the request packet contained in order to successfully parse the NCP * response. A global method for doing this does not exist in ethereal yet * (NFS also requires it), so for now the NCP section will keep its own hash * table keeping track of NCP packet types. * * We construct a conversation specified by the client and server * addresses and the connection number; the key representing the unique * NCP request then is composed of the pointer to the conversation * structure, cast to a "guint" (which may throw away the upper 32 * bits of the pointer on a P64 platform, but the low-order 32 bits * are more likely to differ between conversations than the upper 32 bits), * and the sequence number. * * The value stored in the hash table is the ncp_request_val pointer. This * struct tells us the NCP type and gives the ncp2222_record pointer, if * ncp_type == 0x2222. */ typedef struct { conversation_t *conversation; guint8 nw_sequence; } ncp_request_key; typedef struct { guint16 ncp_type; const ncp_record *ncp_record; } ncp_request_val; static GHashTable *ncp_request_hash = NULL; static GMemChunk *ncp_request_keys = NULL; static GMemChunk *ncp_request_records = NULL; /* Hash Functions */ gint ncp_equal (gconstpointer v, gconstpointer v2) { ncp_request_key *val1 = (ncp_request_key*)v; ncp_request_key *val2 = (ncp_request_key*)v2; if (val1->conversation == val2->conversation && val1->nw_sequence == val2->nw_sequence ) { return 1; } return 0; } guint ncp_hash (gconstpointer v) { ncp_request_key *ncp_key = (ncp_request_key*)v; return GPOINTER_TO_UINT(ncp_key->conversation) + ncp_key->nw_sequence; } /* Initializes the hash table and the mem_chunk area each time a new * file is loaded or re-loaded in ethereal */ static void ncp_init_protocol(void) { if (ncp_request_hash) g_hash_table_destroy(ncp_request_hash); if (ncp_request_keys) g_mem_chunk_destroy(ncp_request_keys); if (ncp_request_records) g_mem_chunk_destroy(ncp_request_records); ncp_request_hash = g_hash_table_new(ncp_hash, ncp_equal); ncp_request_keys = g_mem_chunk_new("ncp_request_keys", sizeof(ncp_request_key), ncp_packet_init_count * sizeof(ncp_request_key), G_ALLOC_AND_FREE); ncp_request_records = g_mem_chunk_new("ncp_request_records", sizeof(ncp_request_val), ncp_packet_init_count * sizeof(ncp_request_val), G_ALLOC_AND_FREE); } void ncp_hash_insert(conversation_t *conversation, guint8 nw_sequence, guint16 ncp_type, const ncp_record *ncp_rec) { ncp_request_val *request_val; ncp_request_key *request_key; /* Now remember the request, so we can find it if we later a reply to it. */ request_key = g_mem_chunk_alloc(ncp_request_keys); request_key->conversation = conversation; request_key->nw_sequence = nw_sequence; request_val = g_mem_chunk_alloc(ncp_request_records); request_val->ncp_type = ncp_type; request_val->ncp_record = ncp_rec; g_hash_table_insert(ncp_request_hash, request_key, request_val); } /* Returns TRUE or FALSE. If TRUE, the recordw as found and * ncp_type and ncp_rec are set. */ gboolean ncp_hash_lookup(conversation_t *conversation, guint8 nw_sequence, guint16 *ncp_type, const ncp_record **ncp_rec) { ncp_request_val *request_val; ncp_request_key request_key; request_key.conversation = conversation; request_key.nw_sequence = nw_sequence; request_val = (ncp_request_val*) g_hash_table_lookup(ncp_request_hash, &request_key); if (request_val) { *ncp_type = request_val->ncp_type; *ncp_rec = request_val->ncp_record; return TRUE; } else { return FALSE; } } #if 0 void dissect_ncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { #else void dissect_ncp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { packet_info *pinfo = π tvbuff_t *tvb = tvb_create_from_top(offset); #endif proto_tree *ncp_tree = NULL; proto_item *ti; struct ncp_ip_header ncpiph; struct ncp_ip_rqhdr ncpiphrq; struct ncp_common_header header; guint16 nw_connection; int hdr_offset = 0; int commhdr; pinfo->current_proto = "NCP"; if (check_col(pinfo->fd, COL_PROTOCOL)) col_add_str(pinfo->fd, COL_PROTOCOL, "NCP"); if ( pi.ptype == PT_TCP || pi.ptype == PT_UDP ) { ncpiph.signature = tvb_get_ntohl(tvb, 0); ncpiph.length = tvb_get_ntohl(tvb, 4); hdr_offset += 8; if ( ncpiph.signature == NCPIP_RQST ) { ncpiphrq.version = tvb_get_ntohl(tvb, hdr_offset); hdr_offset += 4; ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, hdr_offset); hdr_offset += 4; }; }; /* Record the offset where the NCP common header starts */ commhdr = hdr_offset; header.type = tvb_get_ntohs(tvb, commhdr); header.sequence = tvb_get_guint8(tvb, commhdr+2); header.conn_low = tvb_get_guint8(tvb, commhdr+3); header.conn_high = tvb_get_guint8(tvb, commhdr+5); nw_connection = (header.conn_high << 16) + header.conn_low; if (tree) { ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, tvb_length(tvb), FALSE); ncp_tree = proto_item_add_subtree(ti, ett_ncp); if ( pi.ptype == PT_TCP || pi.ptype == PT_UDP ) { proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, 0, 4, ncpiph.signature); proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, 4, 4, ncpiph.length); if ( ncpiph.signature == NCPIP_RQST ) { proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, 8, 4, ncpiphrq.version); proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, 12, 4, ncpiphrq.rplybufsize); }; }; proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr + 0, 2, header.type); proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence); proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection); proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE); } if (header.type == 0x2222) { dissect_ncp2222_request(tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree, tree); } else if (header.type == 0x3333) { dissect_ncp3333_reply(tvb, pinfo, nw_connection, header.sequence, ncp_tree, tree); } /* else if ( header.type == 0x1111 || header.type == 0x5555 || header.type == 0x7777 || header.type == 0x9999 ) { dissect_ncp_other(tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree, tree); } else { return; } */ } void proto_register_ncp(void) { static hf_register_info hf[] = { { &hf_ncp_ip_sig, { "NCP over IP signature", "ncp.ip.signature", FT_UINT32, BASE_HEX, VALS(ncp_ip_signature), 0x0, "" }}, { &hf_ncp_ip_length, { "NCP over IP length", "ncp.ip.length", FT_UINT32, BASE_HEX, NULL, 0x0, "" }}, { &hf_ncp_ip_ver, { "NCP over IP Version", "ncp.ip.version", FT_UINT32, BASE_DEC, NULL, 0x0, "" }}, { &hf_ncp_ip_rplybufsize, { "NCP over IP Reply Buffer Size", "ncp.ip.replybufsize", FT_UINT32, BASE_DEC, NULL, 0x0, "" }}, { &hf_ncp_type, { "Type", "ncp.type", FT_UINT16, BASE_HEX, VALS(ncp_type_vals), 0x0, "NCP message type" }}, { &hf_ncp_seq, { "Sequence Number", "ncp.seq", FT_UINT8, BASE_DEC, NULL, 0x0, "" }}, { &hf_ncp_connection, { "Connection Number", "ncp.connection", FT_UINT16, BASE_DEC, NULL, 0x0, "" }}, { &hf_ncp_task, { "Task Number", "ncp.task", FT_UINT8, BASE_DEC, NULL, 0x0, "" }} }; static gint *ett[] = { &ett_ncp, &ett_ncp_request_fields, &ett_ncp_reply_fields, }; module_t *ncp_module; proto_ncp = proto_register_protocol("NetWare Core Protocol", "ncp"); proto_register_field_array(proto_ncp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); register_init_routine(&ncp_init_protocol); /* Register a configuration option for initial size of NCP hash */ ncp_module = prefs_register_module("ncp", "NCP", NULL); prefs_register_uint_preference(ncp_module, "initial_hash_size", "Initial Hash Size", "Number of entries initially allocated for NCP hash", 10, &ncp_packet_init_count); } void proto_reg_handoff_ncp(void) { dissector_add("tcp.port", TCP_PORT_NCP, dissect_ncp); dissector_add("udp.port", UDP_PORT_NCP, dissect_ncp); dissector_add("ipx.packet_type", IPX_PACKET_TYPE_NCP, dissect_ncp); dissector_add("ipx.socket", IPX_SOCKET_NCP, dissect_ncp); }
/* packet-ncp-int.h * Structures and functions for NetWare Core Protocol. * Gilbert Ramirez <gram@xxxxxxxxxx> * * $Id$ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@xxxxxxxx> * Copyright 1998 Gerald Combs * * * 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. */ typedef struct { int *hf_ptr; gint length; gboolean endianness; } ptvc_record; typedef struct { guint8 error_in_packet; gint ncp_error_index; } error_equivalency; typedef struct { guint8 func; guint8 subfunc; guint8 submask; gchar* name; gint group; const ptvc_record *request_ptvc; void *requst_func; const ptvc_record *reply_ptvc; void *reply_func; error_equivalency *errors; } ncp_record; void dissect_ncp2222_request(tvbuff_t*, packet_info*, guint16, guint8, guint16, proto_tree*, proto_tree*); void dissect_ncp3333_reply(tvbuff_t *, packet_info*, guint16, guint8, proto_tree*, proto_tree*); void ncp_hash_insert(conversation_t *conversation, guint8 nw_sequence, guint16 ncp_type, const ncp_record *ncp_rec); /* Returns TRUE or FALSE. If TRUE, the recordw as found and * ncp_type and ncp_rec are set. */ gboolean ncp_hash_lookup(conversation_t*, guint8 nw_sequence, guint16 *ncp_type, const ncp_record **ncp_rec); extern int proto_ncp;
#ifdef HAVE_CONFIG_H # include "config.h" #endif #include <glib.h> #ifndef __PACKET_H__ #include "packet.h" #endif typedef struct ptvcursor ptvcursor_t; /* Allocates an initializes a ptvcursor_t with 3 variables: * proto_tree, tvbuff, and offset. */ ptvcursor_t* ptvcursor_new(proto_tree*, tvbuff_t*, gint); /* Gets data from tvbuff, adds it to proto_tree, increments offset, * and returns proto_item* */ proto_item* ptvcursor_add(ptvcursor_t*, int hf, gint length, gboolean endianness); /* Frees memory for ptvcursor_t, but nothing deeper than that. */ void ptvcursor_free(ptvcursor_t*);
#ifndef __PTVCURSOR_H__ #include "ptvcursor.h" #endif struct ptvcursor { proto_tree *tree; tvbuff_t *tvb; gint offset; }; /* Allocates an initializes a ptvcursor_t with 3 variables: * proto_tree, tvbuff, and offset. */ ptvcursor_t* ptvcursor_new(proto_tree *tree, tvbuff_t *tvb, gint offset) { ptvcursor_t *ptvc; ptvc = g_new(ptvcursor_t, 1); ptvc->tree = tree; ptvc->tvb = tvb; ptvc->offset = offset; return ptvc; } /* Gets data from tvbuff, adds it to proto_tree, increments offset, * and returns proto_item* */ proto_item* ptvcursor_add(ptvcursor_t *ptvc, int hf, gint length, gboolean endianness) { proto_item *item; item = proto_tree_add_item(ptvc->tree, hf, ptvc->tvb, ptvc->offset, length, endianness); ptvc->offset += length; return item; } /* Frees memory for ptvcursor_t, but nothing deeper than that. */ void ptvcursor_free(ptvcursor_t *ptvc) { g_free(ptvc); }
- Prev by Date: Re: [ethereal-dev] Diameter (using new prefs.c)
- Next by Date: [ethereal-dev] Re: [ethereal-users] Problem with inet_v6defs.h and Linux glibc 2.2
- Previous by thread: Re: Fw: [ethereal-dev] Using Ethereal to measure application performance
- Next by thread: [ethereal-dev] Re: [ethereal-users] Problem with inet_v6defs.h and Linux glibc 2.2
- Index(es):