Olivier Abad's patch to add dissectors for LAP-B and X.25, and wiretap
[obnox/wireshark/wip.git] / packet-lapb.c
1 /* packet-lapb.c
2  * Routines for lapb frame disassembly
3  * Olivier Abad <abad@daba.dhis.org>
4  *
5  * Ethereal - Network traffic analyzer
6  * By Gerald Combs <gerald@zing.org>
7  * Copyright 1998
8  *
9  * 
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
31 #endif
32
33 #include <stdio.h>
34 #include <glib.h>
35 #include <string.h>
36 #include "packet.h"
37
38 #define LAPB_I          0x00    /* Information frames */
39 #define LAPB_S          0x01    /* Supervisory frames */
40 #define LAPB_U          0x03    /* Unnumbered frames */
41
42 #define LAPB_RR         0x01    /* Receiver ready */
43 #define LAPB_RNR        0x05    /* Receiver not ready */
44 #define LAPB_REJ        0x09    /* Reject */
45 #define LAPB_SABM       0x2F    /* Set Asynchronous Balanced Mode */
46 #define LAPB_SABME      0x6F    /* Set Asynchronous Balanced Mode Extended */
47 #define LAPB_DISC       0x43    /* Disconnect */
48 #define LAPB_DM         0x0F    /* Disconnected mode */
49 #define LAPB_UA         0x63    /* Unnumbered acknowledge */
50 #define LAPB_FRMR       0x87    /* Frame reject */
51
52 #define FROM_DCE        0x80
53
54 int proto_lapb = -1;
55 int hf_lapb_address = -1;
56 int hf_lapb_control = -1;
57
58 void
59 dissect_lapb(const u_char *pd, frame_data *fd, proto_tree *tree)
60 {
61     proto_tree *lapb_tree, *ti;
62     char lapb_addr[3];
63     char info[80];
64
65     if (check_col(fd, COL_PROTOCOL))
66         col_add_str(fd, COL_PROTOCOL, "LAPB");
67
68     sprintf(lapb_addr, "%2d", (int)pd[0]);
69     if(check_col(fd, COL_RES_DL_SRC))
70         col_add_str(fd, COL_RES_DL_SRC, lapb_addr);
71
72     switch (pd[1] & 0x0F) {
73     case LAPB_RR:
74         if(check_col(fd, COL_INFO)) {
75             sprintf(info, "RR N(R):%d", (pd[1] >> 5) & 0x7);
76             if ((pd[1] >> 4) && 0x01) { /* P/F bit */
77                 if (((fd->flags & FROM_DCE) && pd[0] == 0x01) ||
78                     (!(fd->flags & FROM_DCE) && pd[0] == 0x03))
79                     strcat(info, " F");
80                 else
81                     strcat(info, " P");
82             }
83             col_add_str(fd, COL_INFO, info);
84         }
85         if (fd->flags & FROM_DCE) {
86             if(check_col(fd, COL_RES_DL_DST))
87                 col_add_str(fd, COL_RES_DL_DST, "DTE");
88             if(check_col(fd, COL_RES_DL_SRC))
89                 col_add_str(fd, COL_RES_DL_SRC, "DCE");
90         }
91         else {
92             if(check_col(fd, COL_RES_DL_DST))
93                 col_add_str(fd, COL_RES_DL_DST, "DCE");
94             if(check_col(fd, COL_RES_DL_SRC))
95                 col_add_str(fd, COL_RES_DL_SRC, "DTE");
96         }
97         if (tree)
98         {
99             ti = proto_tree_add_item_format(tree, proto_lapb, 0, 2, NULL,
100                                             "LAPB");
101             lapb_tree = proto_item_add_subtree(ti, ETT_LAPB);
102             proto_tree_add_item_format(lapb_tree, hf_lapb_address, 0, 1, pd[0],
103                                        "Address : 0x%02X", (int)pd[0]);
104             proto_tree_add_item_format(lapb_tree, hf_lapb_control, 1, 1, "RR",
105                                        "Control field : 0x%02X", (int)pd[1]);
106             proto_tree_add_text(lapb_tree, 1, 1,
107                                 "     %d%d%d..... : N(R) = %d",
108                                 (pd[1] >> 7) & 0x1,
109                                 (pd[1] >> 6) & 0x1,
110                                 (pd[1] >> 5) & 0x1,
111                                 (pd[1] >> 5) & 0x7);
112             proto_tree_add_text(lapb_tree, 1, 1,
113                                 "     ...%d.... : Poll/Final bit",
114                                 (pd[1] >> 4) & 0x1);
115             proto_tree_add_text(lapb_tree, 1, 1,
116                                 "     ....0001 : Receive Ready (RR)");
117         }
118         return;
119     case LAPB_RNR:
120         if(check_col(fd, COL_INFO)) {
121             sprintf(info, "RNR N(R):%d", (pd[1] >> 5) & 0x7);
122             if ((pd[1] >> 4) && 0x01) { /* P/F bit */
123                 if (((fd->flags & FROM_DCE) && pd[0] == 0x01) ||
124                     (!(fd->flags & FROM_DCE) && pd[0] == 0x03))
125                     strcat(info, " F");
126                 else
127                     strcat(info, " P");
128             }
129             col_add_str(fd, COL_INFO, info);
130         }
131         if (fd->flags & FROM_DCE) {
132             if(check_col(fd, COL_RES_DL_DST))
133                 col_add_str(fd, COL_RES_DL_DST, "DTE");
134             if(check_col(fd, COL_RES_DL_SRC))
135                 col_add_str(fd, COL_RES_DL_SRC, "DCE");
136         }
137         else {
138             if(check_col(fd, COL_RES_DL_DST))
139                 col_add_str(fd, COL_RES_DL_DST, "DCE");
140             if(check_col(fd, COL_RES_DL_SRC))
141                 col_add_str(fd, COL_RES_DL_SRC, "DTE");
142         }
143         if (tree)
144         {
145             ti = proto_tree_add_item_format(tree, proto_lapb, 0, 2, NULL,
146                                             "LAPB");
147             lapb_tree = proto_item_add_subtree(ti, ETT_LAPB);
148             proto_tree_add_item_format(lapb_tree, hf_lapb_address, 0, 1, pd[0],
149                                        "Address : 0x%02X", (int)pd[0]);
150             proto_tree_add_item_format(lapb_tree, hf_lapb_control, 1, 1, "RNR",
151                                        "Control field : 0x%02X", (int)pd[1]);
152             proto_tree_add_text(lapb_tree, 1, 1,
153                                 "     %d%d%d..... : N(R) = %d",
154                                 (pd[1] >> 7) & 0x1,
155                                 (pd[1] >> 6) & 0x1,
156                                 (pd[1] >> 5) & 0x1,
157                                 (pd[1] >> 5) & 0x7);
158             proto_tree_add_text(lapb_tree, 1, 1,
159                                 "     ...%d.... : Poll/Final bit",
160                                 (pd[1] >> 4) & 0x1);
161             proto_tree_add_text(lapb_tree, 1, 1,
162                                 "     ....0101 : Receive Not Ready (RNR)");
163         }
164         return;
165     case LAPB_REJ:
166         if(check_col(fd, COL_INFO)) {
167             sprintf(info, "REJ N(R):%d", (pd[1] >> 5) & 0x7);
168             if ((pd[1] >> 4) && 0x01) { /* P/F bit */
169                 if (((fd->flags & FROM_DCE) && pd[0] == 0x01) ||
170                     (!(fd->flags & FROM_DCE) && pd[0] == 0x03))
171                     strcat(info, " F");
172                 else
173                     strcat(info, " P");
174             }
175             col_add_str(fd, COL_INFO, info);
176         }
177         if (fd->flags & FROM_DCE) {
178             if(check_col(fd, COL_RES_DL_DST))
179                 col_add_str(fd, COL_RES_DL_DST, "DTE");
180             if(check_col(fd, COL_RES_DL_SRC))
181                 col_add_str(fd, COL_RES_DL_SRC, "DCE");
182         }
183         else {
184             if(check_col(fd, COL_RES_DL_DST))
185                 col_add_str(fd, COL_RES_DL_DST, "DCE");
186             if(check_col(fd, COL_RES_DL_SRC))
187                 col_add_str(fd, COL_RES_DL_SRC, "DTE");
188         }
189         if (tree)
190         {
191             ti = proto_tree_add_item_format(tree, proto_lapb, 0, 2, NULL,
192                                             "LAPB");
193             lapb_tree = proto_item_add_subtree(ti, ETT_LAPB);
194             proto_tree_add_item_format(lapb_tree, hf_lapb_address, 0, 1, pd[0],
195                                        "Address : 0x%02X", (int)pd[0]);
196             proto_tree_add_item_format(lapb_tree, hf_lapb_control, 1, 1, "REJ",
197                                        "Control field : 0x%02X", (int)pd[1]);
198             proto_tree_add_text(lapb_tree, 1, 1,
199                                 "     %d%d%d..... : N(R) = %d",
200                                 (pd[1] >> 7) & 0x1,
201                                 (pd[1] >> 6) & 0x1,
202                                 (pd[1] >> 5) & 0x1,
203                                 (pd[1] >> 5) & 0x7);
204             proto_tree_add_text(lapb_tree, 1, 1,
205                                 "     ...%d.... : Poll/Final bit",
206                                 (pd[1] >> 4) & 0x1);
207             proto_tree_add_text(lapb_tree, 1, 1,
208                                 "     ....1001 : Reeject (REJ)");
209         }
210         return;
211     }
212
213     /* not a RR/RNR/REJ frame */
214
215     if (pd[1] & 0x01) { /* not an information frame */
216         switch (pd[1] & 0xEF) { /* don't check Poll/Final bit */
217         case LAPB_SABM:
218             if (fd->flags & FROM_DCE) {
219                 if(check_col(fd, COL_RES_DL_DST))
220                     col_add_str(fd, COL_RES_DL_DST, "DTE");
221                 if(check_col(fd, COL_RES_DL_SRC))
222                     col_add_str(fd, COL_RES_DL_SRC, "DCE");
223             }
224             else {
225                 if(check_col(fd, COL_RES_DL_DST))
226                     col_add_str(fd, COL_RES_DL_DST, "DCE");
227                 if(check_col(fd, COL_RES_DL_SRC))
228                     col_add_str(fd, COL_RES_DL_SRC, "DTE");
229             }
230             if(check_col(fd, COL_INFO)) {
231                 if (pd[1] & 0x10)
232                     col_add_str(fd, COL_INFO, "SABM P");
233                 else
234                     col_add_str(fd, COL_INFO, "SABM");
235             }
236             if (tree) {
237                 ti = proto_tree_add_item_format(tree, proto_lapb, 0, 2, NULL,
238                                                 "LAPB");
239                 lapb_tree = proto_item_add_subtree(ti, ETT_LAPB);
240                 proto_tree_add_item_format(lapb_tree, hf_lapb_address, 0, 1,
241                                            pd[0], "Address: 0x%02X",
242                                            (int)pd[0]);
243                 proto_tree_add_item_format(lapb_tree, hf_lapb_control, 1, 1,
244                                            "SABM",
245                                            "Set Asynchronous Balanced Mode (SABM)");
246                 proto_tree_add_text(lapb_tree, 1, 1,
247                                     "...%d.... : Poll bit",
248                                     (pd[1] >> 4) & 0x1);
249             }
250             break;
251         case LAPB_DISC:
252             if (fd->flags & FROM_DCE) {
253                 if(check_col(fd, COL_RES_DL_DST))
254                     col_add_str(fd, COL_RES_DL_DST, "DTE");
255                 if(check_col(fd, COL_RES_DL_SRC))
256                     col_add_str(fd, COL_RES_DL_SRC, "DCE");
257             }
258             else {
259                 if(check_col(fd, COL_RES_DL_DST))
260                     col_add_str(fd, COL_RES_DL_DST, "DCE");
261                 if(check_col(fd, COL_RES_DL_SRC))
262                     col_add_str(fd, COL_RES_DL_SRC, "DTE");
263             }
264             if(check_col(fd, COL_INFO)) {
265                 if (pd[1] & 0x10)
266                     col_add_str(fd, COL_INFO, "DISC P");
267                 else
268                     col_add_str(fd, COL_INFO, "DISC");
269             }
270             if (tree) {
271                 ti = proto_tree_add_item_format(tree, proto_lapb, 0, 2, NULL,
272                                                 "LAPB");
273                 lapb_tree = proto_item_add_subtree(ti, ETT_LAPB);
274                 proto_tree_add_item_format(lapb_tree, hf_lapb_address, 0, 1,
275                                            pd[0], "Address: 0x%02X",
276                                            (int)pd[0]);
277                 proto_tree_add_item_format(lapb_tree, hf_lapb_control, 1, 1,
278                                            "DISC", "Disconnect (DISC)");
279                 proto_tree_add_text(lapb_tree, 1, 1,
280                                     "...%d.... : Poll bit",
281                                     (pd[1] >> 4) & 0x1);
282             }
283             break;
284         case LAPB_DM:
285             if (fd->flags & FROM_DCE) {
286                 if(check_col(fd, COL_RES_DL_DST))
287                     col_add_str(fd, COL_RES_DL_DST, "DTE");
288                 if(check_col(fd, COL_RES_DL_SRC))
289                     col_add_str(fd, COL_RES_DL_SRC, "DCE");
290             }
291             else {
292                 if(check_col(fd, COL_RES_DL_DST))
293                     col_add_str(fd, COL_RES_DL_DST, "DCE");
294                 if(check_col(fd, COL_RES_DL_SRC))
295                     col_add_str(fd, COL_RES_DL_SRC, "DTE");
296             }
297             if(check_col(fd, COL_INFO)) {
298                 if (pd[1] & 0x10)
299                     col_add_str(fd, COL_INFO, "DM F");
300                 else
301                     col_add_str(fd, COL_INFO, "DM");
302             }
303             if (tree) {
304                 ti = proto_tree_add_item_format(tree, proto_lapb, 0, 2, NULL,
305                                                 "LAPB");
306                 lapb_tree = proto_item_add_subtree(ti, ETT_LAPB);
307                 proto_tree_add_item_format(lapb_tree, hf_lapb_address, 0, 1,
308                                            pd[0], "Address: 0x%02X",
309                                            (int)pd[0]);
310                 proto_tree_add_item_format(lapb_tree, hf_lapb_control, 1, 1,
311                                            "DM", "Disconnect Mode (DM)");
312                 proto_tree_add_text(lapb_tree, 1, 1,
313                                     "...%d.... : Final bit",
314                                     (pd[1] >> 4) & 0x1);
315             }
316             break;
317         case LAPB_UA:
318             if (fd->flags & FROM_DCE) {
319                 if(check_col(fd, COL_RES_DL_DST))
320                     col_add_str(fd, COL_RES_DL_DST, "DTE");
321                 if(check_col(fd, COL_RES_DL_SRC))
322                     col_add_str(fd, COL_RES_DL_SRC, "DCE");
323             }
324             else {
325                 if(check_col(fd, COL_RES_DL_DST))
326                     col_add_str(fd, COL_RES_DL_DST, "DCE");
327                 if(check_col(fd, COL_RES_DL_SRC))
328                     col_add_str(fd, COL_RES_DL_SRC, "DTE");
329             }
330             if(check_col(fd, COL_INFO)) {
331                 if (pd[1] & 0x10)
332                     col_add_str(fd, COL_INFO, "UA F");
333                 else
334                     col_add_str(fd, COL_INFO, "UA");
335             }
336             if (tree) {
337                 ti = proto_tree_add_item_format(tree, proto_lapb, 0, 2, NULL,
338                                                 "LAPB");
339                 lapb_tree = proto_item_add_subtree(ti, ETT_LAPB);
340                 proto_tree_add_item_format(lapb_tree, hf_lapb_address, 0, 1,
341                                            pd[0], "Address: 0x%02X",
342                                            (int)pd[0]);
343                 proto_tree_add_item_format(lapb_tree, hf_lapb_control, 1, 1,
344                                            "UA", "Unnumbered Acknowledge (UA)");
345                 proto_tree_add_text(lapb_tree, 1, 1,
346                                     "...%d.... : Final bit",
347                                     (pd[1] >> 4) & 0x1);
348             }
349             break;
350         case LAPB_FRMR:
351             if (fd->flags & FROM_DCE) {
352                 if(check_col(fd, COL_RES_DL_DST))
353                     col_add_str(fd, COL_RES_DL_DST, "DTE");
354                 if(check_col(fd, COL_RES_DL_SRC))
355                     col_add_str(fd, COL_RES_DL_SRC, "DCE");
356             }
357             else {
358                 if(check_col(fd, COL_RES_DL_DST))
359                     col_add_str(fd, COL_RES_DL_DST, "DCE");
360                 if(check_col(fd, COL_RES_DL_SRC))
361                     col_add_str(fd, COL_RES_DL_SRC, "DTE");
362             }
363             if(check_col(fd, COL_INFO)) {
364                 if (pd[1] & 0x10)
365                     col_add_str(fd, COL_INFO, "FRMR F");
366                 else
367                     col_add_str(fd, COL_INFO, "FRMR");
368             }
369             if (tree) {
370                 ti = proto_tree_add_item_format(tree, proto_lapb, 0, 2, NULL,
371                                                 "LAPB");
372                 lapb_tree = proto_item_add_subtree(ti, ETT_LAPB);
373                 proto_tree_add_item_format(lapb_tree, hf_lapb_address, 0, 1,
374                                            pd[0], "Address: 0x%02X",
375                                            (int)pd[0]);
376                 proto_tree_add_item_format(lapb_tree, hf_lapb_control, 1, 1,
377                                            "FRMR", "Frame Reject (FRMR)");
378                 proto_tree_add_text(lapb_tree, 1, 1,
379                                     "...%d.... : Final bit",
380                                     (pd[1] >> 4) & 0x1);
381             }
382             break;
383         }
384     }
385     else /* information frame */
386     {
387         if (fd->flags & FROM_DCE) {
388             if(check_col(fd, COL_RES_DL_DST))
389                 col_add_str(fd, COL_RES_DL_DST, "DTE");
390             if(check_col(fd, COL_RES_DL_SRC))
391                 col_add_str(fd, COL_RES_DL_SRC, "DCE");
392         }
393         else {
394             if(check_col(fd, COL_RES_DL_DST))
395                 col_add_str(fd, COL_RES_DL_DST, "DCE");
396             if(check_col(fd, COL_RES_DL_SRC))
397                 col_add_str(fd, COL_RES_DL_SRC, "DTE");
398         }
399         if(check_col(fd, COL_INFO)) {
400             sprintf(info, "I N(R):%d N(S):%d",
401                     (pd[1] >> 5) & 0x7,
402                     (pd[1] >> 1) & 0x7);
403             if ((pd[1] >> 4) && 0x01) /* P/F bit */
404                 strcat(info, " P");
405             col_add_str(fd, COL_INFO, info);
406         }
407         if (tree) {
408             ti = proto_tree_add_item_format(tree, proto_lapb, 0, 2, NULL,
409                                             "LAPB");
410             lapb_tree = proto_item_add_subtree(ti, ETT_LAPB);
411             proto_tree_add_item_format(lapb_tree, hf_lapb_address, 0, 1,
412                                        pd[0], "Address: 0x%02X",
413                                        (int)pd[0]);
414             proto_tree_add_item_format(lapb_tree, hf_lapb_control, 1, 1,
415                                        "I", "Control field : 0x%02X",
416                                        (int)pd[1]);
417             proto_tree_add_text(lapb_tree, 1, 1,
418                                 "     %d%d%d..... : N(R) = %d",
419                                 (pd[1] >> 7) & 0x1,
420                                 (pd[1] >> 6) & 0x1,
421                                 (pd[1] >> 5) & 0x1,
422                                 (pd[1] >> 5) & 0x7);
423             proto_tree_add_text(lapb_tree, 1, 1,
424                                 "     ...%d.... : Poll/Final bit",
425                                 (pd[1] >> 4) & 0x1);
426             proto_tree_add_text(lapb_tree, 1, 1,
427                                 "     ....%d%d%d. : N(S) = %d",
428                                 (pd[1] >> 3) & 0x1,
429                                 (pd[1] >> 2) & 0x1,
430                                 (pd[1] >> 1) & 0x1,
431                                 (pd[1] >> 1) & 0x7);
432             proto_tree_add_text(lapb_tree, 1, 1,
433                                 "     .......0 : Information Transfer (I)");
434         }
435     }
436
437     /* not end of frame ==> X.25 */
438     if (fd->cap_len > 2) dissect_x25(pd, 2, fd, tree);
439 }
440
441 void
442 proto_register_lapb(void)
443 {
444     static hf_register_info hf[] = {
445         { &hf_lapb_address,
446           { "Address Field", "lapb.address", FT_UINT8, NULL} },
447         { &hf_lapb_control,
448           { "Control Field", "lapb.control", FT_STRING, NULL} },
449     };
450
451     proto_lapb = proto_register_protocol ("LAPB", "lapb");
452     proto_register_field_array (proto_lapb, hf, array_length(hf));
453 }