Include files from the "epan" directory and subdirectories thereof with
[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.26 2002/01/21 07:36:37 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, packet_info *pinfo,
170                         proto_tree *tree)
171 {
172   proto_item   *ti;
173   proto_tree   *exts_tree=NULL;
174   proto_tree   *ext_tree;
175   size_t        ext_len;
176   guint8        ext_type;
177   guint8        ext_subtype=0;
178   size_t        hdrLen;
179
180   /* None of this really matters if we don't have a tree */
181   if (!tree) return;
182
183   /* Add our tree, if we have extensions */
184   ti = proto_tree_add_text(tree, tvb, offset,
185                 tvb_length_remaining(tvb, offset), "Extensions");
186   exts_tree = proto_item_add_subtree(ti, ett_mip_exts);
187
188   /* And, handle each extension */
189   while (tvb_reported_length_remaining(tvb, offset) > 0) {
190
191         /* Get our extension info */
192         ext_type = tvb_get_guint8(tvb, offset);
193         if (ext_type == GEN_AUTH_EXT) {
194           /*
195            * Very nasty . . breaks normal extensions, since the length is
196            * in the wrong place :(
197            */
198           ext_subtype = tvb_get_guint8(tvb, offset + 1);
199           ext_len = tvb_get_ntohs(tvb, offset + 2);
200           hdrLen = 4;
201         } else {
202           ext_len = tvb_get_guint8(tvb, offset + 1);
203           hdrLen = 2;
204         }
205         
206         ti = proto_tree_add_text(exts_tree, tvb, offset, ext_len + hdrLen,
207                                  "Extension: %s",
208                                  val_to_str(ext_type, mip_ext_types,
209                                             "Unknown Extension %u"));
210         ext_tree = proto_item_add_subtree(ti, ett_mip_ext);
211
212         proto_tree_add_item(ext_tree, hf_mip_ext_type, tvb, offset, 1, ext_type);
213         offset++;
214         if (ext_type != GEN_AUTH_EXT) {
215           /* Another nasty hack since GEN_AUTH_EXT broke everything */
216           proto_tree_add_uint(ext_tree, hf_mip_ext_len, tvb, offset, 1, ext_len);
217           offset++;
218         }
219
220         switch(ext_type) {
221         case MH_AUTH_EXT:
222         case MF_AUTH_EXT:
223         case FH_AUTH_EXT:
224           /* All these extensions look the same.  4 byte SPI followed by a key */
225           proto_tree_add_item(ext_tree, hf_mip_aext_spi, tvb, offset, 4, FALSE);
226           proto_tree_add_item(ext_tree, hf_mip_aext_auth, tvb, offset+4, ext_len-4,
227                                                   FALSE);
228           break;
229         case MN_NAI_EXT:
230           proto_tree_add_item(ext_tree, hf_mip_next_nai, tvb, offset, 
231                                                   ext_len, FALSE);
232           break;
233
234         case GEN_AUTH_EXT:      /* RFC 3012 */
235           /*
236            * Very nasty . . breaks normal extensions, since the length is
237            * in the wrong place :(
238            */
239           proto_tree_add_uint(ext_tree, hf_mip_ext_stype, tvb, offset, 1, ext_subtype);
240           offset++;
241           proto_tree_add_uint(ext_tree, hf_mip_ext_len, tvb, offset, 2, ext_len);
242           offset+=2;
243           /* SPI */
244           proto_tree_add_item(ext_tree, hf_mip_aext_spi, tvb, offset, 4, FALSE);
245           /* Key */
246           proto_tree_add_item(ext_tree, hf_mip_aext_auth, tvb, offset + 4,
247                                                   ext_len - 4, FALSE);
248           
249           break;
250         case OLD_CVSE_EXT:      /* RFC 3115 */
251         case CVSE_EXT:          /* RFC 3115 */
252         case OLD_NVSE_EXT:      /* RFC 3115 */
253         case NVSE_EXT:          /* RFC 3115 */
254         case MF_CHALLENGE_EXT:  /* RFC 3012 */
255           /* The default dissector is good here.  The challenge is all hex anyway. */
256         default:
257           proto_tree_add_item(ext_tree, hf_mip_ext, tvb, offset, ext_len, FALSE);
258           break;
259         } /* ext type */
260
261         offset += ext_len;
262   } /* while data remaining */
263
264 } /* dissect_mip_extensions */
265
266 /* Code to actually dissect the packets */
267 static void
268 dissect_mip( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
269 {
270   /* Set up structures we will need to add the protocol subtree and manage it */
271   proto_item    *ti;
272   proto_tree    *mip_tree=NULL;
273   proto_item    *tf;
274   proto_tree    *flags_tree;
275   guint8         type;
276   guint8         flags;
277   nstime_t       ident_time;
278   size_t         offset=0;
279   tvbuff_t      *extensions_tvb;
280   size_t         dataRemaining;
281   
282   /* Make entries in Protocol column and Info column on summary display */
283   
284   if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
285         col_set_str(pinfo->cinfo, COL_PROTOCOL, "MobileIP");
286   if (check_col(pinfo->cinfo, COL_INFO)) 
287         col_clear(pinfo->cinfo, COL_INFO);
288
289   type = tvb_get_guint8(tvb, offset);
290   switch (type) {
291   case REGISTRATION_REQUEST:
292         if (check_col(pinfo->cinfo, COL_INFO)) 
293           col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Request: HAddr=%s COA=%s", 
294                                    ip_to_str(tvb_get_ptr(tvb, 4, 4)),
295                                    ip_to_str(tvb_get_ptr(tvb,12,4)));
296         
297         if (tree) {
298           ti = proto_tree_add_item(tree, proto_mip, tvb, offset, tvb_length(tvb), FALSE);
299           mip_tree = proto_item_add_subtree(ti, ett_mip);
300           
301           /* type */
302           proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type);
303           offset++;
304           
305           /* flags */
306           flags = tvb_get_guint8(tvb, offset);
307           tf = proto_tree_add_uint(mip_tree, hf_mip_flags, tvb,
308                                                            offset, 1, flags);
309           flags_tree = proto_item_add_subtree(tf, ett_mip_flags);
310           proto_tree_add_boolean(flags_tree, hf_mip_s, tvb, offset, 1, flags);
311           proto_tree_add_boolean(flags_tree, hf_mip_b, tvb, offset, 1, flags);
312           proto_tree_add_boolean(flags_tree, hf_mip_d, tvb, offset, 1, flags);
313           proto_tree_add_boolean(flags_tree, hf_mip_m, tvb, offset, 1, flags);
314           proto_tree_add_boolean(flags_tree, hf_mip_g, tvb, offset, 1, flags);
315           proto_tree_add_boolean(flags_tree, hf_mip_v, tvb, offset, 1, flags);
316           proto_tree_add_boolean(flags_tree, hf_mip_t, tvb, offset, 1, flags);
317           offset++;
318
319           /* lifetime */
320           proto_tree_add_item(mip_tree, hf_mip_life, tvb, offset, 2, FALSE);
321           offset +=2;
322           
323           /* home address */
324           proto_tree_add_item(mip_tree, hf_mip_homeaddr, tvb, offset, 4, FALSE);
325           offset += 4;
326           
327           /* home agent address */
328           proto_tree_add_item(mip_tree, hf_mip_haaddr, tvb, offset, 4, FALSE);
329           offset += 4;
330           
331           /* Care of Address */
332           proto_tree_add_item(mip_tree, hf_mip_coa, tvb, offset, 4, FALSE);
333           offset += 4;
334
335           /* Identifier */
336           ident_time.secs =  tvb_get_ntohl(tvb,16)-(guint32) NTP_BASETIME;
337           ident_time.nsecs = tvb_get_ntohl(tvb,20)*1000;
338           proto_tree_add_time(mip_tree, hf_mip_ident, tvb, offset, 8, &ident_time);
339           offset += 8;
340                 
341         } /* if tree */
342         break;
343   case REGISTRATION_REPLY:
344         if (check_col(pinfo->cinfo, COL_INFO)) 
345           col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Reply: HAddr=%s, Code=%u", 
346                                    ip_to_str(tvb_get_ptr(tvb,4,4)), tvb_get_guint8(tvb,1));
347         
348         if (tree) {
349           /* Add Subtree */
350           ti = proto_tree_add_item(tree, proto_mip, tvb, offset, tvb_length(tvb), FALSE);
351           mip_tree = proto_item_add_subtree(ti, ett_mip);
352           
353           /* Type */
354           proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type);
355           offset++;
356           
357           /* Reply Code */
358           proto_tree_add_item(mip_tree, hf_mip_code, tvb, offset, 1, FALSE);
359           offset++;
360
361           /* Registration Lifetime */
362           proto_tree_add_item(mip_tree, hf_mip_life, tvb, offset, 2, FALSE);
363           offset += 2;
364
365           /* Home address */
366           proto_tree_add_item(mip_tree, hf_mip_homeaddr, tvb, offset, 4, FALSE);
367           offset += 4;
368
369           /* Home Agent Address */
370           proto_tree_add_item(mip_tree, hf_mip_haaddr, tvb, offset, 4, FALSE);
371           offset += 4;
372
373           /* Identifier */
374           ident_time.secs =  tvb_get_ntohl(tvb,12)-(guint32) NTP_BASETIME;
375           ident_time.nsecs = tvb_get_ntohl(tvb,16)*1000;
376           proto_tree_add_time(mip_tree, hf_mip_ident, tvb, offset, 8, &ident_time);
377           offset += 8;
378         } /* if tree */
379         
380         break;
381   } /* End switch */
382
383   if (tree) {
384         if (tvb_offset_exists(tvb, offset))
385           dissect_mip_extensions(tvb, offset, pinfo, mip_tree);
386   }
387 } /* dissect_mip */
388
389 /* Register the protocol with Ethereal */
390 void proto_register_mip(void)
391 {                 
392
393 /* Setup list of header fields */
394         static hf_register_info hf[] = {
395           { &hf_mip_type,
396                  { "Message Type",           "mip.type",
397                         FT_UINT8, BASE_DEC, VALS(mip_types), 0,          
398                         "Mobile IP Message type.", HFILL }
399           },
400           { &hf_mip_flags,
401                 {"Flags", "mip.flags",
402                  FT_UINT8, BASE_HEX, NULL, 0x0,
403                  "", HFILL}
404           },
405           { &hf_mip_s,
406                  {"Simultaneous Bindings",           "mip.s",
407
408                    FT_BOOLEAN, 8, NULL, 128,          
409                    "Simultaneous Bindings Allowed", HFILL }
410           },
411           { &hf_mip_b,
412                  {"Broadcast Datagrams",           "mip.b",
413                    FT_BOOLEAN, 8, NULL, 64,          
414                    "Broadcast Datagrams requested", HFILL }
415           },
416           { &hf_mip_d,
417                  { "Co-lcated Care-of Address",           "mip.d",
418                    FT_BOOLEAN, 8, NULL, 32,          
419                    "MN using Co-located Care-of address", HFILL }
420           },
421           { &hf_mip_m,
422                  {"Minimal Encapsulation",           "mip.m",
423                    FT_BOOLEAN, 8, NULL, 16,          
424                    "MN wants Minimal encapsulation", HFILL }
425           },
426           { &hf_mip_g,
427                  {"GRE",           "mip.g",
428                    FT_BOOLEAN, 8, NULL, 8,          
429                    "MN wants GRE encapsulation", HFILL }
430           },
431           { &hf_mip_v,
432                  { "Van Jacobson",           "mip.v",
433                    FT_BOOLEAN, 8, NULL, 4,          
434                    "Van Jacobson", HFILL }
435           },
436           { &hf_mip_t,
437                  { "Reverse Tunneling",           "mip.t",
438                    FT_BOOLEAN, 8, NULL, 2,          
439                    "Reverse tunneling requested", HFILL }
440           },
441           { &hf_mip_code,
442                  { "Reply Code",           "mip.code",
443                         FT_UINT8, BASE_DEC, VALS(mip_reply_codes), 0,          
444                         "Mobile IP Reply code.", HFILL }
445           },
446           { &hf_mip_life,
447                  { "Lifetime",           "mip.life",
448                         FT_UINT16, BASE_DEC, NULL, 0,          
449                         "Mobile IP Lifetime.", HFILL }
450           },
451           { &hf_mip_homeaddr,
452                  { "Home Address",           "mip.homeaddr",
453                         FT_IPv4, BASE_NONE, NULL, 0,          
454                         "Mobile Node's home address.", HFILL }
455           },
456           
457           { &hf_mip_haaddr,
458                  { "Home Agent",           "mip.haaddr",
459                         FT_IPv4, BASE_NONE, NULL, 0,          
460                         "Home agent IP Address.", HFILL }
461           },
462           { &hf_mip_coa,
463                  { "Care of Address",           "mip.coa",
464                         FT_IPv4, BASE_NONE, NULL, 0,          
465                         "Care of Address.", HFILL }
466           },
467           { &hf_mip_ident,
468                  { "Identification",           "mip.ident",
469                         FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0,          
470                         "MN Identification.", HFILL }
471           },
472           { &hf_mip_ext_type,
473                  { "Extension Type",           "mip.ext.type",
474                         FT_UINT8, BASE_DEC, VALS(mip_ext_types), 0,          
475                         "Mobile IP Extension Type.", HFILL }
476           },
477           { &hf_mip_ext_stype,
478                  { "Gen Auth Ext SubType",           "mip.ext.auth.subtype",
479                         FT_UINT8, BASE_DEC, VALS(mip_ext_stypes), 0,          
480                         "Mobile IP Auth Extension Sub Type.", HFILL }
481           },
482           { &hf_mip_ext_len,
483                  { "Extension Length",         "mip.ext.len",
484                         FT_UINT16, BASE_DEC, NULL, 0,
485                         "Mobile IP Extension Length.", HFILL }
486           },
487           { &hf_mip_ext,
488                  { "Extension",                      "mip.extension",
489                         FT_BYTES, BASE_HEX, NULL, 0,
490                         "Extension", HFILL }
491           },
492           { &hf_mip_aext_spi,
493                  { "SPI",                      "mip.auth.spi",
494                         FT_UINT32, BASE_HEX, NULL, 0,
495                         "Authentication Header Security Parameter Index.", HFILL }
496           },
497           { &hf_mip_aext_auth,
498                  { "Authenticator",            "mip.auth.auth",
499                         FT_BYTES, BASE_NONE, NULL, 0,
500                         "Authenticator.", HFILL }
501           },
502           { &hf_mip_next_nai,
503                  { "NAI",                      "mip.nai",
504                         FT_STRING, BASE_NONE, NULL, 0,
505                         "NAI", HFILL }
506           },
507         };
508
509         /* Setup protocol subtree array */
510         static gint *ett[] = {
511                 &ett_mip,
512                 &ett_mip_flags,
513                 &ett_mip_ext,
514                 &ett_mip_exts,
515         };
516
517         /* Register the protocol name and description */
518         proto_mip = proto_register_protocol("Mobile IP", "Mobile IP", "mip");
519
520         /* Register the dissector by name */
521         register_dissector("mip", dissect_mip, proto_mip);
522
523         /* Required function calls to register the header fields and subtrees used */
524         proto_register_field_array(proto_mip, hf, array_length(hf));
525         proto_register_subtree_array(ett, array_length(ett));
526 };
527
528 void
529 proto_reg_handoff_mip(void)
530 {
531         dissector_handle_t mip_handle;
532
533         mip_handle = find_dissector("mip");
534         dissector_add("udp.port", UDP_PORT_MIP, mip_handle);
535 }