Additional RAP error code for password changes sent to a BDC, from Devin
[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.29 2002/04/29 09:57:29 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   
279   /* Make entries in Protocol column and Info column on summary display */
280   
281   if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
282         col_set_str(pinfo->cinfo, COL_PROTOCOL, "MobileIP");
283   if (check_col(pinfo->cinfo, COL_INFO)) 
284         col_clear(pinfo->cinfo, COL_INFO);
285
286   type = tvb_get_guint8(tvb, offset);
287   switch (type) {
288   case REGISTRATION_REQUEST:
289         if (check_col(pinfo->cinfo, COL_INFO)) 
290           col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Request: HAddr=%s COA=%s", 
291                                    ip_to_str(tvb_get_ptr(tvb, 4, 4)),
292                                    ip_to_str(tvb_get_ptr(tvb,12,4)));
293         
294         if (tree) {
295           ti = proto_tree_add_item(tree, proto_mip, tvb, offset, -1, FALSE);
296           mip_tree = proto_item_add_subtree(ti, ett_mip);
297           
298           /* type */
299           proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type);
300           offset++;
301           
302           /* flags */
303           flags = tvb_get_guint8(tvb, offset);
304           tf = proto_tree_add_uint(mip_tree, hf_mip_flags, tvb,
305                                                            offset, 1, flags);
306           flags_tree = proto_item_add_subtree(tf, ett_mip_flags);
307           proto_tree_add_boolean(flags_tree, hf_mip_s, tvb, offset, 1, flags);
308           proto_tree_add_boolean(flags_tree, hf_mip_b, tvb, offset, 1, flags);
309           proto_tree_add_boolean(flags_tree, hf_mip_d, tvb, offset, 1, flags);
310           proto_tree_add_boolean(flags_tree, hf_mip_m, tvb, offset, 1, flags);
311           proto_tree_add_boolean(flags_tree, hf_mip_g, tvb, offset, 1, flags);
312           proto_tree_add_boolean(flags_tree, hf_mip_v, tvb, offset, 1, flags);
313           proto_tree_add_boolean(flags_tree, hf_mip_t, tvb, offset, 1, flags);
314           offset++;
315
316           /* lifetime */
317           proto_tree_add_item(mip_tree, hf_mip_life, tvb, offset, 2, FALSE);
318           offset +=2;
319           
320           /* home address */
321           proto_tree_add_item(mip_tree, hf_mip_homeaddr, tvb, offset, 4, FALSE);
322           offset += 4;
323           
324           /* home agent address */
325           proto_tree_add_item(mip_tree, hf_mip_haaddr, tvb, offset, 4, FALSE);
326           offset += 4;
327           
328           /* Care of Address */
329           proto_tree_add_item(mip_tree, hf_mip_coa, tvb, offset, 4, FALSE);
330           offset += 4;
331
332           /* Identifier */
333           ident_time.secs =  tvb_get_ntohl(tvb,16)-(guint32) NTP_BASETIME;
334           ident_time.nsecs = tvb_get_ntohl(tvb,20)*1000;
335           proto_tree_add_time(mip_tree, hf_mip_ident, tvb, offset, 8, &ident_time);
336           offset += 8;
337                 
338         } /* if tree */
339         break;
340   case REGISTRATION_REPLY:
341         if (check_col(pinfo->cinfo, COL_INFO)) 
342           col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Reply: HAddr=%s, Code=%u", 
343                                    ip_to_str(tvb_get_ptr(tvb,4,4)), tvb_get_guint8(tvb,1));
344         
345         if (tree) {
346           /* Add Subtree */
347           ti = proto_tree_add_item(tree, proto_mip, tvb, offset, -1, FALSE);
348           mip_tree = proto_item_add_subtree(ti, ett_mip);
349           
350           /* Type */
351           proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type);
352           offset++;
353           
354           /* Reply Code */
355           proto_tree_add_item(mip_tree, hf_mip_code, tvb, offset, 1, FALSE);
356           offset++;
357
358           /* Registration Lifetime */
359           proto_tree_add_item(mip_tree, hf_mip_life, tvb, offset, 2, FALSE);
360           offset += 2;
361
362           /* Home address */
363           proto_tree_add_item(mip_tree, hf_mip_homeaddr, tvb, offset, 4, FALSE);
364           offset += 4;
365
366           /* Home Agent Address */
367           proto_tree_add_item(mip_tree, hf_mip_haaddr, tvb, offset, 4, FALSE);
368           offset += 4;
369
370           /* Identifier */
371           ident_time.secs =  tvb_get_ntohl(tvb,12)-(guint32) NTP_BASETIME;
372           ident_time.nsecs = tvb_get_ntohl(tvb,16)*1000;
373           proto_tree_add_time(mip_tree, hf_mip_ident, tvb, offset, 8, &ident_time);
374           offset += 8;
375         } /* if tree */
376         
377         break;
378   } /* End switch */
379
380   if (tree) {
381         if (tvb_reported_length_remaining(tvb, offset) > 0)
382           dissect_mip_extensions(tvb, offset, pinfo, mip_tree);
383   }
384 } /* dissect_mip */
385
386 /* Register the protocol with Ethereal */
387 void proto_register_mip(void)
388 {                 
389
390 /* Setup list of header fields */
391         static hf_register_info hf[] = {
392           { &hf_mip_type,
393                  { "Message Type",           "mip.type",
394                         FT_UINT8, BASE_DEC, VALS(mip_types), 0,          
395                         "Mobile IP Message type.", HFILL }
396           },
397           { &hf_mip_flags,
398                 {"Flags", "mip.flags",
399                  FT_UINT8, BASE_HEX, NULL, 0x0,
400                  "", HFILL}
401           },
402           { &hf_mip_s,
403                  {"Simultaneous Bindings",           "mip.s",
404
405                    FT_BOOLEAN, 8, NULL, 128,          
406                    "Simultaneous Bindings Allowed", HFILL }
407           },
408           { &hf_mip_b,
409                  {"Broadcast Datagrams",           "mip.b",
410                    FT_BOOLEAN, 8, NULL, 64,          
411                    "Broadcast Datagrams requested", HFILL }
412           },
413           { &hf_mip_d,
414                  { "Co-lcated Care-of Address",           "mip.d",
415                    FT_BOOLEAN, 8, NULL, 32,          
416                    "MN using Co-located Care-of address", HFILL }
417           },
418           { &hf_mip_m,
419                  {"Minimal Encapsulation",           "mip.m",
420                    FT_BOOLEAN, 8, NULL, 16,          
421                    "MN wants Minimal encapsulation", HFILL }
422           },
423           { &hf_mip_g,
424                  {"GRE",           "mip.g",
425                    FT_BOOLEAN, 8, NULL, 8,          
426                    "MN wants GRE encapsulation", HFILL }
427           },
428           { &hf_mip_v,
429                  { "Van Jacobson",           "mip.v",
430                    FT_BOOLEAN, 8, NULL, 4,          
431                    "Van Jacobson", HFILL }
432           },
433           { &hf_mip_t,
434                  { "Reverse Tunneling",           "mip.t",
435                    FT_BOOLEAN, 8, NULL, 2,          
436                    "Reverse tunneling requested", HFILL }
437           },
438           { &hf_mip_code,
439                  { "Reply Code",           "mip.code",
440                         FT_UINT8, BASE_DEC, VALS(mip_reply_codes), 0,          
441                         "Mobile IP Reply code.", HFILL }
442           },
443           { &hf_mip_life,
444                  { "Lifetime",           "mip.life",
445                         FT_UINT16, BASE_DEC, NULL, 0,          
446                         "Mobile IP Lifetime.", HFILL }
447           },
448           { &hf_mip_homeaddr,
449                  { "Home Address",           "mip.homeaddr",
450                         FT_IPv4, BASE_NONE, NULL, 0,          
451                         "Mobile Node's home address.", HFILL }
452           },
453           
454           { &hf_mip_haaddr,
455                  { "Home Agent",           "mip.haaddr",
456                         FT_IPv4, BASE_NONE, NULL, 0,          
457                         "Home agent IP Address.", HFILL }
458           },
459           { &hf_mip_coa,
460                  { "Care of Address",           "mip.coa",
461                         FT_IPv4, BASE_NONE, NULL, 0,          
462                         "Care of Address.", HFILL }
463           },
464           { &hf_mip_ident,
465                  { "Identification",           "mip.ident",
466                         FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0,          
467                         "MN Identification.", HFILL }
468           },
469           { &hf_mip_ext_type,
470                  { "Extension Type",           "mip.ext.type",
471                         FT_UINT8, BASE_DEC, VALS(mip_ext_types), 0,          
472                         "Mobile IP Extension Type.", HFILL }
473           },
474           { &hf_mip_ext_stype,
475                  { "Gen Auth Ext SubType",           "mip.ext.auth.subtype",
476                         FT_UINT8, BASE_DEC, VALS(mip_ext_stypes), 0,          
477                         "Mobile IP Auth Extension Sub Type.", HFILL }
478           },
479           { &hf_mip_ext_len,
480                  { "Extension Length",         "mip.ext.len",
481                         FT_UINT16, BASE_DEC, NULL, 0,
482                         "Mobile IP Extension Length.", HFILL }
483           },
484           { &hf_mip_ext,
485                  { "Extension",                      "mip.extension",
486                         FT_BYTES, BASE_HEX, NULL, 0,
487                         "Extension", HFILL }
488           },
489           { &hf_mip_aext_spi,
490                  { "SPI",                      "mip.auth.spi",
491                         FT_UINT32, BASE_HEX, NULL, 0,
492                         "Authentication Header Security Parameter Index.", HFILL }
493           },
494           { &hf_mip_aext_auth,
495                  { "Authenticator",            "mip.auth.auth",
496                         FT_BYTES, BASE_NONE, NULL, 0,
497                         "Authenticator.", HFILL }
498           },
499           { &hf_mip_next_nai,
500                  { "NAI",                      "mip.nai",
501                         FT_STRING, BASE_NONE, NULL, 0,
502                         "NAI", HFILL }
503           },
504         };
505
506         /* Setup protocol subtree array */
507         static gint *ett[] = {
508                 &ett_mip,
509                 &ett_mip_flags,
510                 &ett_mip_ext,
511                 &ett_mip_exts,
512         };
513
514         /* Register the protocol name and description */
515         proto_mip = proto_register_protocol("Mobile IP", "Mobile IP", "mip");
516
517         /* Register the dissector by name */
518         register_dissector("mip", dissect_mip, proto_mip);
519
520         /* Required function calls to register the header fields and subtrees used */
521         proto_register_field_array(proto_mip, hf, array_length(hf));
522         proto_register_subtree_array(ett, array_length(ett));
523 };
524
525 void
526 proto_reg_handoff_mip(void)
527 {
528         dissector_handle_t mip_handle;
529
530         mip_handle = find_dissector("mip");
531         dissector_add("udp.port", UDP_PORT_MIP, mip_handle);
532 }