Add support for reading Full Frontal ATM from an ATM Sniffer capture
[obnox/wireshark/wip.git] / packet-atm.c
1 /* packet-atm.c
2  * Routines for ATM packet disassembly
3  *
4  * $Id: packet-atm.c,v 1.1 1999/08/20 06:55:05 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #include <stdio.h>
35 #include <glib.h>
36 #include "packet.h"
37 #include "resolv.h"
38
39 static int proto_atm = -1;
40 static int proto_atm_lane = -1;
41
42 /*
43  * See
44  *
45  *      http://www.atmforum.org/atmforum/specs/approved.html
46  *
47  * for a number of ATM Forum specifications, e.g. the LAN Emulation
48  * over ATM 1.0 spec, whence I got most of this.
49  */
50
51 /* LE Control opcodes */
52 #define LE_CONFIGURE_REQUEST    0x0001
53 #define LE_CONFIGURE_RESPONSE   0x0101
54 #define LE_JOIN_REQUEST         0x0002
55 #define LE_JOIN_RESPONSE        0x0102
56 #define READY_QUERY             0x0003
57 #define READY_IND               0x0103
58 #define LE_REGISTER_REQUEST     0x0004
59 #define LE_REGISTER_RESPONSE    0x0104
60 #define LE_UNREGISTER_REQUEST   0x0005
61 #define LE_UNREGISTER_RESPONSE  0x0105
62 #define LE_ARP_REQUEST          0x0006
63 #define LE_ARP_RESPONSE         0x0106
64 #define LE_FLUSH_REQUEST        0x0007
65 #define LE_FLUSH_RESPONSE       0x0107
66 #define LE_NARP_REQUEST         0x0008
67 #define LE_TOPOLOGY_REQUEST     0x0009
68
69 static const value_string le_control_opcode_vals[] = {
70         { LE_CONFIGURE_REQUEST,   "LE_CONFIGURE_REQUEST" },
71         { LE_CONFIGURE_RESPONSE,  "LE_CONFIGURE_RESPONSE" },
72         { LE_JOIN_REQUEST,        "LE_JOIN_REQUEST" },
73         { LE_JOIN_RESPONSE,       "LE_JOIN_RESPONSE" },
74         { READY_QUERY,            "READY_QUERY" },
75         { READY_IND,              "READY_IND" },
76         { LE_REGISTER_REQUEST,    "LE_REGISTER_REQUEST" },
77         { LE_REGISTER_RESPONSE,   "LE_REGISTER_RESPONSE" },
78         { LE_UNREGISTER_REQUEST,  "LE_UNREGISTER_REQUEST" },
79         { LE_UNREGISTER_RESPONSE, "LE_UNREGISTER_RESPONSE" },
80         { LE_ARP_REQUEST,         "LE_ARP_REQUEST" },
81         { LE_ARP_RESPONSE,        "LE_ARP_RESPONSE" },
82         { LE_FLUSH_REQUEST,       "LE_FLUSH_REQUEST" },
83         { LE_FLUSH_RESPONSE,      "LE_FLUSH_RESPONSE" },
84         { LE_NARP_REQUEST,        "LE_NARP_REQUEST" },
85         { LE_TOPOLOGY_REQUEST,    "LE_TOPOLOGY_REQUEST" },
86         { 0,                      NULL }
87 };
88
89 /* LE Control statuses */
90 static const value_string le_control_status_vals[] = {
91         { 0,  "Success" },
92         { 1,  "Version not supported" },
93         { 2,  "Invalid request parameters" },
94         { 4,  "Duplicate LAN destination registration" },
95         { 5,  "Duplicate ATM address" },
96         { 6,  "Insufficient resources to grant request" },
97         { 7,  "Access denied" },
98         { 8,  "Invalid REQUESTOR-ID" },
99         { 9,  "Invalid LAN destination" },
100         { 10, "Invalid ATM address" },
101         { 20, "No configuraton" },
102         { 21, "LE_CONFIGURE error" },
103         { 22, "Insufficient information" },
104         { 0,  NULL }
105 };
106
107 /* LE Control LAN destination tags */
108 #define TAG_NOT_PRESENT         0x0000
109 #define TAG_MAC_ADDRESS         0x0001
110 #define TAG_ROUTE_DESCRIPTOR    0x0002
111
112 static const value_string le_control_landest_tag_vals[] = {
113         { TAG_NOT_PRESENT,       "Not present" },
114         { TAG_MAC_ADDRESS,       "MAC address" },
115         { TAG_ROUTE_DESCRIPTOR,  "Route descriptor" },
116         { 0,                     NULL }
117 };
118
119 /* LE Control LAN types */
120 #define LANT_UNSPEC     0x00
121 #define LANT_802_3      0x01
122 #define LANT_802_5      0x02
123
124 static const value_string le_control_lan_type_vals[] = {
125         { LANT_UNSPEC, "Unspecified" },
126         { LANT_802_3,  "Ethernet/802.3" },
127         { LANT_802_5,  "802.5" },
128         { 0,           NULL }
129 };
130
131 static void
132 dissect_le_client(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
133 {
134   proto_item *ti;
135   proto_tree *lane_tree;
136
137   if (tree) {
138     ti = proto_tree_add_item_format(tree, proto_atm_lane, offset, 2, NULL,
139                                             "ATM LANE");
140     lane_tree = proto_item_add_subtree(ti, ETT_ATM_LANE);
141
142     proto_tree_add_text(lane_tree, offset, 2, "LE Client: 0x%04X",
143                         pntohs(&pd[offset]));
144   }
145 }
146
147 static void
148 dissect_lan_destination(const u_char *pd, int offset, const char *type, proto_tree *tree) 
149 {
150   proto_item *td;
151   proto_tree *dest_tree;
152   guint16 tag;
153   proto_item *trd;
154   proto_tree *rd_tree;
155   guint16 route_descriptor;
156
157   td = proto_tree_add_text(tree, offset, 8, "%s LAN destination",
158                         type);
159   dest_tree = proto_item_add_subtree(td, ETT_ATM_LANE_LC_LAN_DEST);
160   tag = pntohs(&pd[offset]);
161   proto_tree_add_text(dest_tree, offset, 2, "Tag: %s",
162         val_to_str(tag, le_control_landest_tag_vals,
163                                 "Unknown (%x)"));
164   offset += 2;
165
166   switch (tag) {
167
168   case TAG_MAC_ADDRESS:
169     proto_tree_add_text(dest_tree, offset, 6, "MAC address: %s",
170                         ether_to_str((u_char *)&pd[offset]));
171     break;
172
173   case TAG_ROUTE_DESCRIPTOR:
174     offset += 4;
175     route_descriptor = pntohs(&pd[offset]);
176     trd = proto_tree_add_text(dest_tree, offset, 2, "Route descriptor: 0x%02X",
177                         route_descriptor);
178     rd_tree = proto_item_add_subtree(td, ETT_ATM_LANE_LC_LAN_DEST_RD);
179     proto_tree_add_text(rd_tree, offset, 2,
180             decode_numeric_bitfield(route_descriptor, 0xFFF0, 2*8,
181                         "LAN ID = %u"));
182     proto_tree_add_text(rd_tree, offset, 2,
183             decode_numeric_bitfield(route_descriptor, 0x000F, 2*8,
184                         "Bridge number = %u"));
185     break;
186   }
187 }
188
189 static void
190 dissect_le_control(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
191 {
192   proto_item *ti;
193   proto_tree *lane_tree;
194   proto_item *tf;
195   proto_tree *flags_tree;
196   guint16 opcode;
197   guint16 flags;
198
199   if (check_col(fd, COL_INFO))
200     col_add_str(fd, COL_INFO, "LE Control");
201
202   if (tree) {
203     ti = proto_tree_add_item_format(tree, proto_atm_lane, offset, 108, NULL,
204                                             "ATM LANE");
205     lane_tree = proto_item_add_subtree(ti, ETT_ATM_LANE);
206
207     proto_tree_add_text(lane_tree, offset, 2, "Marker: 0x%04X",
208                         pntohs(&pd[offset]));
209     offset += 2;
210
211     proto_tree_add_text(lane_tree, offset, 1, "Protocol: 0x%02X",
212                         pd[offset]);
213     offset += 1;
214
215     proto_tree_add_text(lane_tree, offset, 1, "Version: 0x%02X",
216                         pd[offset]);
217     offset += 1;
218
219     opcode = pntohs(&pd[offset]);
220     proto_tree_add_text(lane_tree, offset, 2, "Opcode: %s",
221         val_to_str(opcode, le_control_opcode_vals,
222                                 "Unknown (%x)"));
223     offset += 2;
224
225     if (opcode == READY_QUERY || opcode == READY_IND) {
226       /* There's nothing more in this packet. */
227       return;
228     }
229
230     if (opcode & 0x0100) {
231       /* Response; decode status. */
232       proto_tree_add_text(lane_tree, offset, 2, "Status: %s",
233         val_to_str(pntohs(&pd[offset]), le_control_status_vals,
234                                 "Unknown (%x)"));
235     }
236     offset += 2;
237
238     proto_tree_add_text(lane_tree, offset, 4, "Transaction ID: 0x%08X",
239                         pntohl(&pd[offset]));
240     offset += 4;
241
242     proto_tree_add_text(lane_tree, offset, 2, "Requester LECID: 0x%04X",
243                         pntohs(&pd[offset]));
244     offset += 2;
245
246     flags = pntohs(&pd[offset]);
247     tf = proto_tree_add_text(lane_tree, offset, 2, "Flags: 0x%04X",
248                         pntohs(&pd[offset]));
249     flags_tree = proto_item_add_subtree(tf, ETT_ATM_LANE_LC_FLAGS);
250     proto_tree_add_text(flags_tree, offset, 2, "%s",
251         decode_boolean_bitfield(flags, 0x0001, 8*2,
252                                 "Remote address", "Local address"));
253     proto_tree_add_text(flags_tree, offset, 2, "%s",
254         decode_boolean_bitfield(flags, 0x0080, 8*2,
255                                 "Proxy", "Not proxy"));
256     proto_tree_add_text(flags_tree, offset, 2, "%s",
257         decode_boolean_bitfield(flags, 0x0100, 8*2,
258                                 "Topology change", "No topology change"));
259     offset += 2;
260
261     dissect_lan_destination(pd, offset, "Source", lane_tree);
262     offset += 8;
263
264     dissect_lan_destination(pd, offset, "Target", lane_tree);
265     offset += 8;
266
267     proto_tree_add_text(lane_tree, offset, 20, "Source ATM Address: %s",
268                         bytes_to_str(&pd[offset], 20));
269     offset += 20;
270
271     proto_tree_add_text(lane_tree, offset, 1, "LAN type: %s",
272         val_to_str(pd[offset], le_control_lan_type_vals,
273                                 "Unknown (%x)"));
274     offset += 1;
275
276     proto_tree_add_text(lane_tree, offset, 1, "Maximum frame size: %u",
277                         pd[offset]);
278     offset += 1;
279
280     proto_tree_add_text(lane_tree, offset, 1, "Number of TLVs: %u",
281                         pd[offset]);
282     offset += 1;
283
284     proto_tree_add_text(lane_tree, offset, 1, "ELAN name size: %u",
285                         pd[offset]);
286     offset += 1;
287
288     proto_tree_add_text(lane_tree, offset, 20, "Target ATM Address: %s",
289                         bytes_to_str(&pd[offset], 20));
290     offset += 20;
291
292     proto_tree_add_text(lane_tree, offset, 32, "ELAN name: %s",
293                         bytes_to_str(&pd[offset], 32));
294     offset += 32;
295   }
296 }
297
298 static void
299 dissect_lane(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
300 {
301   if (check_col(fd, COL_PROTOCOL))
302     col_add_str(fd, COL_PROTOCOL, "ATM LANE");
303   if (check_col(fd, COL_INFO))
304     col_add_str(fd, COL_INFO, "ATM LANE");
305
306   /* Is it LE Control, 802.3, 802.5, or "none of the above"? */
307   switch (fd->pseudo_header.ngsniffer_atm.AppHLType) {
308
309   case AHLT_LANE_LE_CTRL:
310     dissect_le_control(pd, offset, fd, tree);
311     break;
312
313   case AHLT_LANE_802_3:
314   case AHLT_LANE_802_3_MC:
315     dissect_le_client(pd, offset, fd, tree);
316     offset += 2;
317
318     /* Dissect as Ethernet */
319     dissect_eth(pd, offset, fd, tree);
320     break;
321
322   case AHLT_LANE_802_5:
323   case AHLT_LANE_802_5_MC:
324     dissect_le_client(pd, offset, fd, tree);
325     offset += 2;
326
327     /* Dissect as Token-Ring */
328     dissect_tr(pd, offset, fd, tree);
329     break;
330
331   default:
332     /* Dump it as raw data. */
333     dissect_data(pd, offset, fd, tree);
334     break;
335   }
336 }
337
338 /* AAL types */
339 static const value_string aal_vals[] = {
340         { ATT_AAL_UNKNOWN,    "Unknown AAL" },
341         { ATT_AAL1,           "AAL1" },
342         { ATT_AAL3_4,         "AAL3/4" },
343         { ATT_AAL5,           "AAL5" },
344         { ATT_AAL_USER,       "User AAL" },
345         { ATT_AAL_SIGNALLING, "Signalling AAL" },
346         { ATT_OAMCELL,        "OAM cell" },
347         { 0,                  NULL }
348 };
349
350 /* AAL5 higher-level traffic types */
351 static const value_string aal5_hltype_vals[] = {
352         { ATT_HL_UNKNOWN, "Unknown traffic type" },
353         { ATT_HL_LLCMX,   "LLC multiplexed" },
354         { ATT_HL_VCMX,    "VC multiplexed" },
355         { ATT_HL_LANE,    "LANE" },
356         { ATT_HL_ILMI,    "ILMI" },
357         { ATT_HL_FRMR,    "Frame Relay" },
358         { ATT_HL_SPANS,   "FORE SPANS" },
359         { ATT_HL_IPSILON, "Ipsilon" },
360         { 0,              NULL }
361 };
362
363 /* Traffic subtypes for VC multiplexed traffic */
364 static const value_string vcmx_type_vals[] = {
365         { AHLT_UNKNOWN,        "Unknown VC multiplexed traffic type" },
366         { AHLT_VCMX_802_3_FCS, "802.3 FCS" },
367         { AHLT_VCMX_802_4_FCS, "802.4 FCS" },
368         { AHLT_VCMX_802_5_FCS, "802.5 FCS" },
369         { AHLT_VCMX_FDDI_FCS,  "FDDI FCS" },
370         { AHLT_VCMX_802_6_FCS, "802.6 FCS" },
371         { AHLT_VCMX_802_3,     "802.3" },
372         { AHLT_VCMX_802_4,     "802.4" },
373         { AHLT_VCMX_802_5,     "802.5" },
374         { AHLT_VCMX_FDDI,      "FDDI" },
375         { AHLT_VCMX_802_6,     "802.6" },
376         { AHLT_VCMX_FRAGMENTS, "Fragments" },
377         { AHLT_VCMX_BPDU,      "BPDU" },
378         { 0,                   NULL }
379 };
380
381 /* Traffic subtypes for LANE traffic */
382 static const value_string lane_type_vals[] = {
383         { AHLT_UNKNOWN,       "Unknown LANE traffic type" },
384         { AHLT_LANE_LE_CTRL,  "LE Control" },
385         { AHLT_LANE_802_3,    "802.3" },
386         { AHLT_LANE_802_5,    "802.5" },
387         { AHLT_LANE_802_3_MC, "802.3 multicast" },
388         { AHLT_LANE_802_5_MC, "802.5 multicast" },
389         { 0,                  NULL }
390 };
391
392 /* Traffic subtypes for Ipsilon traffic */
393 static const value_string ipsilon_type_vals[] = {
394         { AHLT_UNKNOWN,     "Unknown Ipsilon traffic type" },
395         { AHLT_IPSILON_FT0, "Flow type 0" },
396         { AHLT_IPSILON_FT1, "Flow type 1" },
397         { AHLT_IPSILON_FT2, "Flow type 2" },
398         { 0,                NULL }
399 };
400
401 void
402 dissect_atm(const u_char *pd, frame_data *fd, proto_tree *tree) 
403 {
404   int        offset = 0;
405   proto_tree *atm_tree;
406   proto_item *ti;
407   guint       aal_type;
408   guint       hl_type;
409
410   aal_type = fd->pseudo_header.ngsniffer_atm.AppTrafType & ATT_AALTYPE;
411   hl_type = fd->pseudo_header.ngsniffer_atm.AppTrafType & ATT_HLTYPE;
412
413   if (check_col(fd, COL_PROTOCOL))
414     col_add_str(fd, COL_PROTOCOL, "ATM");
415
416   switch (fd->pseudo_header.ngsniffer_atm.channel) {
417
418   case 0:
419     /* Traffic from DCE to DTE. */
420     if (check_col(fd, COL_RES_DL_DST))
421       col_add_str(fd, COL_RES_DL_DST, "DTE");
422     if (check_col(fd, COL_RES_DL_SRC))
423       col_add_str(fd, COL_RES_DL_SRC, "DCE");
424     break;
425
426   case 1:
427     /* Traffic from DTE to DCE. */
428     if (check_col(fd, COL_RES_DL_DST))
429       col_add_str(fd, COL_RES_DL_DST, "DCE");
430     if (check_col(fd, COL_RES_DL_SRC))
431       col_add_str(fd, COL_RES_DL_SRC, "DTE");
432     break;
433   }
434
435   if (check_col(fd, COL_INFO)) {
436     if (aal_type == ATT_AAL5) {
437       col_add_fstr(fd, COL_INFO, "AAL5 %s",
438                 val_to_str(hl_type, aal5_hltype_vals,
439                                 "Unknown traffic type (%x)"));
440     } else {
441       col_add_str(fd, COL_INFO,
442                 val_to_str(aal_type, aal_vals, "Unknown AAL (%x)"));
443     }
444   }
445
446   if (tree) {
447     ti = proto_tree_add_item_format(tree, proto_atm, 0, 0, NULL,
448                                             "ATM");
449     atm_tree = proto_item_add_subtree(ti, ETT_ATM);
450
451     proto_tree_add_text(atm_tree, 0, 0, "AAL: %s",
452         val_to_str(aal_type, aal_vals, "Unknown AAL (%x)"));
453     if (aal_type == ATT_AAL5) {
454       proto_tree_add_text(atm_tree, 0, 0, "Traffic type: %s",
455         val_to_str(hl_type, aal5_hltype_vals, "Unknown AAL5 traffic type (%x)"));
456     }
457     if (aal_type == ATT_AAL5) {
458       switch (hl_type) {
459
460       case ATT_HL_VCMX:
461         proto_tree_add_text(atm_tree, 0, 0, "VC multiplexed traffic type: %s",
462                 val_to_str(fd->pseudo_header.ngsniffer_atm.AppHLType,
463                         vcmx_type_vals, "Unknown VCMX traffic type (%x)"));
464         break;
465
466       case ATT_HL_LANE:
467         proto_tree_add_text(atm_tree, 0, 0, "LANE traffic type: %s",
468                 val_to_str(fd->pseudo_header.ngsniffer_atm.AppHLType,
469                         lane_type_vals, "Unknown LANE traffic type (%x)"));
470         break;
471
472       case ATT_HL_IPSILON:
473         proto_tree_add_text(atm_tree, 0, 0, "Ipsilon traffic type: %s",
474                 val_to_str(fd->pseudo_header.ngsniffer_atm.AppHLType,
475                         ipsilon_type_vals, "Unknown Ipsilon traffic type (%x)"));
476         break;
477       }
478     }
479     proto_tree_add_text(atm_tree, 0, 0, "VPI: %u",
480                 fd->pseudo_header.ngsniffer_atm.Vpi);
481     proto_tree_add_text(atm_tree, 0, 0, "VCI: %u",
482                 fd->pseudo_header.ngsniffer_atm.Vci);
483     switch (fd->pseudo_header.ngsniffer_atm.channel) {
484
485     case 0:
486       /* Traffic from DCE to DTE. */
487       proto_tree_add_text(atm_tree, 0, 0, "Channel: DCE->DTE");
488       break;
489
490     case 1:
491       /* Traffic from DTE to DCE. */
492       proto_tree_add_text(atm_tree, 0, 0, "Channel: DTE->DCE");
493       break;
494
495     default:
496       /* Sniffers shouldn't provide anything other than 0 or 1. */
497       proto_tree_add_text(atm_tree, 0, 0, "Channel: %u",
498                 fd->pseudo_header.ngsniffer_atm.channel);
499       break;
500     }
501     proto_tree_add_text(atm_tree, 0, 0, "Cells: %u",
502                 fd->pseudo_header.ngsniffer_atm.cells);
503     if (aal_type == ATT_AAL5) {
504       proto_tree_add_text(atm_tree, 0, 0, "AAL5 U2U: %u",
505                 fd->pseudo_header.ngsniffer_atm.aal5t_u2u);
506       proto_tree_add_text(atm_tree, 0, 0, "AAL5 len: %u",
507                 fd->pseudo_header.ngsniffer_atm.aal5t_len);
508       proto_tree_add_text(atm_tree, 0, 0, "AAL5 checksum: 0x%08X",
509                 fd->pseudo_header.ngsniffer_atm.aal5t_chksum);
510     }
511   }
512
513   if (aal_type == ATT_AAL5) {
514     switch (hl_type) {
515
516 #if 0
517     case ATT_HL_LLCMX:
518       /* Dissect as WTAP_ENCAP_ATM_RFC1483 */
519       break;
520 #endif
521
522     case ATT_HL_LANE:
523       dissect_lane(pd, offset, fd, tree);
524       break;
525
526     default:
527       if (tree) {
528         /* Dump it as raw data. */
529         dissect_data(pd, offset, fd, tree);
530         break;
531       }
532     }
533   } else {
534     if (tree) {
535       /* Dump it as raw data.  (Is this a single cell?) */
536       dissect_data(pd, offset, fd, tree);
537     }
538   }
539 }
540
541 void
542 proto_register_atm(void)
543 {
544         proto_atm = proto_register_protocol("ATM", "atm");
545         proto_atm_lane = proto_register_protocol("ATM LANE", "lane");
546 }