/**************************************************************************** 
** File: mobileip.c
**
** Author: Mike Borella
**
** Comments: 
**
** $Id: mobileip.c,v 1.10 2001/09/07 20:59:11 mborella Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Library General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/

#include "global.h"
#include "mobileip.h"
#include "ethertypes.h"

/*
 * Types of Mobile IP messages
 */

#define MOBILEIP_TYPE_REGREQ      1
#define MOBILEIP_TYPE_REGREP      3
#define MOBILEIP_TYPE_REGUPDATE   20
#define MOBILEIP_TYPE_REGACK      21

/*
 * Mobile IP type map
 */

strmap_t mobileip_type_map[] =
{
  { MOBILEIP_TYPE_REGREQ,       "registration request" },
  { MOBILEIP_TYPE_REGREP,       "registration reply" },
  { MOBILEIP_TYPE_REGUPDATE,    "registration update" },
  { MOBILEIP_TYPE_REGACK,       "registration acknowledgement" },
  { 0, ""}
};

/*
 * Mobile IP response codes
 */

#define MOBILEIP_RESPCODE_REGACCEPTED              0
#define MOBILEIP_RESPCODE_REGACCEPTEDNOSMB         1
#define MOBILEIP_RESPCODE_FA_UNSPECIFIED           64
#define MOBILEIP_RESPCODE_FA_ADMINPROHIBITED       65
#define MOBILEIP_RESPCODE_FA_INSUFFICIENTRESOURCES 66
#define MOBILEIP_RESPCODE_FA_MNAUTHFAILED          67
#define MOBILEIP_RESPCODE_FA_HAAUTHFAILED          68
#define MOBILEIP_RESPCODE_FA_LIFETIMETOOLONG       69
#define MOBILEIP_RESPCODE_FA_POORLYFORMEDREQ       70
#define MOBILEIP_RESPCODE_FA_POORLYFORMEDREP       71
#define MOBILEIP_RESPCODE_FA_ENCAPSUNAVAILABLE     72
#define MOBILEIP_RESPCODE_FA_VJCOMPUNAVAILABLE     73
#define MOBILEIP_RESPCODE_FA_HNUNREACHABLE         80
#define MOBILEIP_RESPCODE_FA_HAHOSTUNREACHABLE     81
#define MOBILEIP_RESPCODE_FA_HAPORTUNREACHABLE     82
#define MOBILEIP_RESPCODE_FA_HAUNREACHABLE         88
#define MOBILEIP_RESPCODE_HA_UNSPECIFIED           128
#define MOBILEIP_RESPCODE_HA_ADMINPROHIBITED       129
#define MOBILEIP_RESPCODE_HA_INSUFFICIENTRESOURCES 130
#define MOBILEIP_RESPCODE_HA_MNAUTHFAILED          131
#define MOBILEIP_RESPCODE_HA_FAAUTHFAILED          132
#define MOBILEIP_RESPCODE_HA_IDMISMATCH            133
#define MOBILEIP_RESPCODE_HA_POORLYFORMEDREQ       134
#define MOBILEIP_RESPCODE_HA_TOOMANYSMB            135
#define MOBILEIP_RESPCODE_HA_UNKNOWNHAADDR         136

/*
 * Mobile IP extensions
 */

#define MOBILEIP_EXT_MHAUTH            32 /* RFC 2002 */
#define MOBILEIP_EXT_MFAUTH            33 /* RFC 2002 */
#define MOBILEIP_EXT_FHAUTH            34 /* RFC 2002 */
#define MOBILEIP_EXT_GENMOBILEIPAUTH   36 /* RFC 3012 */
#define MOBILEIP_EXT_CVSE              38 /* RFC 3025 */
#define MOBILEIP_EXT_SESSIONSPECIFIC   39 /* TIA/IS-2001 */
#define MOBILEIP_EXT_REGUPDATEAUTH     40 /* TIA/IS-2001 */
#define MOBILEIP_EXT_NAI               131 /* RFC 2794 */
#define MOBILEIP_EXT_MNFACHALLENGE     132 /* RFC 2794 */

