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