* that all the data tables in packet-ncp2222.c can remain static.
*
* Gilbert Ramirez <gram@alumni.rice.edu>
+ * Modified to decode NDS packets by Greg Morris <gmorris@novell.com>
*
- * $Id: packet-ncp2222.inc,v 1.13 2002/05/16 09:59:52 guy Exp $
+ * $Id: packet-ncp2222.inc,v 1.18 2002/08/25 21:41:12 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
return fvalue_get_integer(PITEM_FINFO(item)->value);
}
-char*
+
+char *
+get_item_string(proto_item *item)
+{
+ return fvalue_get(PITEM_FINFO(item)->value);
+}
+
+char *
get_item_name(proto_item *item)
{
return PITEM_FINFO(item)->hfinfo->name;
guint second;
} nw_time_t;
+typedef struct {
+ char * buffer;
+} nw_uni_t;
+
+
/* Given an integer, fill in a nw_date_t struct. */
static void
uint_to_nwdate(guint data, nw_date_t *nwdate)
nwtime->hour = ((data & 0xf800) >> 11) + 1;
}
+static void
+unicode_to_string(char * data, nw_uni_t *nw_uni)
+{
+ guint32 i;
+ guint16 character;
+ int offset = 0;
+ guint32 length = 0;
+ char * buffer = "";
+
+ length = strlen(data);
+
+ if (data[1] == 0x00){
+
+ for (i = 0; i < length; i++) {
+ character = data[offset];
+ buffer[i] = character & 0xff;
+ offset += 2;
+ }
+ }
+ else
+ {
+ buffer = data;
+ }
+ nw_uni->buffer = buffer;
+}
static proto_item*
padd_normal(ptvcursor_t *ptvc, const ptvc_record *rec)
}
+/* Convert a string from little-endian unicode to ascii. At the moment we
+ fake it by taking every odd byte. )-: The caller must free the
+ result returned. */
+static proto_item*
+padd_uni(ptvcursor_t *ptvc, const ptvc_record *rec)
+{
+ proto_item *item;
+ nw_uni_t nw_uni;
+ guint offset;
+
+ offset = ptvcursor_current_offset(ptvc);
+
+ item = ptvcursor_add(ptvc, *rec->hf_ptr,
+ rec->length, rec->endianness);
+
+ unicode_to_string(get_item_string(item), &nw_uni);
+
+ proto_item_set_text(item, get_item_name(item));
+ proto_item_append_text(item, " %s",
+ nw_uni.buffer);
+
+ return item;
+}
/* Add a value for a ptvc_record, and process the sub-ptvc_record
* that it points to. */
case NCP_FMT_NW_TIME:
func = padd_time;
break;
+ case NCP_FMT_UNICODE:
+ func = padd_uni;
+ break;
default:
g_assert_not_reached();
}
case NCP_FMT_NW_TIME:
func = padd_time;
break;
+ case NCP_FMT_UNICODE:
+ func = padd_uni;
+ break;
default:
g_assert_not_reached();
}
errors++;
}
- return "Unknown";
+ return "Unknown Error Code";
}
static const ncp_record ncp1111_request =
{ 0x01, 0x00, NO_SUBFUNC, "Destroy Connection Service", NCP_GROUP_CONNECTION,
NULL, NULL, ncp_0x2_errors, NULL, NO_REQ_COND_SIZE, NULL };
+static const ncp_record ncpbbbb_request =
+ { 0x01, 0x00, NO_SUBFUNC, "Server Broadcast Message", NCP_GROUP_CONNECTION,
+ NULL, NULL, ncp_0x2_errors, NULL, NO_REQ_COND_SIZE, NULL };
+
/* Wrapper around proto_tree_free() */
void free_proto_tree(void *tree)
{
gboolean requires_subfunc;
gboolean has_length = TRUE;
ncp_req_hash_value *request_value = NULL;
- const ncp_record *ncp_rec = NULL;
+ const ncp_record *ncp_rec = NULL;
conversation_t *conversation;
ptvcursor_t *ptvc = NULL;
proto_tree *temp_tree = NULL;
case NCP_DEALLOCATE_SLOT:
ncp_rec = &ncp5555_request;
break;
+ case NCP_BROADCAST_SLOT:
+ ncp_rec = &ncpbbbb_request;
+ break;
default:
ncp_rec = NULL;
}
/* Fill in the INFO column. */
if (check_col(pinfo->cinfo, COL_INFO)) {
- if (ncp_rec) {
- col_add_fstr(pinfo->cinfo, COL_INFO, "C %s", ncp_rec->name);
- }
- else {
- if (requires_subfunc) {
- col_add_fstr(pinfo->cinfo, COL_INFO,
- "C Unknown Function %d %d (0x%02X/0x%02x)",
- func, subfunc, func, subfunc);
- }
- else {
- col_add_fstr(pinfo->cinfo, COL_INFO,
- "C Unknown Function %d (0x%02x)",
- func, func);
- }
- }
- }
+ if (ncp_rec) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "C %s", ncp_rec->name);
+ }
+ else {
+ if (requires_subfunc) {
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "C Unknown Function %d %d (0x%02X/0x%02x)",
+ func, subfunc, func, subfunc);
+ }
+ else {
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "C Unknown Function %d (0x%02x)",
+ func, func);
+ }
+ }
+ }
if (!pinfo->fd->flags.visited) {
/* This is the first time we've looked at this packet.
* a proto_tree, then wonderful. If we don't, we need to build
* one. */
if (ncp_rec) {
- if (ncp_rec->req_cond_indexes) {
- run_req_cond = TRUE;
- }
- /* Only create info string if COL_INFO is available. */
- if (ncp_rec->req_info_str && check_col(pinfo->cinfo, COL_INFO)) {
- run_info_str = TRUE;
- }
- /* We also have to use a tree if we have to construct an info_str */
- if ((run_info_str || run_req_cond) && !ncp_tree) {
- proto_item *ti;
-
- temp_tree = proto_tree_create_root();
- proto_tree_set_visible(temp_tree, FALSE);
- ti = proto_tree_add_item(temp_tree, proto_ncp, tvb, 0, -1, FALSE);
- ncp_tree = proto_item_add_subtree(ti, ett_ncp);
- }
+ if (ncp_rec->req_cond_indexes) {
+ run_req_cond = TRUE;
+ }
+ /* Only create info string if COL_INFO is available. */
+ if (ncp_rec->req_info_str && check_col(pinfo->cinfo, COL_INFO)) {
+ run_info_str = TRUE;
+ }
+ /* We also have to use a tree if we have to construct an info_str */
+ if ((run_info_str || run_req_cond) && !ncp_tree) {
+ proto_item *ti;
+
+ temp_tree = proto_tree_create_root();
+ proto_tree_set_visible(temp_tree, FALSE);
+ ti = proto_tree_add_item(temp_tree, proto_ncp, tvb, 0, -1, FALSE);
+ ncp_tree = proto_item_add_subtree(ti, ett_ncp);
+ }
}
}
PT_NCP, nw_connection, nw_connection, 0);
switch (type) {
- case NCP_ALLOCATE_SLOT:
+ case NCP_BROADCAST_SLOT:
; /* nothing */
break;
}
if (check_col(pinfo->cinfo, COL_INFO)) {
+ if (ncp_rec && ncp_rec->func==0x68 && ncp_rec->subfunc==0x02){
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDS");
+ }
col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
type == NCP_SERVICE_REPLY ? "R" : "ACK",
error_string);
}
}
}
+
+void
+dissect_nds_request(tvbuff_t *tvb, packet_info *pinfo,
+ guint16 nw_connection, guint8 sequence,
+ guint16 type, proto_tree *ncp_tree)
+{
+ guint8 func, subfunc = 0;
+ ncp_req_hash_value *request_value = NULL;
+ const ncp_record *ncp_rec = NULL;
+ conversation_t *conversation;
+ ptvcursor_t *ptvc = NULL;
+ proto_tree *temp_tree = NULL;
+ guint8 nds_verb = 0;
+ char * verb_string = "";
+ guint32 nds_frag = 0;
+
+ func = tvb_get_guint8(tvb, 6);
+ subfunc = tvb_get_guint8(tvb, 7);
+
+ ncp_rec = ncp_record_find(func, subfunc);
+
+ /* Check to see if this is a fragment packet */
+ nds_frag = tvb_get_ntohl(tvb, 8);
+
+ /* Get NDS Verb */
+ if (nds_frag == 0xffffffff) {
+ nds_verb = tvb_get_guint8(tvb, 24);
+ if (nds_verb == 0xfe) {
+ nds_verb = tvb_get_guint8(tvb, 32);
+ }
+ verb_string = match_strval(nds_verb, ncp_nds_verb_vals);
+ if (verb_string == NULL) {
+ verb_string = "NDS Continuation Fragment";
+ }
+ }
+ /* Fill in the INFO column. */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ if (ncp_rec) {
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "NDS");
+ if (nds_frag != 0xffffffff) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Continuation Fragment");
+ }
+ else {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "C NDS %s", verb_string);
+ }
+ }
+ else {
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "C Unknown Function %d (0x%02x)",
+ func, 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(&pinfo->src, &pinfo->dst,
+ PT_NCP, nw_connection, nw_connection, 0);
+
+ if (conversation == NULL) {
+ /* It's not part of any conversation - create a new one. */
+ conversation = conversation_new(&pinfo->src, &pinfo->dst,
+ PT_NCP, nw_connection, nw_connection, 0);
+ }
+
+ request_value = ncp_hash_insert(conversation, sequence, ncp_rec);
+ request_value->req_frame_num = pinfo->fd->num;
+
+ /* If this is the first time we're examining the packet,
+ * check to see if this NCP type uses a "request condition".
+ * If so, we have to build a proto_tree because request conditions
+ * use display filters to work, and without a proto_tree,
+ * display filters can't possibly work. If we already have
+ * a proto_tree, then wonderful. If we don't, we need to build
+ * one. */
+ if (ncp_rec && ncp_tree == NULL) {
+ proto_item *ti;
+
+ temp_tree = proto_tree_create_root();
+ proto_tree_set_visible(temp_tree, FALSE);
+ ti = proto_tree_add_item(temp_tree, proto_ncp, tvb, 0, -1, FALSE);
+ ncp_tree = proto_item_add_subtree(ti, ett_ncp);
+ }
+ }
+
+ if (ncp_tree) {
+ /* If the dissection throws an exception, be sure to free
+ * the temporary proto_tree that was created. Because of the
+ * way the CLEANUP_PUSH macro works, we can't put it in an 'if'
+ * block; it has to be in the same scope as the terminating
+ * CLEANUP_POP or CLEANUP_POP_AND_ALLOC. So, we always
+ * call CLEANUP_POP and friends, but the value of temp_tree is
+ * NULL if no cleanup is needed, and non-null if cleanup is needed.
+ */
+
+ CLEANUP_PUSH(free_proto_tree, temp_tree);
+
+ conversation = find_conversation(&pinfo->src, &pinfo->dst,
+ PT_NCP, nw_connection, nw_connection, 0);
+
+ switch (type) {
+ case NCP_BROADCAST_SLOT:
+ ; /* nothing */
+ break;
+
+ case NCP_SERVICE_REQUEST:
+ proto_tree_add_uint_format(ncp_tree, hf_ncp_func, tvb, 6, 1,
+ func, "Function: %d (0x%02X), %s",
+ func, func, ncp_rec ? ncp_rec->name : "Unknown");
+
+ proto_tree_add_uint_format(ncp_tree, hf_ncp_subfunc, tvb, 7, 1,
+ subfunc, "SubFunction: %d (0x%02x)",
+ subfunc, subfunc);
+
+ proto_tree_add_uint(ncp_tree, hf_ncp_fragment_handle, tvb, 8, 4,
+ nds_frag);
+
+ if (nds_frag == 0xffffffff) {
+ proto_tree_add_item(ncp_tree, hf_ncp_fragment_size, tvb, 12, 4, TRUE);
+ proto_tree_add_item(ncp_tree, hf_ncp_message_size, tvb, 16, 4, TRUE);
+ proto_tree_add_item(ncp_tree, hf_ncp_nds_flag, tvb, 20, 4, FALSE);
+ proto_tree_add_uint_format(ncp_tree, hf_ncp_nds_verb, tvb, 24, 1,
+ nds_verb, "NDS Verb: %u, (0x%02x), %s",
+ nds_verb, nds_verb, verb_string);
+ }
+ break;
+
+ default:
+ ; /* nothing */
+ break;
+ }
+ ptvc = ptvcursor_new(ncp_tree, tvb, 7);
+ if (ncp_rec && ncp_rec->request_ptvc) {
+ clear_repeat_vars();
+ process_ptvc_record(ptvc, ncp_rec->request_ptvc, NULL, TRUE, ncp_rec);
+ }
+ ptvcursor_free(ptvc);
+
+ /* Free the temporary proto_tree */
+ CLEANUP_CALL_AND_POP;
+ }
+}