/* 
 * Mobile IP extension map
 */

strmap_t mobileip_ext_map [] = 
{
  { MOBILEIP_EXT_MHAUTH,          "mobile-home authentication" },
  { MOBILEIP_EXT_MFAUTH,          "mobile-foreign authentication" },
  { MOBILEIP_EXT_FHAUTH,          "foreign-home authentication" },
  { MOBILEIP_EXT_GENMOBILEIPAUTH, "generalized Mobile IP authentication" },
  { MOBILEIP_EXT_CVSE,            "critical vendor-specific extension" },
  { MOBILEIP_EXT_SESSIONSPECIFIC, "session specific extension" },
  { MOBILEIP_EXT_REGUPDATEAUTH,   "registration update authentication" },
  { MOBILEIP_EXT_NAI,             "network access identifier" },
  { MOBILEIP_EXT_MNFACHALLENGE,   "MN-FA challenge" },
  { 0, "" }
};

/*
 * Format of Mobile IP registration request
 *
 * 
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |     Type      |S|B|D|M|G|V|rsv|          Lifetime             |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                          Home Address                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                           Home Agent                          |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                        Care-of Address                        |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                                                               |
 * +                         Identification                        +
 * |                                                               |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * | Extensions ...
 * +-+-+-+-+-+-+-+-
 */

typedef struct mobileip_regreq
{
  u_int8_t  type;
  u_int8_t  flags;
  u_int16_t lifetime;
  u_int32_t home_addr;
  u_int32_t home_agent;
  u_int32_t care_of_addr;
  u_int8_t  identification[8];
} mobileip_regreq_t;

/*
 * Format of Mobile IP registration reply
 *
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |     Type      |     Code      |           Lifetime            |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                          Home Address                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                           Home Agent                          |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                                                               |
 * +                         Identification                        +
 * |                                                               |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * | Extensions ...
 * +-+-+-+-+-+-+-+-
 */

typedef struct mobileip_regrep
{
  u_int8_t  type;
  u_int8_t  code;
  u_int16_t lifetime;
  u_int32_t home_addr;
  u_int32_t home_agent;
  u_int8_t  identification[8];
} mobileip_regrep_t;


/*
 * Format of Mobile IP registration update
 * 0                   1                   2                   3 
 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
 * |     Type      |                  Reserved                     | 
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
 * |                          Home Address                         | 
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
 * |                     Home Agent Address                        | 
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
 * |                                                               | 
 * +                         Identification                        + 
 * |                                                               | 
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
 * | Extensions ... 
 * +-+-+-+-+-+-+-+- 
 */

typedef struct mobileip_regupdate
{
  u_int8_t  type;
  u_int8_t  reserved[3];
  u_int32_t home_addr;
  u_int32_t home_agent;
  u_int8_t  identification[8];
} mobileip_regupdate_t;


/*
 * Format of Mobile IP registration ack
 *
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |     Type      |    Status     |           Reserved            |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                          Home Address                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                           Home Agent                          |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                                                               |
 * +                         Identification                        +
 * |                                                               |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * | Extensions ...
 * +-+-+-+-+-+-+-+-
 */

typedef struct mobileip_regack
{
  u_int8_t  type;
  u_int8_t  status;
  u_int16_t reserved;
  u_int32_t home_addr;
  u_int32_t home_agent;
  u_int8_t  identification[8];
} mobileip_regack_t;

/*
 * Structure of the Mobile IP session specific extension
 */

typedef struct mobileip_ext_sessionspecific
{
  u_int8_t      type;
  u_int8_t      length;
  u_int16_t     protocol;
  u_int32_t     key;
  u_int16_t     reserved;
  u_int16_t     mn_session;
  u_int16_t     mn_id_type;
  u_int8_t      mn_id_length;
} mobileip_ext_sessionspecific_t;

