Have "dissect_netbios_payload()" take as an argument a tvbuff containing
[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@xiexie.org>
9  *
10  * $Id: packet-ncp2222.inc,v 1.4 2001/09/03 10:33:05 guy 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 /* Run through the table of ptv_record's and add info to the tree */
86 static void
87 process_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec)
88 {
89         while(rec->hf_ptr != NULL) {
90                 ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
91                                 rec->endianness);
92                 rec++;
93         }
94 }
95
96
97 /* Given an error_equivalency table and a completion code, return
98  * the string representing the error. */
99 static const char*
100 ncp_error_string(const error_equivalency *errors, guint8 completion_code)
101 {
102         while (errors->ncp_error_index != -1) {
103                 if (errors->error_in_packet == completion_code) {
104                         return ncp_errors[errors->ncp_error_index];
105                 }
106                 errors++;
107         }
108
109         return "Unknown";
110 }
111
112 static const ncp_record ncp1111_request =
113         { 0x01, 0x00, NO_SUBFUNC, "Create Connection Service", NCP_GROUP_CONNECTION,
114                 NULL, NULL, NULL, NULL,
115                 ncp_0x2_errors };
116
117
118 void
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)
122 {
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;
129
130         func = tvb_get_guint8(tvb, 6);
131
132         requires_subfunc = ncp_requires_subfunc(func);
133         has_length = ncp_has_length_parameter(func);
134         if (requires_subfunc) {
135                 if (has_length) {
136                         subfunc = tvb_get_guint8(tvb, 9);
137                 }
138                 else {
139                         subfunc = tvb_get_guint8(tvb, 7);
140                 }
141         }
142
143         /* Determine which ncp_record to use. */
144         switch (type) {
145                 case 0x1111:
146                         ncp_rec = &ncp1111_request;
147                         break;
148                 case 0x2222:
149                         ncp_rec = ncp_record_find(func, subfunc);
150                         break;
151                 default:
152                         ncp_rec = NULL;
153         }
154
155         /* Fill in the INFO column. */
156         if (check_col(pinfo->fd, COL_INFO)) {
157                 if (ncp_rec) {
158                         col_add_fstr(pinfo->fd, COL_INFO, "C %s", ncp_rec->name);
159                 }
160                 else {
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);
165                         }
166                         else {
167                                 col_add_fstr(pinfo->fd, COL_INFO,
168                                         "C Unknown Function 0x%02x (%d)",
169                                         func, func);
170                         }
171                 }
172         }
173
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);
189                 }
190                 ncp_hash_insert(conversation, sequence, 0x2222, ncp_rec);
191         }
192
193         if (ncp_tree) {
194                 switch (type) {
195                         case 0x1111:
196                                 ; /* nothing */
197                                 break;
198
199                         case 0x2222:
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");
203                                 break;
204
205                         default:
206                                 ; /* nothing */
207                                 break;
208                 }
209
210                 if (requires_subfunc) {
211                         if (has_length) {
212                                 proto_tree_add_item(ncp_tree, hf_ncp_length, tvb, 7,
213                                                 2, FALSE);
214                                 proto_tree_add_item(ncp_tree, hf_ncp_subfunc, tvb, 9,
215                                                 1, FALSE);
216                                 ptvc = ptvcursor_new(ncp_tree, tvb, 10);
217                         }
218                         else {
219                                 proto_tree_add_item(ncp_tree, hf_ncp_subfunc, tvb, 7,
220                                                 1, FALSE);
221                                 ptvc = ptvcursor_new(ncp_tree, tvb, 8);
222                         }
223                 }
224                 else {
225                         ptvc = ptvcursor_new(ncp_tree, tvb, 7);
226                 }
227
228                 /* The group is not part of the packet, but it's useful
229                  * information to display anyway. */
230                 if (ncp_rec) {
231                         proto_tree_add_text(ncp_tree, tvb, 6, 1, "Group: %s",
232                                         ncp_groups[ncp_rec->group]);
233                 }
234
235                 if (ncp_rec && ncp_rec->request_ptvc) {
236                         process_ptvc_record(ptvc, ncp_rec->request_ptvc);
237                 }
238                 ptvcursor_free(ptvc);
239         }
240 }
241
242
243 void
244 dissect_ncp_reply(tvbuff_t *tvb, packet_info *pinfo,
245         guint16 nw_connection, guint8 sequence,
246         proto_tree *ncp_tree, proto_tree *tree) {
247
248         conversation_t                  *conversation;
249         const ncp_record                *ncp_rec = NULL;
250         guint16                         ncp_type;
251         gboolean                        found_request = FALSE;
252         guint8                          completion_code;
253         guint                           length;
254         ptvcursor_t                     *ptvc = NULL;
255         const char                      *error_string;
256
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
262                    this reply */
263                 found_request = ncp_hash_lookup(conversation, sequence,
264                                 &ncp_type, &ncp_rec);
265         }
266         /* else... we haven't seen an NCP Request for that conversation and sequence. */
267
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)
271          * value. */
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);
275         }
276         else if (completion_code == 0) {
277                 error_string = "OK";
278         }
279         else {
280                 error_string = "Not OK";
281         }
282
283         if (check_col(pinfo->fd, COL_INFO)) {
284                 col_add_fstr(pinfo->fd, COL_INFO, "R %s", error_string);
285         }
286
287         if (ncp_tree) {
288
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.
292                  */
293                 if (ncp_rec) {
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);
299                         }
300                 }
301
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);
305
306                 proto_tree_add_item(ncp_tree, hf_ncp_connection_status, tvb, 7, 1, FALSE);
307
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.");
312                 }
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) {
318                                 return;
319                         }
320
321                         ptvc = ptvcursor_new(ncp_tree, tvb, 8);
322                         process_ptvc_record(ptvc, ncp_rec->reply_ptvc);
323                         ptvcursor_free(ptvc);
324                 }
325         }
326 }