print-mobility.c revision 1.7
1/* 2 * Copyright (C) 2002 WIDE Project. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the project nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31#ifndef lint 32__RCSID("$NetBSD: print-mobility.c,v 1.7 2017/02/05 04:05:05 spz Exp $"); 33#endif 34 35/* \summary: IPv6 mobility printer */ 36 37#ifdef HAVE_CONFIG_H 38#include "config.h" 39#endif 40 41#include <netdissect-stdinc.h> 42 43#include "ip6.h" 44#include "netdissect.h" 45#include "addrtoname.h" 46#include "extract.h" 47 48static const char tstr[] = "[|MOBILITY]"; 49 50/* Mobility header */ 51struct ip6_mobility { 52 uint8_t ip6m_pproto; /* following payload protocol (for PG) */ 53 uint8_t ip6m_len; /* length in units of 8 octets */ 54 uint8_t ip6m_type; /* message type */ 55 uint8_t reserved; /* reserved */ 56 uint16_t ip6m_cksum; /* sum of IPv6 pseudo-header and MH */ 57 union { 58 uint16_t ip6m_un_data16[1]; /* type-specific field */ 59 uint8_t ip6m_un_data8[2]; /* type-specific field */ 60 } ip6m_dataun; 61}; 62 63#define ip6m_data16 ip6m_dataun.ip6m_un_data16 64#define ip6m_data8 ip6m_dataun.ip6m_un_data8 65 66#define IP6M_MINLEN 8 67 68/* http://www.iana.org/assignments/mobility-parameters/mobility-parameters.xhtml */ 69 70/* message type */ 71#define IP6M_BINDING_REQUEST 0 /* Binding Refresh Request */ 72#define IP6M_HOME_TEST_INIT 1 /* Home Test Init */ 73#define IP6M_CAREOF_TEST_INIT 2 /* Care-of Test Init */ 74#define IP6M_HOME_TEST 3 /* Home Test */ 75#define IP6M_CAREOF_TEST 4 /* Care-of Test */ 76#define IP6M_BINDING_UPDATE 5 /* Binding Update */ 77#define IP6M_BINDING_ACK 6 /* Binding Acknowledgement */ 78#define IP6M_BINDING_ERROR 7 /* Binding Error */ 79#define IP6M_MAX 7 80 81static const struct tok ip6m_str[] = { 82 { IP6M_BINDING_REQUEST, "BRR" }, 83 { IP6M_HOME_TEST_INIT, "HoTI" }, 84 { IP6M_CAREOF_TEST_INIT, "CoTI" }, 85 { IP6M_HOME_TEST, "HoT" }, 86 { IP6M_CAREOF_TEST, "CoT" }, 87 { IP6M_BINDING_UPDATE, "BU" }, 88 { IP6M_BINDING_ACK, "BA" }, 89 { IP6M_BINDING_ERROR, "BE" }, 90 { 0, NULL } 91}; 92 93static const unsigned ip6m_hdrlen[IP6M_MAX + 1] = { 94 IP6M_MINLEN, /* IP6M_BINDING_REQUEST */ 95 IP6M_MINLEN + 8, /* IP6M_HOME_TEST_INIT */ 96 IP6M_MINLEN + 8, /* IP6M_CAREOF_TEST_INIT */ 97 IP6M_MINLEN + 16, /* IP6M_HOME_TEST */ 98 IP6M_MINLEN + 16, /* IP6M_CAREOF_TEST */ 99 IP6M_MINLEN + 4, /* IP6M_BINDING_UPDATE */ 100 IP6M_MINLEN + 4, /* IP6M_BINDING_ACK */ 101 IP6M_MINLEN + 16, /* IP6M_BINDING_ERROR */ 102}; 103 104/* Mobility Header Options */ 105#define IP6MOPT_MINLEN 2 106#define IP6MOPT_PAD1 0x0 /* Pad1 */ 107#define IP6MOPT_PADN 0x1 /* PadN */ 108#define IP6MOPT_REFRESH 0x2 /* Binding Refresh Advice */ 109#define IP6MOPT_REFRESH_MINLEN 4 110#define IP6MOPT_ALTCOA 0x3 /* Alternate Care-of Address */ 111#define IP6MOPT_ALTCOA_MINLEN 18 112#define IP6MOPT_NONCEID 0x4 /* Nonce Indices */ 113#define IP6MOPT_NONCEID_MINLEN 6 114#define IP6MOPT_AUTH 0x5 /* Binding Authorization Data */ 115#define IP6MOPT_AUTH_MINLEN 12 116 117static int 118mobility_opt_print(netdissect_options *ndo, 119 const u_char *bp, const unsigned len) 120{ 121 unsigned i, optlen; 122 123 for (i = 0; i < len; i += optlen) { 124 ND_TCHECK(bp[i]); 125 if (bp[i] == IP6MOPT_PAD1) 126 optlen = 1; 127 else { 128 if (i + 1 < len) { 129 ND_TCHECK(bp[i + 1]); 130 optlen = bp[i + 1] + 2; 131 } 132 else 133 goto trunc; 134 } 135 if (i + optlen > len) 136 goto trunc; 137 ND_TCHECK(bp[i + optlen]); 138 139 switch (bp[i]) { 140 case IP6MOPT_PAD1: 141 ND_PRINT((ndo, "(pad1)")); 142 break; 143 case IP6MOPT_PADN: 144 if (len - i < IP6MOPT_MINLEN) { 145 ND_PRINT((ndo, "(padn: trunc)")); 146 goto trunc; 147 } 148 ND_PRINT((ndo, "(padn)")); 149 break; 150 case IP6MOPT_REFRESH: 151 if (len - i < IP6MOPT_REFRESH_MINLEN) { 152 ND_PRINT((ndo, "(refresh: trunc)")); 153 goto trunc; 154 } 155 /* units of 4 secs */ 156 ND_PRINT((ndo, "(refresh: %u)", 157 EXTRACT_16BITS(&bp[i+2]) << 2)); 158 break; 159 case IP6MOPT_ALTCOA: 160 if (len - i < IP6MOPT_ALTCOA_MINLEN) { 161 ND_PRINT((ndo, "(altcoa: trunc)")); 162 goto trunc; 163 } 164 ND_PRINT((ndo, "(alt-CoA: %s)", ip6addr_string(ndo, &bp[i+2]))); 165 break; 166 case IP6MOPT_NONCEID: 167 if (len - i < IP6MOPT_NONCEID_MINLEN) { 168 ND_PRINT((ndo, "(ni: trunc)")); 169 goto trunc; 170 } 171 ND_PRINT((ndo, "(ni: ho=0x%04x co=0x%04x)", 172 EXTRACT_16BITS(&bp[i+2]), 173 EXTRACT_16BITS(&bp[i+4]))); 174 break; 175 case IP6MOPT_AUTH: 176 if (len - i < IP6MOPT_AUTH_MINLEN) { 177 ND_PRINT((ndo, "(auth: trunc)")); 178 goto trunc; 179 } 180 ND_PRINT((ndo, "(auth)")); 181 break; 182 default: 183 if (len - i < IP6MOPT_MINLEN) { 184 ND_PRINT((ndo, "(sopt_type %u: trunc)", bp[i])); 185 goto trunc; 186 } 187 ND_PRINT((ndo, "(type-0x%02x: len=%u)", bp[i], bp[i + 1])); 188 break; 189 } 190 } 191 return 0; 192 193trunc: 194 return 1; 195} 196 197/* 198 * Mobility Header 199 */ 200int 201mobility_print(netdissect_options *ndo, 202 const u_char *bp, const u_char *bp2 _U_) 203{ 204 const struct ip6_mobility *mh; 205 const u_char *ep; 206 unsigned mhlen, hlen; 207 uint8_t type; 208 209 mh = (const struct ip6_mobility *)bp; 210 211 /* 'ep' points to the end of available data. */ 212 ep = ndo->ndo_snapend; 213 214 if (!ND_TTEST(mh->ip6m_len)) { 215 /* 216 * There's not enough captured data to include the 217 * mobility header length. 218 * 219 * Our caller expects us to return the length, however, 220 * so return a value that will run to the end of the 221 * captured data. 222 * 223 * XXX - "ip6_print()" doesn't do anything with the 224 * returned length, however, as it breaks out of the 225 * header-processing loop. 226 */ 227 mhlen = ep - bp; 228 goto trunc; 229 } 230 mhlen = (mh->ip6m_len + 1) << 3; 231 232 /* XXX ip6m_cksum */ 233 234 ND_TCHECK(mh->ip6m_type); 235 type = mh->ip6m_type; 236 if (type <= IP6M_MAX && mhlen < ip6m_hdrlen[type]) { 237 ND_PRINT((ndo, "(header length %u is too small for type %u)", mhlen, type)); 238 goto trunc; 239 } 240 ND_PRINT((ndo, "mobility: %s", tok2str(ip6m_str, "type-#%u", type))); 241 switch (type) { 242 case IP6M_BINDING_REQUEST: 243 hlen = IP6M_MINLEN; 244 break; 245 case IP6M_HOME_TEST_INIT: 246 case IP6M_CAREOF_TEST_INIT: 247 hlen = IP6M_MINLEN; 248 if (ndo->ndo_vflag) { 249 ND_TCHECK2(*mh, hlen + 8); 250 ND_PRINT((ndo, " %s Init Cookie=%08x:%08x", 251 type == IP6M_HOME_TEST_INIT ? "Home" : "Care-of", 252 EXTRACT_32BITS(&bp[hlen]), 253 EXTRACT_32BITS(&bp[hlen + 4]))); 254 } 255 hlen += 8; 256 break; 257 case IP6M_HOME_TEST: 258 case IP6M_CAREOF_TEST: 259 ND_TCHECK(mh->ip6m_data16[0]); 260 ND_PRINT((ndo, " nonce id=0x%x", EXTRACT_16BITS(&mh->ip6m_data16[0]))); 261 hlen = IP6M_MINLEN; 262 if (ndo->ndo_vflag) { 263 ND_TCHECK2(*mh, hlen + 8); 264 ND_PRINT((ndo, " %s Init Cookie=%08x:%08x", 265 type == IP6M_HOME_TEST ? "Home" : "Care-of", 266 EXTRACT_32BITS(&bp[hlen]), 267 EXTRACT_32BITS(&bp[hlen + 4]))); 268 } 269 hlen += 8; 270 if (ndo->ndo_vflag) { 271 ND_TCHECK2(*mh, hlen + 8); 272 ND_PRINT((ndo, " %s Keygen Token=%08x:%08x", 273 type == IP6M_HOME_TEST ? "Home" : "Care-of", 274 EXTRACT_32BITS(&bp[hlen]), 275 EXTRACT_32BITS(&bp[hlen + 4]))); 276 } 277 hlen += 8; 278 break; 279 case IP6M_BINDING_UPDATE: 280 ND_TCHECK(mh->ip6m_data16[0]); 281 ND_PRINT((ndo, " seq#=%u", EXTRACT_16BITS(&mh->ip6m_data16[0]))); 282 hlen = IP6M_MINLEN; 283 ND_TCHECK2(*mh, hlen + 1); 284 if (bp[hlen] & 0xf0) 285 ND_PRINT((ndo, " ")); 286 if (bp[hlen] & 0x80) 287 ND_PRINT((ndo, "A")); 288 if (bp[hlen] & 0x40) 289 ND_PRINT((ndo, "H")); 290 if (bp[hlen] & 0x20) 291 ND_PRINT((ndo, "L")); 292 if (bp[hlen] & 0x10) 293 ND_PRINT((ndo, "K")); 294 /* Reserved (4bits) */ 295 hlen += 1; 296 /* Reserved (8bits) */ 297 hlen += 1; 298 ND_TCHECK2(*mh, hlen + 2); 299 /* units of 4 secs */ 300 ND_PRINT((ndo, " lifetime=%u", EXTRACT_16BITS(&bp[hlen]) << 2)); 301 hlen += 2; 302 break; 303 case IP6M_BINDING_ACK: 304 ND_TCHECK(mh->ip6m_data8[0]); 305 ND_PRINT((ndo, " status=%u", mh->ip6m_data8[0])); 306 if (mh->ip6m_data8[1] & 0x80) 307 ND_PRINT((ndo, " K")); 308 /* Reserved (7bits) */ 309 hlen = IP6M_MINLEN; 310 ND_TCHECK2(*mh, hlen + 2); 311 ND_PRINT((ndo, " seq#=%u", EXTRACT_16BITS(&bp[hlen]))); 312 hlen += 2; 313 ND_TCHECK2(*mh, hlen + 2); 314 /* units of 4 secs */ 315 ND_PRINT((ndo, " lifetime=%u", EXTRACT_16BITS(&bp[hlen]) << 2)); 316 hlen += 2; 317 break; 318 case IP6M_BINDING_ERROR: 319 ND_TCHECK(mh->ip6m_data8[0]); 320 ND_PRINT((ndo, " status=%u", mh->ip6m_data8[0])); 321 /* Reserved */ 322 hlen = IP6M_MINLEN; 323 ND_TCHECK2(*mh, hlen + 16); 324 ND_PRINT((ndo, " homeaddr %s", ip6addr_string(ndo, &bp[hlen]))); 325 hlen += 16; 326 break; 327 default: 328 ND_PRINT((ndo, " len=%u", mh->ip6m_len)); 329 return(mhlen); 330 break; 331 } 332 if (ndo->ndo_vflag) 333 if (mobility_opt_print(ndo, &bp[hlen], mhlen - hlen)) 334 goto trunc;; 335 336 return(mhlen); 337 338 trunc: 339 ND_PRINT((ndo, "%s", tstr)); 340 return(mhlen); 341} 342