/*
 * Structure of the mobile IP CVSE
 */

typedef struct mobileip_ext_cvse
{
  u_int8_t    type;
  u_int8_t    reserved;
  u_int16_t   length;
  u_int32_t   vendor;
  u_int16_t   subtype;
} mobileip_ext_cvse_t;

/*
 * Structure of the mobile IP mobile/home authentication extension
 */

typedef struct mobileip_ext_mhauth
{
  u_int8_t    type;
  u_int8_t    length;
  u_int32_t   spi;
} mobileip_ext_mhauth_t;

/*
 * Structure of the fixed portion of the general mobile IP auth extension
 */

typedef struct mobileip_ext_genmobileipauth
{
  u_int8_t    type;
  u_int8_t    subtype;
  u_int16_t   length;
  u_int32_t   spi;
} mobileip_ext_genmobileipauth_t;

extern struct arg_t * my_args;
extern strmap_t ethertype_map[];

/*----------------------------------------------------------------------------
**
** dump_mobileip_sessionspecificext()
**
** Dumps mobile IP session specific extensions
**
**----------------------------------------------------------------------------
*/

void dump_mobileip_ext_sessionspecific(packet_t *pkt)
{
  mobileip_ext_sessionspecific_t ss;
  u_int8_t * mn_id;

  /* Get the common part of the extension */
  if (get_packet_bytes((u_int8_t *) &ss, pkt, 15) == 0)
    return;

  /* Conversions */
  ss.protocol = ntohs(ss.protocol);
  ss.key = ntohl(ss.key);
  ss.reserved = ntohs(ss.reserved);
  ss.mn_session = ntohs(ss.mn_session);
  ss.mn_id_type = ntohs(ss.mn_id_type);

  /* Display */
  if (my_args->m)
    {
      display_minimal_string(map2str(mobileip_ext_map, ss.type));
      display_minimal_string(" ");
    }
  else
    {
      display_strmap("Extension type", ss.type, mobileip_ext_map);
      display("  Length", &ss.length, 1, DISP_DEC);
      display_strmap_hex("  Protocol", ss.protocol, ethertype_map);
      display("  Key", (u_int8_t *) &ss.key, 4, DISP_HEX);
      display("  Reserved", (u_int8_t *) &ss.reserved, 2, DISP_DEC);
      display("  MN session ref ID", (u_int8_t *) &ss.mn_session, 2, DISP_DEC);
      display("  MN ID type", (u_int8_t *) &ss.mn_id_type, 2, DISP_DEC);
      display("  MN ID length", (u_int8_t *) &ss.mn_id_length, 1, DISP_DEC);
    }

  /* Allocate memeory for the MN ID */
  mn_id = my_malloc(ss.mn_id_length);

  /* Get the MN ID */
  if (get_packet_bytes(mn_id, pkt, ss.mn_id_length) == 0)
    return;

  /* Display the MN ID */
  if (my_args->m)
    {
    }
  else
    display("  MN ID", mn_id, ss.mn_id_length, DISP_HEX);

  /* Deallocate memory for the MN ID */
  my_free(mn_id);

  /* 
   * Check for any padding.  Some PCF's send a full 21 byte option 
   * regardless of the length of the MN ID.  The fixed portion of the
   * option is 13 bytes.
   */

  if (ss.mn_id_length + 13 < ss.length)
    {
      u_int16_t dummy;

      if (get_packet_bytes((u_int8_t *) &dummy, pkt, 
			   ss.length - ss.mn_id_length - 13) == 0)
	return;
    }
  return;
}

/*----------------------------------------------------------------------------
**
** dump_mobileip_ext_csve()
**
** Dumps mobile IP critical / vendor specific extensions
**
**----------------------------------------------------------------------------
*/

