"hf_sna_rh_csi" is now an FT_UINT8 field, so add it with
[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.2 2000/10/21 05:52:21 guy Exp $
11  *
12  * Ethereal - Network traffic analyzer
13  * By Gerald Combs <gerald@zing.org>
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 /* Return a ncp_record* based on func and possibly subfunc */
47 static const ncp_record *
48 ncp_record_find(guint8 func, guint8 subfunc)
49 {
50         const ncp_record *ncp_rec = ncp_packets;
51
52         while(ncp_rec->func != 0 || ncp_rec->subfunc != 0 ||
53                 ncp_rec->name != NULL ) {
54                 if (ncp_rec->func == func &&
55                         ncp_rec->subfunc == (subfunc & ncp_rec->submask)) {
56                         return ncp_rec;
57                 }
58                 ncp_rec++;
59         }
60         return NULL;
61 }
62
63 /* Run through the table of ptv_record's and add info to the tree */
64 static void
65 process_ptvc_record(ptvcursor_t *ptvc, const ptvc_record *rec)
66 {
67         while(rec->hf_ptr != NULL) {
68                 ptvcursor_add(ptvc, *rec->hf_ptr, rec->length,
69                                 rec->endianness);
70                 rec++;
71         }
72 }
73
74
75 /* Given an error_equivalency table and a completion code, return
76  * the string representing the error. */
77 static const char*
78 ncp_error_string(const error_equivalency *errors, guint8 completion_code)
79 {
80         while (errors->ncp_error_index != -1) {
81                 if (errors->error_in_packet == completion_code) {
82                         return ncp_errors[errors->ncp_error_index];
83                 }
84                 errors++;
85         }
86
87         return "Unknown";
88 }
89
90 void
91 dissect_ncp_request(tvbuff_t *tvb, packet_info *pinfo,
92                 guint16 nw_connection, guint8 sequence,
93                 guint16 type, proto_tree *ncp_tree, proto_tree *tree)
94 {
95         guint8                  func, subfunc = 0;
96         gboolean                requires_subfunc;
97         const ncp_record        *ncp_rec;
98         conversation_t          *conversation;
99         ptvcursor_t             *ptvc = NULL;
100
101         func = tvb_get_guint8(tvb, 6);
102
103         requires_subfunc = ncp_requires_subfunc(func);
104         if (requires_subfunc) {
105                 subfunc = tvb_get_guint8(tvb, 9);
106         }
107
108         ncp_rec = ncp_record_find(func, subfunc);
109
110         if (check_col(pinfo->fd, COL_INFO)) {
111                 if (ncp_rec) {
112                         col_add_fstr(pinfo->fd, COL_INFO, "C %s", ncp_rec->name);
113                 }
114                 else {
115                         if (requires_subfunc) {
116                                 col_add_fstr(pinfo->fd, COL_INFO,
117                                                 "C Unknown Function 0x%02X/0x%02x",
118                                                 func, subfunc);
119                         }
120                         else {
121                                 col_add_fstr(pinfo->fd, COL_INFO,
122                                                 "C Unknown Function 0x%02x",
123                                                 func);
124                         }
125                 }
126         }
127
128         if (!pinfo->fd->flags.visited) {
129                 /* This is the first time we've looked at this packet.
130                    Keep track of the address and connection whence the request
131                    came, and the address and connection to which the request
132                    is being sent, so that we can match up calls with replies.
133                    (We don't include the sequence number, as we may want
134                    to have all packets over the same connection treated
135                    as being part of a single conversation so that we can
136                    let the user select that conversation to be displayed.) */
137                 conversation = find_conversation(&pi.src, &pi.dst,
138                     PT_NCP, nw_connection, nw_connection, 0);
139                 if (conversation == NULL) {
140                         /* It's not part of any conversation - create a new one. */
141                         conversation = conversation_new(&pi.src, &pi.dst,
142                             PT_NCP, nw_connection, nw_connection, NULL, 0);
143                 }
144                 ncp_hash_insert(conversation, sequence, 0x2222, ncp_rec);
145         }
146
147         if (ncp_tree) {
148                 proto_tree_add_uint_format(ncp_tree, hf_ncp_func, tvb, 6, 1,
149                         func, "Function Code: 0x%02X (%s)",
150                         func, ncp_rec ? ncp_rec->name : "Unknown");
151
152                 if (requires_subfunc) {
153                         proto_tree_add_item(ncp_tree, hf_ncp_length, tvb, 7,
154                                         2, FALSE);
155                         proto_tree_add_item(ncp_tree, hf_ncp_subfunc, tvb, 9,
156                                         1, FALSE);
157                         ptvc = ptvcursor_new(ncp_tree, tvb, 10);
158                 }
159                 else {
160                         ptvc = ptvcursor_new(ncp_tree, tvb, 7);
161                 }
162
163                 /* The group is not part of the packet, but it's useful
164                  * information to display anyway. */
165                 if (ncp_rec) {
166                         proto_tree_add_text(ncp_tree, tvb, 6, 1, "Group: %s",
167                                         ncp_groups[ncp_rec->group]);
168                 }
169
170                 if (ncp_rec && ncp_rec->request_ptvc) {
171                         process_ptvc_record(ptvc, ncp_rec->request_ptvc);
172                 }
173                 ptvcursor_free(ptvc);
174         }
175 }
176
177
178 void
179 dissect_ncp_reply(tvbuff_t *tvb, packet_info *pinfo,
180         guint16 nw_connection, guint8 sequence,
181         proto_tree *ncp_tree, proto_tree *tree) {
182
183         conversation_t                  *conversation;
184         const ncp_record                *ncp_rec = NULL;
185         guint16                         ncp_type;
186         gboolean                        found_request = FALSE;
187         guint8                          completion_code;
188         guint                           length;
189         ptvcursor_t                     *ptvc = NULL;
190         const char                      *error_string;
191
192         /* Find the conversation whence the request would have come. */
193         conversation = find_conversation(&pi.src, &pi.dst,
194                     PT_NCP, nw_connection, nw_connection, 0);
195         if (conversation != NULL) {
196                 /* find the record telling us the request made that caused
197                    this reply */
198                 found_request = ncp_hash_lookup(conversation, sequence,
199                                 &ncp_type, &ncp_rec);
200         }
201         /* else... we haven't seen an NCP Request for that conversation and sequence. */
202
203         /* A completion code of 0 always means OK. Non-zero means failure,
204          * but each non-zero value has a different meaning. And the same value
205          * can have different meanings, depending on the ncp.func (and ncp.subfunc)
206          * value. */
207         completion_code = tvb_get_guint8(tvb, 6);
208         if (ncp_rec && ncp_rec->errors) {
209                 error_string = ncp_error_string(ncp_rec->errors, completion_code);
210         }
211         else if (completion_code == 0) {
212                 error_string = "OK";
213         }
214         else {
215                 error_string = "Not OK";
216         }
217
218         if (check_col(pinfo->fd, COL_INFO)) {
219                 col_add_fstr(pinfo->fd, COL_INFO, "R %s", error_string);
220         }
221
222         if (ncp_tree) {
223
224                 /* Put the func (and maybe subfunc) from the request packet
225                  * in the proto tree, but hidden. That way filters on ncp.func
226                  * or ncp.subfunc will find both the requests and the replies.
227                  */
228                 if (ncp_rec) {
229                         proto_tree_add_uint(ncp_tree, hf_ncp_func, tvb,
230                                         6, 0, ncp_rec->func);
231                         if (ncp_requires_subfunc(ncp_rec->func)) {
232                                 proto_tree_add_uint(ncp_tree, hf_ncp_subfunc,
233                                                 tvb, 6, 0, ncp_rec->subfunc);
234                         }
235                 }
236
237                 proto_tree_add_uint_format(ncp_tree, hf_ncp_completion_code, tvb, 6, 1,
238                         completion_code, "Completion Code: 0x%02x (%s)",
239                         completion_code, error_string);
240
241                 proto_tree_add_item(ncp_tree, hf_ncp_connection_status, tvb, 7, 1, FALSE);
242
243                 length = tvb_length(tvb);
244                 if (!ncp_rec && length > 8) {
245                         proto_tree_add_text(ncp_tree, tvb, 8, length - 8,
246                                         "No request record found. Parsing is impossible.");
247                 }
248                 else if (ncp_rec && ncp_rec->reply_ptvc) {
249                         /* If a non-zero completion code was found, it is
250                          * legal to not have any fields, even if the packet
251                          * type is defined as having fields. */
252                         if (completion_code != 0 && tvb_length(tvb) == 8) {
253                                 return;
254                         }
255
256                         ptvc = ptvcursor_new(ncp_tree, tvb, 8);
257                         process_ptvc_record(ptvc, ncp_rec->reply_ptvc);
258                         ptvcursor_free(ptvc);
259                 }
260         }
261 }