Use Ashok's IEEE-float-to-long code as the basis for
[obnox/wireshark/wip.git] / packet-ncp2222.inc
1 /* packet-ncp2222.inc
2  *
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.
7  *
8  * Gilbert Ramirez <gram@alumni.rice.edu>
9  *
10  * $Id: packet-ncp2222.inc,v 1.9 2002/04/04 03:51:39 gram Exp $
11  *
12  * Ethereal - Network traffic analyzer
13  * By Gerald Combs <gerald@ethereal.com>
14  * Copyright 2000 Gerald Combs
15  *
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.
20  * 
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.
25  * 
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.
29  */
30
31 /* Does NCP func require a subfunction code? */
32 static gboolean
33 ncp_requires_subfunc(guint8 func)
34 {
35         const guint8 *ncp_func_requirement = ncp_func_requires_subfunc;
36
37         while (*ncp_func_requirement != 0) {
38                 if (*ncp_func_requirement == func) {
39                         return TRUE;
40                 }
41                 ncp_func_requirement++;
42         }
43         return FALSE;
44 }
45
46 /* Does the NCP func have a length parameter? */
47 static gboolean
48 ncp_has_length_parameter(guint8 func)
49 {
50         const guint8 *ncp_func_requirement = ncp_func_has_no_length_parameter;
51
52         while (*ncp_func_requirement != 0) {
53                 if (*ncp_func_requirement == func) {
54                         return FALSE;
55                 }
56                 ncp_func_requirement++;
57         }
58         return TRUE;
59 }
60                 
61
62 /* Return a ncp_record* based on func and possibly subfunc */
63 static const ncp_record *
64 ncp_record_find(guint8 func, guint8 subfunc)
65 {
66         const ncp_record *ncp_rec = ncp_packets;
67
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) {
73                                         return ncp_rec;
74                                 }
75                         }
76                         else {
77                                 return ncp_rec;
78                         }
79                 }
80                 ncp_rec++;
81         }
82         return NULL;
83 }
84
85 /* Add a value for a ptvc_record, and process the sub-ptvc_record
86  * that it points to. */
87 static void
88 process_sub_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec)
89 {
90         proto_item              *item;
91         proto_tree              *sub_tree;
92         const ptvc_record       *sub_rec;
93         int                     current_offset;
94         gint                    ett;
95         ptvcursor_t             *sub_ptvc;
96
97         /* Save the current offset */
98         current_offset = ptvcursor_current_offset(ptvc);
99
100         /* Add the item */
101         item = ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
102                         rec->endianness);
103
104         ett = *rec->sub_ptvc_rec->ett;
105
106         /* Make a new protocol sub-tree */
107         sub_tree = proto_item_add_subtree(item, ett);
108
109         /* Make a new ptvcursor */
110         sub_ptvc = ptvcursor_new(sub_tree, ptvcursor_tvbuff(ptvc),
111                         current_offset);
112
113         /* Use it */
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);
119                 sub_rec++;
120         }
121
122         /* Free it. */
123         ptvcursor_free(sub_ptvc);
124 }
125
126 /* Run through the table of ptvc_record's and add info to the tree */
127 static void
128 process_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec)
129 {
130         while(rec->hf_ptr != NULL) {
131                 if (rec->sub_ptvc_rec) {
132                         process_sub_ptvc_record(ptvc, rec);
133                 }
134                 else {
135                         ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
136                                 rec->endianness);
137                 }
138                 rec++;
139         }
140 }
141
142
143 /* Given an error_equivalency table and a completion code, return
144  * the string representing the error. */
145 static const char*
146 ncp_error_string(const error_equivalency *errors, guint8 completion_code)
147 {
148         while (errors->ncp_error_index != -1) {
149                 if (errors->error_in_packet == completion_code) {
150                         return ncp_errors[errors->ncp_error_index];
151                 }
152                 errors++;
153         }
154
155         return "Unknown";
156 }
157
158 static const ncp_record ncp1111_request =
159         { 0x01, 0x00, NO_SUBFUNC, "Create Connection Service", NCP_GROUP_CONNECTION,
160                 NULL, NULL, NULL, NULL,
161                 ncp_0x2_errors };
162
163
164 void
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)
168 {
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;
175
176         func = tvb_get_guint8(tvb, 6);
177
178         requires_subfunc = ncp_requires_subfunc(func);
179         has_length = ncp_has_length_parameter(func);
180         if (requires_subfunc) {
181                 if (has_length) {
182                         subfunc = tvb_get_guint8(tvb, 9);
183                 }
184                 else {
185                         subfunc = tvb_get_guint8(tvb, 7);
186                 }
187         }
188
189         /* Determine which ncp_record to use. */
190         switch (type) {
191                 case 0x1111:
192                         ncp_rec = &ncp1111_request;
193                         break;
194                 case 0x2222:
195                         ncp_rec = ncp_record_find(func, subfunc);
196                         break;
197                 default:
198                         ncp_rec = NULL;
199         }
200
201         /* Fill in the INFO column. */
202         if (check_col(pinfo->cinfo, COL_INFO)) {
203                 if (ncp_rec) {
204                         col_add_fstr(pinfo->cinfo, COL_INFO, "C %s", ncp_rec->name);
205                 }
206                 else {
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);
211                         }
212                         else {
213                                 col_add_fstr(pinfo->cinfo, COL_INFO,
214                                         "C Unknown Function 0x%02x (%d)",
215                                         func, func);
216                         }
217                 }
218         }
219
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);
231
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);
236                 }
237                 ncp_hash_insert(conversation, sequence, ncp_rec);
238         }
239
240         if (ncp_tree) {
241                 conversation = find_conversation(&pinfo->src, &pinfo->dst,
242                     PT_NCP, nw_connection, nw_connection, 0);
243
244                 switch (type) {
245                         case 0x1111:
246                                 ; /* nothing */
247                                 break;
248
249                         case 0x2222:
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");
253                                 break;
254
255                         default:
256                                 ; /* nothing */
257                                 break;
258                 }
259
260                 if (requires_subfunc) {
261                         if (has_length) {
262                                 proto_tree_add_item(ncp_tree, hf_ncp_length, tvb, 7,
263                                                 2, FALSE);
264                                 proto_tree_add_item(ncp_tree, hf_ncp_subfunc, tvb, 9,
265                                                 1, FALSE);
266                                 ptvc = ptvcursor_new(ncp_tree, tvb, 10);
267                         }
268                         else {
269                                 proto_tree_add_item(ncp_tree, hf_ncp_subfunc, tvb, 7,
270                                                 1, FALSE);
271                                 ptvc = ptvcursor_new(ncp_tree, tvb, 8);
272                         }
273                 }
274                 else {
275                         ptvc = ptvcursor_new(ncp_tree, tvb, 7);
276                 }
277
278                 /* The group is not part of the packet, but it's useful
279                  * information to display anyway. */
280                 if (ncp_rec) {
281                         proto_tree_add_text(ncp_tree, tvb, 6, 1, "Group: %s",
282                                         ncp_groups[ncp_rec->group]);
283                 }
284
285                 if (ncp_rec && ncp_rec->request_ptvc) {
286                         process_ptvc_record(ptvc, ncp_rec->request_ptvc);
287                 }
288                 ptvcursor_free(ptvc);
289         }
290 }
291
292
293 void
294 dissect_ncp_reply(tvbuff_t *tvb, packet_info *pinfo,
295         guint16 nw_connection, guint8 sequence,
296         proto_tree *ncp_tree, proto_tree *tree) {
297
298         conversation_t                  *conversation;
299         const ncp_record                *ncp_rec = NULL;
300         guint8                          completion_code;
301         guint                           length;
302         ptvcursor_t                     *ptvc = NULL;
303         const char                      *error_string;
304
305         if (!pinfo->fd->flags.visited) {
306                 /* Find the conversation whence the request would have come. */
307                 conversation = find_conversation(&pinfo->src, &pinfo->dst,
308                             PT_NCP, nw_connection, nw_connection, 0);
309                 if (conversation != NULL) {
310                         /* find the record telling us the request made that caused
311                            this reply */
312                         ncp_rec = ncp_hash_lookup(conversation, sequence);
313                         p_add_proto_data(pinfo->fd, proto_ncp, (void*) ncp_rec);
314                 }
315                 /* else... we haven't seen an NCP Request for that conversation and sequence. */
316         }
317         else {
318                 ncp_rec = p_get_proto_data(pinfo->fd, proto_ncp);
319         }
320
321         /* A completion code of 0 always means OK. Non-zero means failure,
322          * but each non-zero value has a different meaning. And the same value
323          * can have different meanings, depending on the ncp.func (and ncp.subfunc)
324          * value. */
325         completion_code = tvb_get_guint8(tvb, 6);
326         if (ncp_rec && ncp_rec->errors) {
327                 error_string = ncp_error_string(ncp_rec->errors, completion_code);
328         }
329         else if (completion_code == 0) {
330                 error_string = "OK";
331         }
332         else {
333                 error_string = "Not OK";
334         }
335
336         if (check_col(pinfo->cinfo, COL_INFO)) {
337                 col_add_fstr(pinfo->cinfo, COL_INFO, "R %s", error_string);
338         }
339
340         if (ncp_tree) {
341
342                 /* Put the func (and maybe subfunc) from the request packet
343                  * in the proto tree, but hidden. That way filters on ncp.func
344                  * or ncp.subfunc will find both the requests and the replies.
345                  */
346                 if (ncp_rec) {
347                         proto_tree_add_uint(ncp_tree, hf_ncp_func, tvb,
348                                         6, 0, ncp_rec->func);
349                         if (ncp_requires_subfunc(ncp_rec->func)) {
350                                 proto_tree_add_uint(ncp_tree, hf_ncp_subfunc,
351                                                 tvb, 6, 0, ncp_rec->subfunc);
352                         }
353                 }
354
355                 proto_tree_add_uint_format(ncp_tree, hf_ncp_completion_code, tvb, 6, 1,
356                         completion_code, "Completion Code: 0x%02x (%s)",
357                         completion_code, error_string);
358
359                 proto_tree_add_item(ncp_tree, hf_ncp_connection_status, tvb, 7, 1, FALSE);
360
361                 length = tvb_length(tvb);
362                 if (!ncp_rec && length > 8) {
363                         proto_tree_add_text(ncp_tree, tvb, 8, length - 8,
364                                         "No request record found. Parsing is impossible.");
365                 }
366                 else if (ncp_rec && ncp_rec->reply_ptvc) {
367                         /* If a non-zero completion code was found, it is
368                          * legal to not have any fields, even if the packet
369                          * type is defined as having fields. */
370                         if (completion_code != 0 && tvb_length(tvb) == 8) {
371                                 return;
372                         }
373                         /*printf("func=0x%x subfunc=0x%x\n", ncp_rec->func, ncp_rec->subfunc);*/
374                         ptvc = ptvcursor_new(ncp_tree, tvb, 8);
375                         process_ptvc_record(ptvc, ncp_rec->reply_ptvc);
376                         ptvcursor_free(ptvc);
377                 }
378         }
379 }