void dump_mobileip_ext_cvse(packet_t * pkt)
{
  mobileip_ext_cvse_t cvse;
  u_int8_t * data;

  /* Get the common part of the header */
  if (get_packet_bytes((u_int8_t *) &cvse, pkt, 10) == 0)
    return;
  
  /* Conversions */
  cvse.length = ntohs(cvse.length);
  cvse.vendor = ntohl(cvse.vendor);
  cvse.subtype = ntohs(cvse.subtype);

  /* Display */
  if (my_args->m)
    {
      display_minimal_string(map2str(mobileip_ext_map, cvse.type));
      display_minimal_string(" ");
    }
  else
    {
      display_strmap("Extention type", cvse.type, mobileip_ext_map);
      display("  Reserved", &cvse.reserved, 1, DISP_DEC);
      display("  Length", (u_int8_t *) &cvse.length, 2, DISP_DEC);
      display("  Vendor ID", (u_int8_t *) &cvse.vendor, 4, DISP_DEC);
      display("  Subtype", (u_int8_t *) &cvse.subtype, 2, DISP_DEC);
    }

  if (cvse.length > 6)
    {
      /* Allocate memory for data */
      data = my_malloc(cvse.length-6);
  
      /* Get data portion */
      if (get_packet_bytes(data, pkt, cvse.length-6) == 0)
	return;
      
      /* Display data portion */
      if (!my_args->m)
	display("  Data", data, cvse.length-6, DISP_HEX_MULTILINE);
      
      /* Free memory for data */
      my_free(data);
    }
}

/*----------------------------------------------------------------------------
**
** dump_mobileip_ext_nai()
**
** Dumps mobile IP NAI extension
**
**----------------------------------------------------------------------------
*/

void dump_mobileip_ext_nai(packet_t * pkt)
{
  u_int8_t    type;
  u_int8_t    length;
  char *      nai;
  
  /* Get the type */
  if (get_packet_bytes((u_int8_t *) &type, pkt, 1) == 0)
    return;

  /* Get the length */
  if (get_packet_bytes((u_int8_t *) &length, pkt, 1) == 0)
    return;
 
  /* Get the NAI */
  nai = (char *) malloc (length+2);
  if (get_packet_bytes(nai, pkt, length) == 0)
    return;
  nai[length] = '\0';
  
  /* Display */
  if (my_args->m)
    {
    }
  else
    {
      display_strmap("Extension type", type, mobileip_ext_map);
      display("  Length", (u_int8_t *) &length, 1, DISP_DEC);
      display_string("  NAI", nai);
    }

  /* Free memory */
  my_free(nai);
 
  return;
}

/*----------------------------------------------------------------------------
**
** dump_mobileip_ext_mnfachallenge()
**
** Dumps mobile IP MN-FA  extension
**
**----------------------------------------------------------------------------
*/

void dump_mobileip_ext_mnfachallenge(packet_t * pkt)
{
  u_int8_t    type;
  u_int8_t    length;
  u_int8_t *  challenge;
  
  /* Get the type */
  if (get_packet_bytes((u_int8_t *) &type, pkt, 1) == 0)
    return;

  /* Get the length */
  if (get_packet_bytes((u_int8_t *) &length, pkt, 1) == 0)
    return;
 
  /* Get the authenticator */
  challenge = (char *) malloc (length+2);
  if (get_packet_bytes((u_int8_t *) challenge, pkt, length) == 0)
    return;
  
  /* Display */
  if (my_args->m)
    {
    }
  else
    {
      display_strmap("Extension type", type, mobileip_ext_map);
      display("  Length", (u_int8_t *) &length, 1, DISP_DEC);
      display("  Challenge", (u_int8_t *) challenge, length, DISP_HEX);
    }

  /* Free memory */
  my_free(challenge);
 
  return;
}


/*----------------------------------------------------------------------------
**
** dump_mobileip_ext_genmobileipauth()
**
** Dumps the general MIP authentication extension
**
**----------------------------------------------------------------------------
*/

