3 * Routines for NetWare Core Protocol. This C code gets #include'd
4 * into packet-ncp2222.c, which is generated from ncp2222.py. It's
5 * #include'd instead of being in a separate compilation unit so
6 * that all the data tables in packet-ncp2222.c can remain static.
8 * Gilbert Ramirez <gram@alumni.rice.edu>
10 * $Id: packet-ncp2222.inc,v 1.8 2002/01/10 04:44:34 gram Exp $
12 * Ethereal - Network traffic analyzer
13 * By Gerald Combs <gerald@ethereal.com>
14 * Copyright 2000 Gerald Combs
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 /* Does NCP func require a subfunction code? */
33 ncp_requires_subfunc(guint8 func)
35 const guint8 *ncp_func_requirement = ncp_func_requires_subfunc;
37 while (*ncp_func_requirement != 0) {
38 if (*ncp_func_requirement == func) {
41 ncp_func_requirement++;
46 /* Does the NCP func have a length parameter? */
48 ncp_has_length_parameter(guint8 func)
50 const guint8 *ncp_func_requirement = ncp_func_has_no_length_parameter;
52 while (*ncp_func_requirement != 0) {
53 if (*ncp_func_requirement == func) {
56 ncp_func_requirement++;
62 /* Return a ncp_record* based on func and possibly subfunc */
63 static const ncp_record *
64 ncp_record_find(guint8 func, guint8 subfunc)
66 const ncp_record *ncp_rec = ncp_packets;
68 while(ncp_rec->func != 0 || ncp_rec->subfunc != 0 ||
69 ncp_rec->name != NULL ) {
70 if (ncp_rec->func == func) {
71 if (ncp_rec->has_subfunc) {
72 if (ncp_rec->subfunc == subfunc) {
85 /* Add a value for a ptvc_record, and process the sub-ptvc_record
86 * that it points to. */
88 process_sub_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec)
92 const ptvc_record *sub_rec;
95 ptvcursor_t *sub_ptvc;
97 /* Save the current offset */
98 current_offset = ptvcursor_current_offset(ptvc);
101 item = ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
104 ett = *rec->sub_ptvc_rec->ett;
106 /* Make a new protocol sub-tree */
107 sub_tree = proto_item_add_subtree(item, ett);
109 /* Make a new ptvcursor */
110 sub_ptvc = ptvcursor_new(sub_tree, ptvcursor_tvbuff(ptvc),
114 sub_rec = rec->sub_ptvc_rec->ptvc_rec;
115 while(sub_rec->hf_ptr != NULL) {
116 g_assert(!sub_rec->sub_ptvc_rec);
117 ptvcursor_add_no_advance(sub_ptvc, *sub_rec->hf_ptr,
118 sub_rec->length, sub_rec->endianness);
123 ptvcursor_free(sub_ptvc);
126 /* Run through the table of ptvc_record's and add info to the tree */
128 process_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec)
130 while(rec->hf_ptr != NULL) {
131 if (rec->sub_ptvc_rec) {
132 process_sub_ptvc_record(ptvc, rec);
135 ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
143 /* Given an error_equivalency table and a completion code, return
144 * the string representing the error. */
146 ncp_error_string(const error_equivalency *errors, guint8 completion_code)
148 while (errors->ncp_error_index != -1) {
149 if (errors->error_in_packet == completion_code) {
150 return ncp_errors[errors->ncp_error_index];
158 static const ncp_record ncp1111_request =
159 { 0x01, 0x00, NO_SUBFUNC, "Create Connection Service", NCP_GROUP_CONNECTION,
160 NULL, NULL, NULL, NULL,
165 dissect_ncp_request(tvbuff_t *tvb, packet_info *pinfo,
166 guint16 nw_connection, guint8 sequence,
167 guint16 type, proto_tree *ncp_tree, proto_tree *tree)
169 guint8 func, subfunc = 0;
170 gboolean requires_subfunc;
171 gboolean has_length = TRUE;
172 const ncp_record *ncp_rec = NULL;
173 conversation_t *conversation;
174 ptvcursor_t *ptvc = NULL;
176 func = tvb_get_guint8(tvb, 6);
178 requires_subfunc = ncp_requires_subfunc(func);
179 has_length = ncp_has_length_parameter(func);
180 if (requires_subfunc) {
182 subfunc = tvb_get_guint8(tvb, 9);
185 subfunc = tvb_get_guint8(tvb, 7);
189 /* Determine which ncp_record to use. */
192 ncp_rec = &ncp1111_request;
195 ncp_rec = ncp_record_find(func, subfunc);
201 /* Fill in the INFO column. */
202 if (check_col(pinfo->cinfo, COL_INFO)) {
204 col_add_fstr(pinfo->cinfo, COL_INFO, "C %s", ncp_rec->name);
207 if (requires_subfunc) {
208 col_add_fstr(pinfo->cinfo, COL_INFO,
209 "C Unknown Function 0x%02X/0x%02x (%d %d)",
210 func, subfunc, func, subfunc);
213 col_add_fstr(pinfo->cinfo, COL_INFO,
214 "C Unknown Function 0x%02x (%d)",
220 if (!pinfo->fd->flags.visited) {
221 /* This is the first time we've looked at this packet.
222 Keep track of the address and connection whence the request
223 came, and the address and connection to which the request
224 is being sent, so that we can match up calls with replies.
225 (We don't include the sequence number, as we may want
226 to have all packets over the same connection treated
227 as being part of a single conversation so that we can
228 let the user select that conversation to be displayed.) */
229 conversation = find_conversation(&pinfo->src, &pinfo->dst,
230 PT_NCP, nw_connection, nw_connection, 0);
232 if (conversation == NULL) {
233 /* It's not part of any conversation - create a new one. */
234 conversation = conversation_new(&pinfo->src, &pinfo->dst,
235 PT_NCP, nw_connection, nw_connection, 0);
237 ncp_hash_insert(conversation, sequence, ncp_rec);
241 conversation = find_conversation(&pinfo->src, &pinfo->dst,
242 PT_NCP, nw_connection, nw_connection, 0);
250 proto_tree_add_uint_format(ncp_tree, hf_ncp_func, tvb, 6, 1,
251 func, "Function Code: 0x%02X (%s)",
252 func, ncp_rec ? ncp_rec->name : "Unknown");
260 if (requires_subfunc) {
262 proto_tree_add_item(ncp_tree, hf_ncp_length, tvb, 7,
264 proto_tree_add_item(ncp_tree, hf_ncp_subfunc, tvb, 9,
266 ptvc = ptvcursor_new(ncp_tree, tvb, 10);
269 proto_tree_add_item(ncp_tree, hf_ncp_subfunc, tvb, 7,
271 ptvc = ptvcursor_new(ncp_tree, tvb, 8);
275 ptvc = ptvcursor_new(ncp_tree, tvb, 7);
278 /* The group is not part of the packet, but it's useful
279 * information to display anyway. */
281 proto_tree_add_text(ncp_tree, tvb, 6, 1, "Group: %s",
282 ncp_groups[ncp_rec->group]);
285 if (ncp_rec && ncp_rec->request_ptvc) {
286 process_ptvc_record(ptvc, ncp_rec->request_ptvc);
288 ptvcursor_free(ptvc);
294 dissect_ncp_reply(tvbuff_t *tvb, packet_info *pinfo,
295 guint16 nw_connection, guint8 sequence,
296 proto_tree *ncp_tree, proto_tree *tree) {
298 conversation_t *conversation;
299 const ncp_record *ncp_rec = NULL;
300 gboolean found_request = FALSE;
301 guint8 completion_code;
303 ptvcursor_t *ptvc = NULL;
304 const char *error_string;
306 if (!pinfo->fd->flags.visited) {
307 /* Find the conversation whence the request would have come. */
308 conversation = find_conversation(&pinfo->src, &pinfo->dst,
309 PT_NCP, nw_connection, nw_connection, 0);
310 if (conversation != NULL) {
311 /* find the record telling us the request made that caused
313 ncp_rec = ncp_hash_lookup(conversation, sequence);
314 p_add_proto_data(pinfo->fd, proto_ncp, (void*) ncp_rec);
316 /* else... we haven't seen an NCP Request for that conversation and sequence. */
319 ncp_rec = p_get_proto_data(pinfo->fd, proto_ncp);
322 /* A completion code of 0 always means OK. Non-zero means failure,
323 * but each non-zero value has a different meaning. And the same value
324 * can have different meanings, depending on the ncp.func (and ncp.subfunc)
326 completion_code = tvb_get_guint8(tvb, 6);
327 if (ncp_rec && ncp_rec->errors) {
328 error_string = ncp_error_string(ncp_rec->errors, completion_code);
330 else if (completion_code == 0) {
334 error_string = "Not OK";
337 if (check_col(pinfo->cinfo, COL_INFO)) {
338 col_add_fstr(pinfo->cinfo, COL_INFO, "R %s", error_string);
343 /* Put the func (and maybe subfunc) from the request packet
344 * in the proto tree, but hidden. That way filters on ncp.func
345 * or ncp.subfunc will find both the requests and the replies.
348 proto_tree_add_uint(ncp_tree, hf_ncp_func, tvb,
349 6, 0, ncp_rec->func);
350 if (ncp_requires_subfunc(ncp_rec->func)) {
351 proto_tree_add_uint(ncp_tree, hf_ncp_subfunc,
352 tvb, 6, 0, ncp_rec->subfunc);
356 proto_tree_add_uint_format(ncp_tree, hf_ncp_completion_code, tvb, 6, 1,
357 completion_code, "Completion Code: 0x%02x (%s)",
358 completion_code, error_string);
360 proto_tree_add_item(ncp_tree, hf_ncp_connection_status, tvb, 7, 1, FALSE);
362 length = tvb_length(tvb);
363 if (!ncp_rec && length > 8) {
364 proto_tree_add_text(ncp_tree, tvb, 8, length - 8,
365 "No request record found. Parsing is impossible.");
367 else if (ncp_rec && ncp_rec->reply_ptvc) {
368 /* If a non-zero completion code was found, it is
369 * legal to not have any fields, even if the packet
370 * type is defined as having fields. */
371 if (completion_code != 0 && tvb_length(tvb) == 8) {
374 /*printf("func=0x%x subfunc=0x%x\n", ncp_rec->func, ncp_rec->subfunc);*/
375 ptvc = ptvcursor_new(ncp_tree, tvb, 8);
376 process_ptvc_record(ptvc, ncp_rec->reply_ptvc);
377 ptvcursor_free(ptvc);