warning: ISO C does not allow extra ; outside of a function
[obnox/wireshark/wip.git] / packet-mip.c
1 /* packet-mip.c
2  * Routines for Mobile IP dissection
3  * Copyright 2000, Stefan Raab <sraab@cisco.com>
4  *
5  * $Id: packet-mip.c,v 1.35 2003/12/21 05:51:33 jmayer Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
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 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include <string.h>
34 #include <glib.h>
35 #include <time.h>
36
37 #include <epan/packet.h>
38
39 /* Initialize the protocol and registered fields */
40 static int proto_mip = -1;
41 static int hf_mip_type = -1;
42 static int hf_mip_flags = -1;
43 static int hf_mip_s = -1;
44 static int hf_mip_b = -1;
45 static int hf_mip_d = -1;
46 static int hf_mip_m = -1;
47 static int hf_mip_g = -1;
48 static int hf_mip_v = -1;
49 static int hf_mip_t = -1;
50 static int hf_mip_code = -1;
51 static int hf_mip_life = -1;
52 static int hf_mip_homeaddr = -1;
53 static int hf_mip_haaddr = -1;
54 static int hf_mip_coa = -1;
55 static int hf_mip_ident = -1;
56 static int hf_mip_ext_type = -1;
57 static int hf_mip_ext_stype = -1;
58 static int hf_mip_ext_len = -1;
59 static int hf_mip_ext = -1;
60 static int hf_mip_aext_spi = -1;
61 static int hf_mip_aext_auth = -1;
62 static int hf_mip_next_nai = -1;
63
64 /* Initialize the subtree pointers */
65 static gint ett_mip = -1;
66 static gint ett_mip_flags = -1;
67 static gint ett_mip_ext = -1;
68 static gint ett_mip_exts = -1;
69
70 /* Port used for Mobile IP */
71 #define UDP_PORT_MIP    434
72 #define NTP_BASETIME 2208988800ul
73
74 typedef enum {
75     REGISTRATION_REQUEST = 1,
76     REGISTRATION_REPLY = 3
77 } mipMessageTypes;
78
79 static const value_string mip_types[] = {
80   {REGISTRATION_REQUEST, "Registration Request"},
81   {REGISTRATION_REPLY,   "Registration Reply"},
82   {0, NULL},
83 };
84
85 static const value_string mip_reply_codes[]= {
86   {0, "Reg Accepted"},
87   {1, "Reg Accepted, but Simultaneous Bindings Unsupported."},
88   {64, "Reg Deny (FA)- Unspecified Reason"},
89   {65, "Reg Deny (FA)- Administratively Prohibited"},
90   {66, "Reg Deny (FA)- Insufficient Resources"},
91   {67, "Reg Deny (FA)- MN failed Authentication"},
92   {68, "Reg Deny (FA)- HA failed Authentication"},
93   {69, "Reg Deny (FA)- Requested Lifetime too Long"},
94   {70, "Reg Deny (FA)- Poorly Formed Request"},
95   {71, "Reg Deny (FA)- Poorly Formed Reply"},
96   {72, "Reg Deny (FA)- Requested Encapsulation Unavailable"},
97   {73, "Reg Deny (FA)- VJ Compression Unavailable"},
98   {74, "Reg Deny (FA)- Requested Reverse Tunnel Unavailable"},
99   {75, "Reg Deny (FA)- Reverse Tunnel is Mandatory and 'T' Bit Not Set"},
100   {76, "Reg Deny (FA)- Mobile Node Too Distant"},
101   {79, "Reg Deny (FA)- Delivery Style Not Supported"},
102   {80, "Reg Deny (FA)- Home Network Unreachable"},
103   {81, "Reg Deny (FA)- HA Host Unreachable"},
104   {82, "Reg Deny (FA)- HA Port Unreachable"},
105   {88, "Reg Deny (FA)- HA Unreachable"},
106   {96, "Reg Deny (FA)(NAI) - Non Zero Home Address Required"},
107   {97, "Reg Deny (FA)(NAI) - Missing NAI"},
108   {98, "Reg Deny (FA)(NAI) - Missing Home Agent"},
109   {99, "Reg Deny (FA)(NAI) - Missing Home Address"},
110   {128, "Reg Deny (HA)- Unspecified"},
111   {129, "Reg Deny (HA)- Administratively Prohibited"},
112   {130, "Reg Deny (HA)- Insufficient Resources"},
113   {131, "Reg Deny (HA)- MN Failed Authentication"},
114   {132, "Reg Deny (HA)- FA Failed Authentication"},
115   {133, "Reg Deny (HA)- Registration ID Mismatch"},
116   {134, "Reg Deny (HA)- Poorly Formed Request"},
117   {135, "Reg Deny (HA)- Too Many Simultaneous Bindings"},
118   {136, "Reg Deny (HA)- Unknown HA Address"},
119   {137, "Reg Deny (HA)- Requested Reverse Tunnel Unavailable"},
120   {138, "Reg Deny (HA)- Reverse Tunnel is Mandatory and 'T' Bit Not Set"},
121   {139, "Reg Deny (HA)- Requested Encapsulation Unavailable"},
122   {0, NULL},
123 };
124
125 typedef enum {
126   MH_AUTH_EXT = 32,
127   MF_AUTH_EXT = 33,
128   FH_AUTH_EXT = 34,
129   GEN_AUTH_EXT = 36,      /* RFC 3012 */
130   OLD_CVSE_EXT = 37,      /* RFC 3115 */
131   CVSE_EXT = 38,          /* RFC 3115 */
132   MN_NAI_EXT = 131,
133   MF_CHALLENGE_EXT = 132, /* RFC 3012 */
134   OLD_NVSE_EXT = 133,     /* RFC 3115 */
135   NVSE_EXT = 134          /* RFC 3115 */
136 } MIP_EXTS;
137 static const value_string mip_ext_types[]= {
138   {MH_AUTH_EXT, "Mobile-Home Authentication Extension"},
139   {MF_AUTH_EXT, "Mobile-Foreign Authentication Extension"},
140   {FH_AUTH_EXT, "Foreign-Home Authentication Extension"},
141   {MN_NAI_EXT,  "Mobile Node NAI Extension"},
142   {GEN_AUTH_EXT, "Generalized Mobile-IP Authentication Extension"},
143   {MF_CHALLENGE_EXT, "MN-FA Challenge Extension"},
144   {CVSE_EXT, "Critical Vendor/Organization Specific Extension"},
145   {OLD_CVSE_EXT, "Critical Vendor/Organization Specific Extension"},
146   {NVSE_EXT, "Normal Vendor/Organization Specific Extension"},
147   {OLD_NVSE_EXT, "Normal Vendor/Organization Specific Extension"},
148   {0, NULL},
149 };
150
151 static const value_string mip_ext_stypes[]= {
152   {1, "MN AAA Extension"},
153   {0, NULL},
154 };
155 /* Code to dissect extensions */
156 static void
157 dissect_mip_extensions( tvbuff_t *tvb, int offset, proto_tree *tree)
158 {
159   proto_item   *ti;
160   proto_tree   *exts_tree=NULL;
161   proto_tree   *ext_tree;
162   size_t        ext_len;
163   guint8        ext_type;
164   guint8        ext_subtype=0;
165   size_t        hdrLen;
166
167   /* None of this really matters if we don't have a tree */
168   if (!tree) return;
169
170   /* Add our tree, if we have extensions */
171   ti = proto_tree_add_text(tree, tvb, offset, -1, "Extensions");
172   exts_tree = proto_item_add_subtree(ti, ett_mip_exts);
173
174   /* And, handle each extension */
175   while (tvb_reported_length_remaining(tvb, offset) > 0) {
176
177         /* Get our extension info */
178         ext_type = tvb_get_guint8(tvb, offset);
179         if (ext_type == GEN_AUTH_EXT) {
180           /*
181            * Very nasty . . breaks normal extensions, since the length is
182            * in the wrong place :(
183            */
184           ext_subtype = tvb_get_guint8(tvb, offset + 1);
185           ext_len = tvb_get_ntohs(tvb, offset + 2);
186           hdrLen = 4;
187         } else {
188           ext_len = tvb_get_guint8(tvb, offset + 1);
189           hdrLen = 2;
190         }
191
192         ti = proto_tree_add_text(exts_tree, tvb, offset, ext_len + hdrLen,
193                                  "Extension: %s",
194                                  val_to_str(ext_type, mip_ext_types,
195                                             "Unknown Extension %u"));
196         ext_tree = proto_item_add_subtree(ti, ett_mip_ext);
197
198         proto_tree_add_item(ext_tree, hf_mip_ext_type, tvb, offset, 1, ext_type);
199         offset++;
200         if (ext_type != GEN_AUTH_EXT) {
201           /* Another nasty hack since GEN_AUTH_EXT broke everything */
202           proto_tree_add_uint(ext_tree, hf_mip_ext_len, tvb, offset, 1, ext_len);
203           offset++;
204         }
205
206         switch(ext_type) {
207         case MH_AUTH_EXT:
208         case MF_AUTH_EXT:
209         case FH_AUTH_EXT:
210           /* All these extensions look the same.  4 byte SPI followed by a key */
211           proto_tree_add_item(ext_tree, hf_mip_aext_spi, tvb, offset, 4, FALSE);
212           proto_tree_add_item(ext_tree, hf_mip_aext_auth, tvb, offset+4, ext_len-4,
213                                                   FALSE);
214           break;
215         case MN_NAI_EXT:
216           proto_tree_add_item(ext_tree, hf_mip_next_nai, tvb, offset,
217                                                   ext_len, FALSE);
218           break;
219
220         case GEN_AUTH_EXT:      /* RFC 3012 */
221           /*
222            * Very nasty . . breaks normal extensions, since the length is
223            * in the wrong place :(
224            */
225           proto_tree_add_uint(ext_tree, hf_mip_ext_stype, tvb, offset, 1, ext_subtype);
226           offset++;
227           proto_tree_add_uint(ext_tree, hf_mip_ext_len, tvb, offset, 2, ext_len);
228           offset+=2;
229           /* SPI */
230           proto_tree_add_item(ext_tree, hf_mip_aext_spi, tvb, offset, 4, FALSE);
231           /* Key */
232           proto_tree_add_item(ext_tree, hf_mip_aext_auth, tvb, offset + 4,
233                                                   ext_len - 4, FALSE);
234
235           break;
236         case OLD_CVSE_EXT:      /* RFC 3115 */
237         case CVSE_EXT:          /* RFC 3115 */
238         case OLD_NVSE_EXT:      /* RFC 3115 */
239         case NVSE_EXT:          /* RFC 3115 */
240         case MF_CHALLENGE_EXT:  /* RFC 3012 */
241           /* The default dissector is good here.  The challenge is all hex anyway. */
242         default:
243           proto_tree_add_item(ext_tree, hf_mip_ext, tvb, offset, ext_len, FALSE);
244           break;
245         } /* ext type */
246
247         offset += ext_len;
248   } /* while data remaining */
249
250 } /* dissect_mip_extensions */
251
252 /* Code to actually dissect the packets */
253 static void
254 dissect_mip( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
255 {
256   /* Set up structures we will need to add the protocol subtree and manage it */
257   proto_item    *ti;
258   proto_tree    *mip_tree=NULL;
259   proto_item    *tf;
260   proto_tree    *flags_tree;
261   guint8         type;
262   guint8         flags;
263   nstime_t       ident_time;
264   size_t         offset=0;
265
266   /* Make entries in Protocol column and Info column on summary display */
267
268   if (check_col(pinfo->cinfo, COL_PROTOCOL))
269         col_set_str(pinfo->cinfo, COL_PROTOCOL, "MobileIP");
270   if (check_col(pinfo->cinfo, COL_INFO))
271         col_clear(pinfo->cinfo, COL_INFO);
272
273   type = tvb_get_guint8(tvb, offset);
274   switch (type) {
275   case REGISTRATION_REQUEST:
276         if (check_col(pinfo->cinfo, COL_INFO))
277           col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Request: HAddr=%s COA=%s",
278                                    ip_to_str(tvb_get_ptr(tvb, 4, 4)),
279                                    ip_to_str(tvb_get_ptr(tvb,12,4)));
280
281         if (tree) {
282           ti = proto_tree_add_item(tree, proto_mip, tvb, offset, -1, FALSE);
283           mip_tree = proto_item_add_subtree(ti, ett_mip);
284
285           /* type */
286           proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type);
287           offset++;
288
289           /* flags */
290           flags = tvb_get_guint8(tvb, offset);
291           tf = proto_tree_add_uint(mip_tree, hf_mip_flags, tvb,
292                                                            offset, 1, flags);
293           flags_tree = proto_item_add_subtree(tf, ett_mip_flags);
294           proto_tree_add_boolean(flags_tree, hf_mip_s, tvb, offset, 1, flags);
295           proto_tree_add_boolean(flags_tree, hf_mip_b, tvb, offset, 1, flags);
296           proto_tree_add_boolean(flags_tree, hf_mip_d, tvb, offset, 1, flags);
297           proto_tree_add_boolean(flags_tree, hf_mip_m, tvb, offset, 1, flags);
298           proto_tree_add_boolean(flags_tree, hf_mip_g, tvb, offset, 1, flags);
299           proto_tree_add_boolean(flags_tree, hf_mip_v, tvb, offset, 1, flags);
300           proto_tree_add_boolean(flags_tree, hf_mip_t, tvb, offset, 1, flags);
301           offset++;
302
303           /* lifetime */
304           proto_tree_add_item(mip_tree, hf_mip_life, tvb, offset, 2, FALSE);
305           offset +=2;
306
307           /* home address */
308           proto_tree_add_item(mip_tree, hf_mip_homeaddr, tvb, offset, 4, FALSE);
309           offset += 4;
310
311           /* home agent address */
312           proto_tree_add_item(mip_tree, hf_mip_haaddr, tvb, offset, 4, FALSE);
313           offset += 4;
314
315           /* Care of Address */
316           proto_tree_add_item(mip_tree, hf_mip_coa, tvb, offset, 4, FALSE);
317           offset += 4;
318
319           /* Identifier */
320           ident_time.secs =  tvb_get_ntohl(tvb,16)-(guint32) NTP_BASETIME;
321           ident_time.nsecs = tvb_get_ntohl(tvb,20)*1000;
322           proto_tree_add_time(mip_tree, hf_mip_ident, tvb, offset, 8, &ident_time);
323           offset += 8;
324
325         } /* if tree */
326         break;
327   case REGISTRATION_REPLY:
328         if (check_col(pinfo->cinfo, COL_INFO))
329           col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Reply: HAddr=%s, Code=%u",
330                                    ip_to_str(tvb_get_ptr(tvb,4,4)), tvb_get_guint8(tvb,1));
331
332         if (tree) {
333           /* Add Subtree */
334           ti = proto_tree_add_item(tree, proto_mip, tvb, offset, -1, FALSE);
335           mip_tree = proto_item_add_subtree(ti, ett_mip);
336
337           /* Type */
338           proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type);
339           offset++;
340
341           /* Reply Code */
342           proto_tree_add_item(mip_tree, hf_mip_code, tvb, offset, 1, FALSE);
343           offset++;
344
345           /* Registration Lifetime */
346           proto_tree_add_item(mip_tree, hf_mip_life, tvb, offset, 2, FALSE);
347           offset += 2;
348
349           /* Home address */
350           proto_tree_add_item(mip_tree, hf_mip_homeaddr, tvb, offset, 4, FALSE);
351           offset += 4;
352
353           /* Home Agent Address */
354           proto_tree_add_item(mip_tree, hf_mip_haaddr, tvb, offset, 4, FALSE);
355           offset += 4;
356
357           /* Identifier */
358           ident_time.secs =  tvb_get_ntohl(tvb,12)-(guint32) NTP_BASETIME;
359           ident_time.nsecs = tvb_get_ntohl(tvb,16)*1000;
360           proto_tree_add_time(mip_tree, hf_mip_ident, tvb, offset, 8, &ident_time);
361           offset += 8;
362         } /* if tree */
363
364         break;
365   } /* End switch */
366
367   if (tree) {
368         if (tvb_reported_length_remaining(tvb, offset) > 0)
369           dissect_mip_extensions(tvb, offset, mip_tree);
370   }
371 } /* dissect_mip */
372
373 /* Register the protocol with Ethereal */
374 void proto_register_mip(void)
375 {
376
377 /* Setup list of header fields */
378         static hf_register_info hf[] = {
379           { &hf_mip_type,
380                  { "Message Type",           "mip.type",
381                         FT_UINT8, BASE_DEC, VALS(mip_types), 0,
382                         "Mobile IP Message type.", HFILL }
383           },
384           { &hf_mip_flags,
385                 {"Flags", "mip.flags",
386                  FT_UINT8, BASE_HEX, NULL, 0x0,
387                  "", HFILL}
388           },
389           { &hf_mip_s,
390                  {"Simultaneous Bindings",           "mip.s",
391
392                    FT_BOOLEAN, 8, NULL, 128,
393                    "Simultaneous Bindings Allowed", HFILL }
394           },
395           { &hf_mip_b,
396                  {"Broadcast Datagrams",           "mip.b",
397                    FT_BOOLEAN, 8, NULL, 64,
398                    "Broadcast Datagrams requested", HFILL }
399           },
400           { &hf_mip_d,
401                  { "Co-lcated Care-of Address",           "mip.d",
402                    FT_BOOLEAN, 8, NULL, 32,
403                    "MN using Co-located Care-of address", HFILL }
404           },
405           { &hf_mip_m,
406                  {"Minimal Encapsulation",           "mip.m",
407                    FT_BOOLEAN, 8, NULL, 16,
408                    "MN wants Minimal encapsulation", HFILL }
409           },
410           { &hf_mip_g,
411                  {"GRE",           "mip.g",
412                    FT_BOOLEAN, 8, NULL, 8,
413                    "MN wants GRE encapsulation", HFILL }
414           },
415           { &hf_mip_v,
416                  { "Van Jacobson",           "mip.v",
417                    FT_BOOLEAN, 8, NULL, 4,
418                    "Van Jacobson", HFILL }
419           },
420           { &hf_mip_t,
421                  { "Reverse Tunneling",           "mip.t",
422                    FT_BOOLEAN, 8, NULL, 2,
423                    "Reverse tunneling requested", HFILL }
424           },
425           { &hf_mip_code,
426                  { "Reply Code",           "mip.code",
427                         FT_UINT8, BASE_DEC, VALS(mip_reply_codes), 0,
428                         "Mobile IP Reply code.", HFILL }
429           },
430           { &hf_mip_life,
431                  { "Lifetime",           "mip.life",
432                         FT_UINT16, BASE_DEC, NULL, 0,
433                         "Mobile IP Lifetime.", HFILL }
434           },
435           { &hf_mip_homeaddr,
436                  { "Home Address",           "mip.homeaddr",
437                         FT_IPv4, BASE_NONE, NULL, 0,
438                         "Mobile Node's home address.", HFILL }
439           },
440
441           { &hf_mip_haaddr,
442                  { "Home Agent",           "mip.haaddr",
443                         FT_IPv4, BASE_NONE, NULL, 0,
444                         "Home agent IP Address.", HFILL }
445           },
446           { &hf_mip_coa,
447                  { "Care of Address",           "mip.coa",
448                         FT_IPv4, BASE_NONE, NULL, 0,
449                         "Care of Address.", HFILL }
450           },
451           { &hf_mip_ident,
452                  { "Identification",           "mip.ident",
453                         FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0,
454                         "MN Identification.", HFILL }
455           },
456           { &hf_mip_ext_type,
457                  { "Extension Type",           "mip.ext.type",
458                         FT_UINT8, BASE_DEC, VALS(mip_ext_types), 0,
459                         "Mobile IP Extension Type.", HFILL }
460           },
461           { &hf_mip_ext_stype,
462                  { "Gen Auth Ext SubType",           "mip.ext.auth.subtype",
463                         FT_UINT8, BASE_DEC, VALS(mip_ext_stypes), 0,
464                         "Mobile IP Auth Extension Sub Type.", HFILL }
465           },
466           { &hf_mip_ext_len,
467                  { "Extension Length",         "mip.ext.len",
468                         FT_UINT16, BASE_DEC, NULL, 0,
469                         "Mobile IP Extension Length.", HFILL }
470           },
471           { &hf_mip_ext,
472                  { "Extension",                      "mip.extension",
473                         FT_BYTES, BASE_HEX, NULL, 0,
474                         "Extension", HFILL }
475           },
476           { &hf_mip_aext_spi,
477                  { "SPI",                      "mip.auth.spi",
478                         FT_UINT32, BASE_HEX, NULL, 0,
479                         "Authentication Header Security Parameter Index.", HFILL }
480           },
481           { &hf_mip_aext_auth,
482                  { "Authenticator",            "mip.auth.auth",
483                         FT_BYTES, BASE_NONE, NULL, 0,
484                         "Authenticator.", HFILL }
485           },
486           { &hf_mip_next_nai,
487                  { "NAI",                      "mip.nai",
488                         FT_STRING, BASE_NONE, NULL, 0,
489                         "NAI", HFILL }
490           },
491         };
492
493         /* Setup protocol subtree array */
494         static gint *ett[] = {
495                 &ett_mip,
496                 &ett_mip_flags,
497                 &ett_mip_ext,
498                 &ett_mip_exts,
499         };
500
501         /* Register the protocol name and description */
502         proto_mip = proto_register_protocol("Mobile IP", "Mobile IP", "mip");
503
504         /* Register the dissector by name */
505         register_dissector("mip", dissect_mip, proto_mip);
506
507         /* Required function calls to register the header fields and subtrees used */
508         proto_register_field_array(proto_mip, hf, array_length(hf));
509         proto_register_subtree_array(ett, array_length(ett));
510 }
511
512 void
513 proto_reg_handoff_mip(void)
514 {
515         dissector_handle_t mip_handle;
516
517         mip_handle = find_dissector("mip");
518         dissector_add("udp.port", UDP_PORT_MIP, mip_handle);
519 }