void dump_mobileip_ext_genmobileipauth(packet_t * pkt)
{
  mobileip_ext_genmobileipauth_t  genmip;
  u_int8_t *                      auth;

  /* Get the fixed header */
  if (get_packet_bytes((u_int8_t *) &genmip, pkt, 8) == 0)
   return;

  /* Conversions */
  genmip.length = ntohs(genmip.length);

  /* Allocate memory for the authentication */
  auth = my_malloc(genmip.length-4);

  /* Get the authenticator */
  if (get_packet_bytes(auth, pkt, genmip.length-4) == 0)
    return;

  /* Display */
  if (my_args->m)
    {
    }
  else
    {
      display_strmap("Extension type", genmip.type, mobileip_ext_map);
      display("  Subtype", &genmip.subtype, 1, DISP_DEC);
      display("  Length", (u_int8_t *) &genmip.length, 2, DISP_DEC);
      display("  SPI", (u_int8_t *) &genmip.spi, 4, DISP_HEX);
      display("  Authenticator", auth, genmip.length-4, DISP_HEX_MULTILINE);
    }

  /* Free memory for authenticator */
  my_free(auth);

  return;

}

/*----------------------------------------------------------------------------
**
** dump_mobileip_ext_mhauth()
**
** Dumps mobile IP mobile/home authentication extension messages
**
**----------------------------------------------------------------------------
*/

void dump_mobileip_ext_mhauth(packet_t * pkt)
{
  mobileip_ext_mhauth_t mh;
  u_int8_t * authenticator;

  /* Read all but the authenticator */
  if (get_packet_bytes((u_int8_t *) &mh, pkt, 6) == 0)
    return;

  /* Conversions */
  mh.spi = ntohl(mh.spi);

  /* Allocate memory for authenticator */
  authenticator = my_malloc(mh.length-4);

  /* Read authenticator */
  if (get_packet_bytes(authenticator, pkt, mh.length-4) == 0)
    return;

  /* Display */
  if (my_args->m)
    {
      display_minimal_string(map2str(mobileip_ext_map, mh.type));
      display_minimal_string(" ");
    }
  else
    {
      display_strmap("Extension type", mh.type, mobileip_ext_map);
      display("  Length", &mh.length, 1, DISP_DEC);
      display("  SPI", (u_int8_t *) &mh.spi, 4, DISP_HEX);
      display("  Authenticator", authenticator, mh.length-4, 
	      DISP_HEX_MULTILINE);
    }

  /* Free memory for authenticator */
  my_free(authenticator);

  return;
}

/*----------------------------------------------------------------------------
**
** dump_mobileip()
**
** Dumps mobile IP messages
**
**----------------------------------------------------------------------------
*/

