| /* |
| * Copyright (C) 2002 WIDE Project. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the project nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #ifndef lint |
| static const char rcsid[] _U_ = |
| "@(#) $Header: /tcpdump/master/tcpdump/print-mobility.c,v 1.12 2005-04-20 22:21:00 guy Exp $"; |
| #endif |
| |
| #ifdef INET6 |
| #include <tcpdump-stdinc.h> |
| |
| #include <stdio.h> |
| |
| #include "ip6.h" |
| |
| #include "interface.h" |
| #include "addrtoname.h" |
| #include "extract.h" /* must come after interface.h */ |
| |
| /* Mobility header */ |
| struct ip6_mobility { |
| u_int8_t ip6m_pproto; /* following payload protocol (for PG) */ |
| u_int8_t ip6m_len; /* length in units of 8 octets */ |
| u_int8_t ip6m_type; /* message type */ |
| u_int8_t reserved; /* reserved */ |
| u_int16_t ip6m_cksum; /* sum of IPv6 pseudo-header and MH */ |
| union { |
| u_int16_t ip6m_un_data16[1]; /* type-specific field */ |
| u_int8_t ip6m_un_data8[2]; /* type-specific fiedl */ |
| } ip6m_dataun; |
| }; |
| |
| #define ip6m_data16 ip6m_dataun.ip6m_un_data16 |
| #define ip6m_data8 ip6m_dataun.ip6m_un_data8 |
| |
| #define IP6M_MINLEN 8 |
| |
| /* message type */ |
| #define IP6M_BINDING_REQUEST 0 /* Binding Refresh Request */ |
| #define IP6M_HOME_TEST_INIT 1 /* Home Test Init */ |
| #define IP6M_CAREOF_TEST_INIT 2 /* Care-of Test Init */ |
| #define IP6M_HOME_TEST 3 /* Home Test */ |
| #define IP6M_CAREOF_TEST 4 /* Care-of Test */ |
| #define IP6M_BINDING_UPDATE 5 /* Binding Update */ |
| #define IP6M_BINDING_ACK 6 /* Binding Acknowledgement */ |
| #define IP6M_BINDING_ERROR 7 /* Binding Error */ |
| |
| /* Mobility Header Options */ |
| #define IP6MOPT_MINLEN 2 |
| #define IP6MOPT_PAD1 0x0 /* Pad1 */ |
| #define IP6MOPT_PADN 0x1 /* PadN */ |
| #define IP6MOPT_REFRESH 0x2 /* Binding Refresh Advice */ |
| #define IP6MOPT_REFRESH_MINLEN 4 |
| #define IP6MOPT_ALTCOA 0x3 /* Alternate Care-of Address */ |
| #define IP6MOPT_ALTCOA_MINLEN 18 |
| #define IP6MOPT_NONCEID 0x4 /* Nonce Indices */ |
| #define IP6MOPT_NONCEID_MINLEN 6 |
| #define IP6MOPT_AUTH 0x5 /* Binding Authorization Data */ |
| #define IP6MOPT_AUTH_MINLEN 12 |
| |
| static void |
| mobility_opt_print(const u_char *bp, int len) |
| { |
| int i; |
| int optlen; |
| |
| for (i = 0; i < len; i += optlen) { |
| if (bp[i] == IP6MOPT_PAD1) |
| optlen = 1; |
| else { |
| if (i + 1 < len) |
| optlen = bp[i + 1] + 2; |
| else |
| goto trunc; |
| } |
| if (i + optlen > len) |
| goto trunc; |
| |
| switch (bp[i]) { |
| case IP6MOPT_PAD1: |
| printf("(pad1)"); |
| break; |
| case IP6MOPT_PADN: |
| if (len - i < IP6MOPT_MINLEN) { |
| printf("(padn: trunc)"); |
| goto trunc; |
| } |
| printf("(padn)"); |
| break; |
| case IP6MOPT_REFRESH: |
| if (len - i < IP6MOPT_REFRESH_MINLEN) { |
| printf("(refresh: trunc)"); |
| goto trunc; |
| } |
| /* units of 4 secs */ |
| printf("(refresh: %d)", |
| EXTRACT_16BITS(&bp[i+2]) << 2); |
| break; |
| case IP6MOPT_ALTCOA: |
| if (len - i < IP6MOPT_ALTCOA_MINLEN) { |
| printf("(altcoa: trunc)"); |
| goto trunc; |
| } |
| printf("(alt-CoA: %s)", ip6addr_string(&bp[i+2])); |
| break; |
| case IP6MOPT_NONCEID: |
| if (len - i < IP6MOPT_NONCEID_MINLEN) { |
| printf("(ni: trunc)"); |
| goto trunc; |
| } |
| printf("(ni: ho=0x%04x co=0x%04x)", |
| EXTRACT_16BITS(&bp[i+2]), |
| EXTRACT_16BITS(&bp[i+4])); |
| break; |
| case IP6MOPT_AUTH: |
| if (len - i < IP6MOPT_AUTH_MINLEN) { |
| printf("(auth: trunc)"); |
| goto trunc; |
| } |
| printf("(auth)"); |
| break; |
| default: |
| if (len - i < IP6MOPT_MINLEN) { |
| printf("(sopt_type %d: trunc)", bp[i]); |
| goto trunc; |
| } |
| printf("(type-0x%02x: len=%d)", bp[i], bp[i + 1]); |
| break; |
| } |
| } |
| return; |
| |
| trunc: |
| printf("[trunc] "); |
| } |
| |
| /* |
| * Mobility Header |
| */ |
| int |
| mobility_print(const u_char *bp, const u_char *bp2 _U_) |
| { |
| const struct ip6_mobility *mh; |
| const u_char *ep; |
| int mhlen, hlen, type; |
| |
| mh = (struct ip6_mobility *)bp; |
| |
| /* 'ep' points to the end of available data. */ |
| ep = snapend; |
| |
| if (!TTEST(mh->ip6m_len)) { |
| /* |
| * There's not enough captured data to include the |
| * mobility header length. |
| * |
| * Our caller expects us to return the length, however, |
| * so return a value that will run to the end of the |
| * captured data. |
| * |
| * XXX - "ip6_print()" doesn't do anything with the |
| * returned length, however, as it breaks out of the |
| * header-processing loop. |
| */ |
| mhlen = ep - bp; |
| goto trunc; |
| } |
| mhlen = (int)((mh->ip6m_len + 1) << 3); |
| |
| /* XXX ip6m_cksum */ |
| |
| TCHECK(mh->ip6m_type); |
| type = mh->ip6m_type; |
| switch (type) { |
| case IP6M_BINDING_REQUEST: |
| printf("mobility: BRR"); |
| hlen = IP6M_MINLEN; |
| break; |
| case IP6M_HOME_TEST_INIT: |
| case IP6M_CAREOF_TEST_INIT: |
| printf("mobility: %soTI", |
| type == IP6M_HOME_TEST_INIT ? "H" : "C"); |
| hlen = IP6M_MINLEN; |
| if (vflag) { |
| TCHECK2(*mh, hlen + 8); |
| printf(" %s Init Cookie=%08x:%08x", |
| type == IP6M_HOME_TEST_INIT ? "Home" : "Care-of", |
| EXTRACT_32BITS(&bp[hlen]), |
| EXTRACT_32BITS(&bp[hlen + 4])); |
| } |
| hlen += 8; |
| break; |
| case IP6M_HOME_TEST: |
| case IP6M_CAREOF_TEST: |
| printf("mobility: %soT", |
| type == IP6M_HOME_TEST ? "H" : "C"); |
| TCHECK(mh->ip6m_data16[0]); |
| printf(" nonce id=0x%x", EXTRACT_16BITS(&mh->ip6m_data16[0])); |
| hlen = IP6M_MINLEN; |
| if (vflag) { |
| TCHECK2(*mh, hlen + 8); |
| printf(" %s Init Cookie=%08x:%08x", |
| type == IP6M_HOME_TEST ? "Home" : "Care-of", |
| EXTRACT_32BITS(&bp[hlen]), |
| EXTRACT_32BITS(&bp[hlen + 4])); |
| } |
| hlen += 8; |
| if (vflag) { |
| TCHECK2(*mh, hlen + 8); |
| printf(" %s Keygen Token=%08x:%08x", |
| type == IP6M_HOME_TEST ? "Home" : "Care-of", |
| EXTRACT_32BITS(&bp[hlen]), |
| EXTRACT_32BITS(&bp[hlen + 4])); |
| } |
| hlen += 8; |
| break; |
| case IP6M_BINDING_UPDATE: |
| printf("mobility: BU"); |
| TCHECK(mh->ip6m_data16[0]); |
| printf(" seq#=%d", EXTRACT_16BITS(&mh->ip6m_data16[0])); |
| hlen = IP6M_MINLEN; |
| TCHECK2(*mh, hlen + 1); |
| if (bp[hlen] & 0xf0) |
| printf(" "); |
| if (bp[hlen] & 0x80) |
| printf("A"); |
| if (bp[hlen] & 0x40) |
| printf("H"); |
| if (bp[hlen] & 0x20) |
| printf("L"); |
| if (bp[hlen] & 0x10) |
| printf("K"); |
| /* Reserved (4bits) */ |
| hlen += 1; |
| /* Reserved (8bits) */ |
| hlen += 1; |
| TCHECK2(*mh, hlen + 2); |
| /* units of 4 secs */ |
| printf(" lifetime=%d", EXTRACT_16BITS(&bp[hlen]) << 2); |
| hlen += 2; |
| break; |
| case IP6M_BINDING_ACK: |
| printf("mobility: BA"); |
| TCHECK(mh->ip6m_data8[0]); |
| printf(" status=%d", mh->ip6m_data8[0]); |
| if (mh->ip6m_data8[1] & 0x80) |
| printf(" K"); |
| /* Reserved (7bits) */ |
| hlen = IP6M_MINLEN; |
| TCHECK2(*mh, hlen + 2); |
| printf(" seq#=%d", EXTRACT_16BITS(&bp[hlen])); |
| hlen += 2; |
| TCHECK2(*mh, hlen + 2); |
| /* units of 4 secs */ |
| printf(" lifetime=%d", EXTRACT_16BITS(&bp[hlen]) << 2); |
| hlen += 2; |
| break; |
| case IP6M_BINDING_ERROR: |
| printf("mobility: BE"); |
| TCHECK(mh->ip6m_data8[0]); |
| printf(" status=%d", mh->ip6m_data8[0]); |
| /* Reserved */ |
| hlen = IP6M_MINLEN; |
| TCHECK2(*mh, hlen + 16); |
| printf(" homeaddr %s", ip6addr_string(&bp[hlen])); |
| hlen += 16; |
| break; |
| default: |
| printf("mobility: type-#%d len=%d", type, mh->ip6m_len); |
| return(mhlen); |
| break; |
| } |
| if (vflag) |
| mobility_opt_print(&bp[hlen], mhlen - hlen); |
| |
| return(mhlen); |
| |
| trunc: |
| fputs("[|MOBILITY]", stdout); |
| return(mhlen); |
| } |
| #endif /* INET6 */ |