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