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