void dump_mobileip(packet_t *pkt)
{
  u_int8_t          first_byte;

  /* Set the layer */
  set_layer(LAYER_APPLICATION);

  /*
   * Look at the first byte to determine the type
   */

  if (look_packet_bytes(&first_byte, pkt, 1) == 0)
    return;

  /* 
   * Display mobile IP annoucnement
   */

  if (my_args->m)
    display_minimal_string("| Mobile IP ");
  else
    display_header_banner("Mobile IP");

  /* 
   * Take action based on message type
   */

  switch(first_byte)
    {
    case MOBILEIP_TYPE_REGREQ: /* registration request */
      {
	mobileip_regreq_t regreq;
	
	/* Get the message */
	if (get_packet_bytes((u_int8_t *) &regreq, pkt, sizeof(regreq)) == 0)
	  return;

	/* Conversions */
	regreq.lifetime = ntohs(regreq.lifetime);

	/* Display */
	if (my_args->m)
	  {
	    display_minimal_string(map2str(mobileip_type_map, regreq.type));
	    display_minimal_string(" (");
	    display_minimal_string("addr:");
	    display_minimal_ipv4((u_int8_t *) &regreq.home_addr);
	    display_minimal_string(",HA:");
	    display_minimal_ipv4((u_int8_t *) &regreq.home_agent);
	    display_minimal_string(",COA:");
	    display_minimal_ipv4((u_int8_t *) &regreq.care_of_addr);
	    display_minimal_string(") ");
	  }
	else
	  {
	    display_strmap("Type", regreq.type, mobileip_type_map);
	    display("Flags", &regreq.flags, 1, DISP_HEX);
	    display("Lifetime", (u_int8_t *) &regreq.lifetime, 2, DISP_DEC);
	    display_ipv4("Home address", (u_int8_t *) &regreq.home_addr);
	    display_ipv4("Home agent", (u_int8_t *) &regreq.home_agent);
	    display_ipv4("Care of address", (u_int8_t *) &regreq.care_of_addr);
	    display("Identification", (u_int8_t *) &regreq.identification, 8, 
		    DISP_HEX);
	  }
      }
      break;

    case MOBILEIP_TYPE_REGREP: /* registration response */
      {
	mobileip_regrep_t regrep;

	/* Get the message */
	if (get_packet_bytes((u_int8_t *) &regrep, pkt, sizeof(regrep)) == 0)
	  return;

	/* Conversions */
	regrep.lifetime = ntohs(regrep.lifetime);

	/* Display */
	if (my_args->m)
	  {
	    display_minimal_string(map2str(mobileip_type_map, regrep.type));
	    display_minimal_string(" (");
	    display_minimal_string("addr:");
	    display_minimal_ipv4((u_int8_t *) &regrep.home_addr);
	    display_minimal_string(",HA:");
	    display_minimal_ipv4((u_int8_t *) &regrep.home_agent);
	    display_minimal_string(") ");
	  }
	else
	  {
	    display_strmap("Type", regrep.type, mobileip_type_map);
	    display("Code", &regrep.code, 1, DISP_HEX);
	    display("Lifetime", (u_int8_t *) &regrep.lifetime, 2, DISP_DEC);
	    display_ipv4("Home address", (u_int8_t *) &regrep.home_addr);
	    display_ipv4("Home agent", (u_int8_t *) &regrep.home_agent);
	    display("Identification", (u_int8_t *) &regrep.identification, 8, 
		    DISP_HEX);
	  }
      }
      break;

    case MOBILEIP_TYPE_REGUPDATE: /* registration update */
      { 
	mobileip_regupdate_t regupdate;

	/* Get the message */
	if (get_packet_bytes((u_int8_t *) &regupdate, pkt, sizeof(regupdate)) 
	    == 0)
	  return;

	/* Display */
	if (my_args->m)
	  {
	    display_minimal_string(map2str(mobileip_type_map, regupdate.type));
	    display_minimal_string(" (");
	    display_minimal_string("addr:");
	    display_minimal_ipv4((u_int8_t *) &regupdate.home_addr);
	    display_minimal_string(",HA:");
	    display_minimal_ipv4((u_int8_t *) &regupdate.home_agent);
	    display_minimal_string(") ");
	  }
	else
	  {
	    display_strmap("Type", regupdate.type, mobileip_type_map);
	    display("Reserved", (u_int8_t *) &regupdate.reserved, 3, DISP_DEC);
	    display_ipv4("Home address", (u_int8_t *) &regupdate.home_addr);
	    display_ipv4("Home agent", (u_int8_t *) &regupdate.home_agent);
	    display("Identification", (u_int8_t *) &regupdate.identification, 
		    8, DISP_HEX);
	  }
      }
      break;
      
    case MOBILEIP_TYPE_REGACK: /* registration ack */
      {
	mobileip_regack_t regack;

	/* Get the message */
	if (get_packet_bytes((u_int8_t *) &regack, pkt, sizeof(regack)) == 0)
	  return;

	/* Conversions */
	regack.reserved = ntohs(regack.reserved);

	/* Display */
	if (my_args->m)
	  {
	    display_minimal_string(map2str(mobileip_type_map, regack.type));
	    display_minimal_string(" (");
	    display_minimal_string("addr:");
	    display_minimal_ipv4((u_int8_t *) &regack.home_addr);
	    display_minimal_string(",HA:");
	    display_minimal_ipv4((u_int8_t *) &regack.home_agent);
	    display_minimal_string(") ");
	  }
	else
	  {
	    display_strmap("Type", regack.type, mobileip_type_map);
	    display("Status", &regack.status, 1, DISP_HEX);
	    display("Reserved", (u_int8_t *) &regack.reserved, 2, DISP_DEC);
	    display_ipv4("Home address", (u_int8_t *) &regack.home_addr);
	    display_ipv4("Home agent", (u_int8_t *) &regack.home_agent);
	    display("Identification", (u_int8_t *) &regack.identification, 8, 
		    DISP_HEX);
	  }
      }
      break;

    default: /* Unknown message type, dump the hexbuffer and quit */
      hexbuffer_flush();
      return;
    }

  /* 
   * Look for extensions. Note that since not all mobile IP extensions 
   * follow the RFC 2002 method (type-length-value) we may cause weird
   * problems by assuming that there is a valid length after the type.
   */

  while (get_packet_apparentbytesleft(pkt))
    {
      u_int8_t type;

      /* Get the next byte, which should be the type of the extension */
      if (look_packet_bytes(&type, pkt, 1) == 0)
	{
	  hexbuffer_flush();
	  return;
	}

      /* Decide what to do based on the extension type */
      switch(type)
	{
	case MOBILEIP_EXT_SESSIONSPECIFIC:
	  dump_mobileip_ext_sessionspecific(pkt);
	  break;

	case MOBILEIP_EXT_CVSE:
	  dump_mobileip_ext_cvse(pkt);
	  break;

	case MOBILEIP_EXT_MHAUTH:
	case MOBILEIP_EXT_REGUPDATEAUTH:
	  dump_mobileip_ext_mhauth(pkt);
	  break;

        case MOBILEIP_EXT_NAI:
          dump_mobileip_ext_nai(pkt);
          break;
 
        case MOBILEIP_EXT_MNFACHALLENGE:
          dump_mobileip_ext_mnfachallenge(pkt);
          break;

        case MOBILEIP_EXT_GENMOBILEIPAUTH:
          dump_mobileip_ext_genmobileipauth(pkt);
          break;

	default: /* We don't recognize this extension...just dump the data */
	  {
	    u_int8_t   type;
	    u_int8_t   length;
	    u_int8_t * data;

	    /* Get the type and the length */
	    if (get_packet_bytes(&type, pkt, 1) == 0) 
	      return;
	    if (get_packet_bytes(&length, pkt, 1) == 0)
	      return;

	    /* Display the type and the length */
	    if (my_args->m)
	      {
		
	      }
	    else
	      {
		display_strmap("Extension type", type, mobileip_ext_map);
		display("  Length", &length, 1, DISP_DEC);
	      }

	    /* Allocate memory for the data */
	    data = my_malloc(length);

	    /* Get the data */
	    if (get_packet_bytes(data, pkt, length) == 0)
              {
                hexbuffer_flush();
	        return;
              } 

	    /* 
	     * Dump the data. Let's not do anything for minimal mode because
	     * it would probably just clutter the display 
	     */

	    if (!my_args->m)
	      {
		display("  Data", data, length, DISP_HEX_MULTILINE);
	      }

	    /* Deallocate memory for the data */
	    my_free(data);
	  }
	  break;
	}
    }

  /* Dump the hex buffer */
  hexbuffer_flush();

  return;
}


syntax highlighted by Code2HTML, v. 0.9.1