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@xiexie.org>
10 * $Id: packet-ncp2222.inc,v 1.4 2001/09/03 10:33:05 guy 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 /* Run through the table of ptv_record's and add info to the tree */
87 process_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec)
89 while(rec->hf_ptr != NULL) {
90 ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
97 /* Given an error_equivalency table and a completion code, return
98 * the string representing the error. */
100 ncp_error_string(const error_equivalency *errors, guint8 completion_code)
102 while (errors->ncp_error_index != -1) {
103 if (errors->error_in_packet == completion_code) {
104 return ncp_errors[errors->ncp_error_index];
112 static const ncp_record ncp1111_request =
113 { 0x01, 0x00, NO_SUBFUNC, "Create Connection Service", NCP_GROUP_CONNECTION,
114 NULL, NULL, NULL, NULL,
119 dissect_ncp_request(tvbuff_t *tvb, packet_info *pinfo,
120 guint16 nw_connection, guint8 sequence,
121 guint16 type, proto_tree *ncp_tree, proto_tree *tree)
123 guint8 func, subfunc = 0;
124 gboolean requires_subfunc;
125 gboolean has_length = TRUE;
126 const ncp_record *ncp_rec = NULL;
127 conversation_t *conversation;
128 ptvcursor_t *ptvc = NULL;
130 func = tvb_get_guint8(tvb, 6);
132 requires_subfunc = ncp_requires_subfunc(func);
133 has_length = ncp_has_length_parameter(func);
134 if (requires_subfunc) {
136 subfunc = tvb_get_guint8(tvb, 9);
139 subfunc = tvb_get_guint8(tvb, 7);
143 /* Determine which ncp_record to use. */
146 ncp_rec = &ncp1111_request;
149 ncp_rec = ncp_record_find(func, subfunc);
155 /* Fill in the INFO column. */
156 if (check_col(pinfo->fd, COL_INFO)) {
158 col_add_fstr(pinfo->fd, COL_INFO, "C %s", ncp_rec->name);
161 if (requires_subfunc) {
162 col_add_fstr(pinfo->fd, COL_INFO,
163 "C Unknown Function 0x%02X/0x%02x (%d %d)",
164 func, subfunc, func, subfunc);
167 col_add_fstr(pinfo->fd, COL_INFO,
168 "C Unknown Function 0x%02x (%d)",
174 if (!pinfo->fd->flags.visited) {
175 /* This is the first time we've looked at this packet.
176 Keep track of the address and connection whence the request
177 came, and the address and connection to which the request
178 is being sent, so that we can match up calls with replies.
179 (We don't include the sequence number, as we may want
180 to have all packets over the same connection treated
181 as being part of a single conversation so that we can
182 let the user select that conversation to be displayed.) */
183 conversation = find_conversation(&pinfo->src, &pinfo->dst,
184 PT_NCP, nw_connection, nw_connection, 0);
185 if (conversation == NULL) {
186 /* It's not part of any conversation - create a new one. */
187 conversation = conversation_new(&pinfo->src, &pinfo->dst,
188 PT_NCP, nw_connection, nw_connection, 0);
190 ncp_hash_insert(conversation, sequence, 0x2222, ncp_rec);
200 proto_tree_add_uint_format(ncp_tree, hf_ncp_func, tvb, 6, 1,
201 func, "Function Code: 0x%02X (%s)",
202 func, ncp_rec ? ncp_rec->name : "Unknown");
210 if (requires_subfunc) {
212 proto_tree_add_item(ncp_tree, hf_ncp_length, tvb, 7,
214 proto_tree_add_item(ncp_tree, hf_ncp_subfunc, tvb, 9,
216 ptvc = ptvcursor_new(ncp_tree, tvb, 10);
219 proto_tree_add_item(ncp_tree, hf_ncp_subfunc, tvb, 7,
221 ptvc = ptvcursor_new(ncp_tree, tvb, 8);
225 ptvc = ptvcursor_new(ncp_tree, tvb, 7);
228 /* The group is not part of the packet, but it's useful
229 * information to display anyway. */
231 proto_tree_add_text(ncp_tree, tvb, 6, 1, "Group: %s",
232 ncp_groups[ncp_rec->group]);
235 if (ncp_rec && ncp_rec->request_ptvc) {
236 process_ptvc_record(ptvc, ncp_rec->request_ptvc);
238 ptvcursor_free(ptvc);
244 dissect_ncp_reply(tvbuff_t *tvb, packet_info *pinfo,
245 guint16 nw_connection, guint8 sequence,
246 proto_tree *ncp_tree, proto_tree *tree) {
248 conversation_t *conversation;
249 const ncp_record *ncp_rec = NULL;
251 gboolean found_request = FALSE;
252 guint8 completion_code;
254 ptvcursor_t *ptvc = NULL;
255 const char *error_string;
257 /* Find the conversation whence the request would have come. */
258 conversation = find_conversation(&pinfo->src, &pinfo->dst,
259 PT_NCP, nw_connection, nw_connection, 0);
260 if (conversation != NULL) {
261 /* find the record telling us the request made that caused
263 found_request = ncp_hash_lookup(conversation, sequence,
264 &ncp_type, &ncp_rec);
266 /* else... we haven't seen an NCP Request for that conversation and sequence. */
268 /* A completion code of 0 always means OK. Non-zero means failure,
269 * but each non-zero value has a different meaning. And the same value
270 * can have different meanings, depending on the ncp.func (and ncp.subfunc)
272 completion_code = tvb_get_guint8(tvb, 6);
273 if (ncp_rec && ncp_rec->errors) {
274 error_string = ncp_error_string(ncp_rec->errors, completion_code);
276 else if (completion_code == 0) {
280 error_string = "Not OK";
283 if (check_col(pinfo->fd, COL_INFO)) {
284 col_add_fstr(pinfo->fd, COL_INFO, "R %s", error_string);
289 /* Put the func (and maybe subfunc) from the request packet
290 * in the proto tree, but hidden. That way filters on ncp.func
291 * or ncp.subfunc will find both the requests and the replies.
294 proto_tree_add_uint(ncp_tree, hf_ncp_func, tvb,
295 6, 0, ncp_rec->func);
296 if (ncp_requires_subfunc(ncp_rec->func)) {
297 proto_tree_add_uint(ncp_tree, hf_ncp_subfunc,
298 tvb, 6, 0, ncp_rec->subfunc);
302 proto_tree_add_uint_format(ncp_tree, hf_ncp_completion_code, tvb, 6, 1,
303 completion_code, "Completion Code: 0x%02x (%s)",
304 completion_code, error_string);
306 proto_tree_add_item(ncp_tree, hf_ncp_connection_status, tvb, 7, 1, FALSE);
308 length = tvb_length(tvb);
309 if (!ncp_rec && length > 8) {
310 proto_tree_add_text(ncp_tree, tvb, 8, length - 8,
311 "No request record found. Parsing is impossible.");
313 else if (ncp_rec && ncp_rec->reply_ptvc) {
314 /* If a non-zero completion code was found, it is
315 * legal to not have any fields, even if the packet
316 * type is defined as having fields. */
317 if (completion_code != 0 && tvb_length(tvb) == 8) {
321 ptvc = ptvcursor_new(ncp_tree, tvb, 8);
322 process_ptvc_record(ptvc, ncp_rec->reply_ptvc);
323 ptvcursor_free(ptvc);