1 /* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 22 /* \summary: IP printer */ 23 24 #ifdef HAVE_CONFIG_H 25 #include "config.h" 26 #endif 27 28 #include <netdissect-stdinc.h> 29 30 #include <string.h> 31 32 #include "netdissect.h" 33 #include "addrtoname.h" 34 #include "extract.h" 35 36 #include "ip.h" 37 #include "ipproto.h" 38 39 static const char tstr[] = "[|ip]"; 40 41 static const struct tok ip_option_values[] = { 42 { IPOPT_EOL, "EOL" }, 43 { IPOPT_NOP, "NOP" }, 44 { IPOPT_TS, "timestamp" }, 45 { IPOPT_SECURITY, "security" }, 46 { IPOPT_RR, "RR" }, 47 { IPOPT_SSRR, "SSRR" }, 48 { IPOPT_LSRR, "LSRR" }, 49 { IPOPT_RA, "RA" }, 50 { IPOPT_RFC1393, "traceroute" }, 51 { 0, NULL } 52 }; 53 54 /* 55 * print the recorded route in an IP RR, LSRR or SSRR option. 56 */ 57 static int 58 ip_printroute(netdissect_options *ndo, 59 register const u_char *cp, u_int length) 60 { 61 register u_int ptr; 62 register u_int len; 63 64 if (length < 3) { 65 ND_PRINT((ndo, " [bad length %u]", length)); 66 return (0); 67 } 68 if ((length + 1) & 3) 69 ND_PRINT((ndo, " [bad length %u]", length)); 70 ND_TCHECK(cp[2]); 71 ptr = cp[2] - 1; 72 if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1) 73 ND_PRINT((ndo, " [bad ptr %u]", cp[2])); 74 75 for (len = 3; len < length; len += 4) { 76 ND_TCHECK2(cp[len], 4); 77 ND_PRINT((ndo, " %s", ipaddr_string(ndo, &cp[len]))); 78 if (ptr > len) 79 ND_PRINT((ndo, ",")); 80 } 81 return (0); 82 83 trunc: 84 return (-1); 85 } 86 87 /* 88 * If source-routing is present and valid, return the final destination. 89 * Otherwise, return IP destination. 90 * 91 * This is used for UDP and TCP pseudo-header in the checksum 92 * calculation. 93 */ 94 static uint32_t 95 ip_finddst(netdissect_options *ndo, 96 const struct ip *ip) 97 { 98 int length; 99 int len; 100 const u_char *cp; 101 uint32_t retval; 102 103 cp = (const u_char *)(ip + 1); 104 length = (IP_HL(ip) << 2) - sizeof(struct ip); 105 106 for (; length > 0; cp += len, length -= len) { 107 int tt; 108 109 ND_TCHECK(*cp); 110 tt = *cp; 111 if (tt == IPOPT_EOL) 112 break; 113 else if (tt == IPOPT_NOP) 114 len = 1; 115 else { 116 ND_TCHECK(cp[1]); 117 len = cp[1]; 118 if (len < 2) 119 break; 120 } 121 ND_TCHECK2(*cp, len); 122 switch (tt) { 123 124 case IPOPT_SSRR: 125 case IPOPT_LSRR: 126 if (len < 7) 127 break; 128 UNALIGNED_MEMCPY(&retval, cp + len - 4, 4); 129 return retval; 130 } 131 } 132 trunc: 133 UNALIGNED_MEMCPY(&retval, &ip->ip_dst, sizeof(uint32_t)); 134 return retval; 135 } 136 137 /* 138 * Compute a V4-style checksum by building a pseudoheader. 139 */ 140 int 141 nextproto4_cksum(netdissect_options *ndo, 142 const struct ip *ip, const uint8_t *data, 143 u_int len, u_int covlen, u_int next_proto) 144 { 145 struct phdr { 146 uint32_t src; 147 uint32_t dst; 148 u_char mbz; 149 u_char proto; 150 uint16_t len; 151 } ph; 152 struct cksum_vec vec[2]; 153 154 /* pseudo-header.. */ 155 ph.len = htons((uint16_t)len); 156 ph.mbz = 0; 157 ph.proto = next_proto; 158 UNALIGNED_MEMCPY(&ph.src, &ip->ip_src, sizeof(uint32_t)); 159 if (IP_HL(ip) == 5) 160 UNALIGNED_MEMCPY(&ph.dst, &ip->ip_dst, sizeof(uint32_t)); 161 else 162 ph.dst = ip_finddst(ndo, ip); 163 164 vec[0].ptr = (const uint8_t *)(void *)&ph; 165 vec[0].len = sizeof(ph); 166 vec[1].ptr = data; 167 vec[1].len = covlen; 168 return (in_cksum(vec, 2)); 169 } 170 171 static int 172 ip_printts(netdissect_options *ndo, 173 register const u_char *cp, u_int length) 174 { 175 register u_int ptr; 176 register u_int len; 177 int hoplen; 178 const char *type; 179 180 if (length < 4) { 181 ND_PRINT((ndo, "[bad length %u]", length)); 182 return (0); 183 } 184 ND_PRINT((ndo, " TS{")); 185 hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4; 186 if ((length - 4) & (hoplen-1)) 187 ND_PRINT((ndo, "[bad length %u]", length)); 188 ND_TCHECK(cp[2]); 189 ptr = cp[2] - 1; 190 len = 0; 191 if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1) 192 ND_PRINT((ndo, "[bad ptr %u]", cp[2])); 193 ND_TCHECK(cp[3]); 194 switch (cp[3]&0xF) { 195 case IPOPT_TS_TSONLY: 196 ND_PRINT((ndo, "TSONLY")); 197 break; 198 case IPOPT_TS_TSANDADDR: 199 ND_PRINT((ndo, "TS+ADDR")); 200 break; 201 /* 202 * prespecified should really be 3, but some ones might send 2 203 * instead, and the IPOPT_TS_PRESPEC constant can apparently 204 * have both values, so we have to hard-code it here. 205 */ 206 207 case 2: 208 ND_PRINT((ndo, "PRESPEC2.0")); 209 break; 210 case 3: /* IPOPT_TS_PRESPEC */ 211 ND_PRINT((ndo, "PRESPEC")); 212 break; 213 default: 214 ND_PRINT((ndo, "[bad ts type %d]", cp[3]&0xF)); 215 goto done; 216 } 217 218 type = " "; 219 for (len = 4; len < length; len += hoplen) { 220 if (ptr == len) 221 type = " ^ "; 222 ND_TCHECK2(cp[len], hoplen); 223 ND_PRINT((ndo, "%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]), 224 hoplen!=8 ? "" : ipaddr_string(ndo, &cp[len]))); 225 type = " "; 226 } 227 228 done: 229 ND_PRINT((ndo, "%s", ptr == len ? " ^ " : "")); 230 231 if (cp[3]>>4) 232 ND_PRINT((ndo, " [%d hops not recorded]} ", cp[3]>>4)); 233 else 234 ND_PRINT((ndo, "}")); 235 return (0); 236 237 trunc: 238 return (-1); 239 } 240 241 /* 242 * print IP options. 243 */ 244 static void 245 ip_optprint(netdissect_options *ndo, 246 register const u_char *cp, u_int length) 247 { 248 register u_int option_len; 249 const char *sep = ""; 250 251 for (; length > 0; cp += option_len, length -= option_len) { 252 u_int option_code; 253 254 ND_PRINT((ndo, "%s", sep)); 255 sep = ","; 256 257 ND_TCHECK(*cp); 258 option_code = *cp; 259 260 ND_PRINT((ndo, "%s", 261 tok2str(ip_option_values,"unknown %u",option_code))); 262 263 if (option_code == IPOPT_NOP || 264 option_code == IPOPT_EOL) 265 option_len = 1; 266 267 else { 268 ND_TCHECK(cp[1]); 269 option_len = cp[1]; 270 if (option_len < 2) { 271 ND_PRINT((ndo, " [bad length %u]", option_len)); 272 return; 273 } 274 } 275 276 if (option_len > length) { 277 ND_PRINT((ndo, " [bad length %u]", option_len)); 278 return; 279 } 280 281 ND_TCHECK2(*cp, option_len); 282 283 switch (option_code) { 284 case IPOPT_EOL: 285 return; 286 287 case IPOPT_TS: 288 if (ip_printts(ndo, cp, option_len) == -1) 289 goto trunc; 290 break; 291 292 case IPOPT_RR: /* fall through */ 293 case IPOPT_SSRR: 294 case IPOPT_LSRR: 295 if (ip_printroute(ndo, cp, option_len) == -1) 296 goto trunc; 297 break; 298 299 case IPOPT_RA: 300 if (option_len < 4) { 301 ND_PRINT((ndo, " [bad length %u]", option_len)); 302 break; 303 } 304 ND_TCHECK(cp[3]); 305 if (EXTRACT_16BITS(&cp[2]) != 0) 306 ND_PRINT((ndo, " value %u", EXTRACT_16BITS(&cp[2]))); 307 break; 308 309 case IPOPT_NOP: /* nothing to print - fall through */ 310 case IPOPT_SECURITY: 311 default: 312 break; 313 } 314 } 315 return; 316 317 trunc: 318 ND_PRINT((ndo, "%s", tstr)); 319 } 320 321 #define IP_RES 0x8000 322 323 static const struct tok ip_frag_values[] = { 324 { IP_MF, "+" }, 325 { IP_DF, "DF" }, 326 { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */ 327 { 0, NULL } 328 }; 329 330 struct ip_print_demux_state { 331 const struct ip *ip; 332 const u_char *cp; 333 u_int len, off; 334 u_char nh; 335 int advance; 336 }; 337 338 static void 339 ip_print_demux(netdissect_options *ndo, 340 struct ip_print_demux_state *ipds) 341 { 342 const char *p_name; 343 344 again: 345 switch (ipds->nh) { 346 347 case IPPROTO_AH: 348 if (!ND_TTEST(*ipds->cp)) { 349 ND_PRINT((ndo, "[|AH]")); 350 break; 351 } 352 ipds->nh = *ipds->cp; 353 ipds->advance = ah_print(ndo, ipds->cp); 354 if (ipds->advance <= 0) 355 break; 356 ipds->cp += ipds->advance; 357 ipds->len -= ipds->advance; 358 goto again; 359 360 case IPPROTO_ESP: 361 { 362 int enh, padlen; 363 ipds->advance = esp_print(ndo, ipds->cp, ipds->len, 364 (const u_char *)ipds->ip, 365 &enh, &padlen); 366 if (ipds->advance <= 0) 367 break; 368 ipds->cp += ipds->advance; 369 ipds->len -= ipds->advance + padlen; 370 ipds->nh = enh & 0xff; 371 goto again; 372 } 373 374 case IPPROTO_IPCOMP: 375 { 376 ipcomp_print(ndo, ipds->cp); 377 /* 378 * Either this has decompressed the payload and 379 * printed it, in which case there's nothing more 380 * to do, or it hasn't, in which case there's 381 * nothing more to do. 382 */ 383 break; 384 } 385 386 case IPPROTO_SCTP: 387 sctp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len); 388 break; 389 390 case IPPROTO_DCCP: 391 dccp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len); 392 break; 393 394 case IPPROTO_TCP: 395 /* pass on the MF bit plus the offset to detect fragments */ 396 tcp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, 397 ipds->off & (IP_MF|IP_OFFMASK)); 398 break; 399 400 case IPPROTO_UDP: 401 /* pass on the MF bit plus the offset to detect fragments */ 402 udp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, 403 ipds->off & (IP_MF|IP_OFFMASK)); 404 break; 405 406 case IPPROTO_ICMP: 407 /* pass on the MF bit plus the offset to detect fragments */ 408 icmp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, 409 ipds->off & (IP_MF|IP_OFFMASK)); 410 break; 411 412 case IPPROTO_PIGP: 413 /* 414 * XXX - the current IANA protocol number assignments 415 * page lists 9 as "any private interior gateway 416 * (used by Cisco for their IGRP)" and 88 as 417 * "EIGRP" from Cisco. 418 * 419 * Recent BSD <netinet/in.h> headers define 420 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88. 421 * We define IP_PROTO_PIGP as 9 and 422 * IP_PROTO_EIGRP as 88; those names better 423 * match was the current protocol number 424 * assignments say. 425 */ 426 igrp_print(ndo, ipds->cp, ipds->len); 427 break; 428 429 case IPPROTO_EIGRP: 430 eigrp_print(ndo, ipds->cp, ipds->len); 431 break; 432 433 case IPPROTO_ND: 434 ND_PRINT((ndo, " nd %d", ipds->len)); 435 break; 436 437 case IPPROTO_EGP: 438 egp_print(ndo, ipds->cp, ipds->len); 439 break; 440 441 case IPPROTO_OSPF: 442 ospf_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip); 443 break; 444 445 case IPPROTO_IGMP: 446 igmp_print(ndo, ipds->cp, ipds->len); 447 break; 448 449 case IPPROTO_IPV4: 450 /* DVMRP multicast tunnel (ip-in-ip encapsulation) */ 451 ip_print(ndo, ipds->cp, ipds->len); 452 if (! ndo->ndo_vflag) { 453 ND_PRINT((ndo, " (ipip-proto-4)")); 454 return; 455 } 456 break; 457 458 case IPPROTO_IPV6: 459 /* ip6-in-ip encapsulation */ 460 ip6_print(ndo, ipds->cp, ipds->len); 461 break; 462 463 case IPPROTO_RSVP: 464 rsvp_print(ndo, ipds->cp, ipds->len); 465 break; 466 467 case IPPROTO_GRE: 468 /* do it */ 469 gre_print(ndo, ipds->cp, ipds->len); 470 break; 471 472 case IPPROTO_MOBILE: 473 mobile_print(ndo, ipds->cp, ipds->len); 474 break; 475 476 case IPPROTO_PIM: 477 pim_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip); 478 break; 479 480 case IPPROTO_VRRP: 481 if (ndo->ndo_packettype == PT_CARP) { 482 if (ndo->ndo_vflag) 483 ND_PRINT((ndo, "carp %s > %s: ", 484 ipaddr_string(ndo, &ipds->ip->ip_src), 485 ipaddr_string(ndo, &ipds->ip->ip_dst))); 486 carp_print(ndo, ipds->cp, ipds->len, ipds->ip->ip_ttl); 487 } else { 488 if (ndo->ndo_vflag) 489 ND_PRINT((ndo, "vrrp %s > %s: ", 490 ipaddr_string(ndo, &ipds->ip->ip_src), 491 ipaddr_string(ndo, &ipds->ip->ip_dst))); 492 vrrp_print(ndo, ipds->cp, ipds->len, 493 (const u_char *)ipds->ip, ipds->ip->ip_ttl); 494 } 495 break; 496 497 case IPPROTO_PGM: 498 pgm_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip); 499 break; 500 501 default: 502 if (ndo->ndo_nflag==0 && (p_name = netdb_protoname(ipds->nh)) != NULL) 503 ND_PRINT((ndo, " %s", p_name)); 504 else 505 ND_PRINT((ndo, " ip-proto-%d", ipds->nh)); 506 ND_PRINT((ndo, " %d", ipds->len)); 507 break; 508 } 509 } 510 511 void 512 ip_print_inner(netdissect_options *ndo, 513 const u_char *bp, 514 u_int length, u_int nh, 515 const u_char *bp2) 516 { 517 struct ip_print_demux_state ipd; 518 519 ipd.ip = (const struct ip *)bp2; 520 ipd.cp = bp; 521 ipd.len = length; 522 ipd.off = 0; 523 ipd.nh = nh; 524 ipd.advance = 0; 525 526 ip_print_demux(ndo, &ipd); 527 } 528 529 530 /* 531 * print an IP datagram. 532 */ 533 void 534 ip_print(netdissect_options *ndo, 535 const u_char *bp, 536 u_int length) 537 { 538 struct ip_print_demux_state ipd; 539 struct ip_print_demux_state *ipds=&ipd; 540 const u_char *ipend; 541 u_int hlen; 542 struct cksum_vec vec[1]; 543 uint16_t sum, ip_sum; 544 const char *p_name; 545 546 ipds->ip = (const struct ip *)bp; 547 ND_TCHECK(ipds->ip->ip_vhl); 548 if (IP_V(ipds->ip) != 4) { /* print version and fail if != 4 */ 549 if (IP_V(ipds->ip) == 6) 550 ND_PRINT((ndo, "IP6, wrong link-layer encapsulation ")); 551 else 552 ND_PRINT((ndo, "IP%u ", IP_V(ipds->ip))); 553 return; 554 } 555 if (!ndo->ndo_eflag) 556 ND_PRINT((ndo, "IP ")); 557 558 ND_TCHECK(*ipds->ip); 559 if (length < sizeof (struct ip)) { 560 ND_PRINT((ndo, "truncated-ip %u", length)); 561 return; 562 } 563 hlen = IP_HL(ipds->ip) * 4; 564 if (hlen < sizeof (struct ip)) { 565 ND_PRINT((ndo, "bad-hlen %u", hlen)); 566 return; 567 } 568 569 ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len); 570 if (length < ipds->len) 571 ND_PRINT((ndo, "truncated-ip - %u bytes missing! ", 572 ipds->len - length)); 573 if (ipds->len < hlen) { 574 #ifdef GUESS_TSO 575 if (ipds->len) { 576 ND_PRINT((ndo, "bad-len %u", ipds->len)); 577 return; 578 } 579 else { 580 /* we guess that it is a TSO send */ 581 ipds->len = length; 582 } 583 #else 584 ND_PRINT((ndo, "bad-len %u", ipds->len)); 585 return; 586 #endif /* GUESS_TSO */ 587 } 588 589 /* 590 * Cut off the snapshot length to the end of the IP payload. 591 */ 592 ipend = bp + ipds->len; 593 if (ipend < ndo->ndo_snapend) 594 ndo->ndo_snapend = ipend; 595 596 ipds->len -= hlen; 597 598 ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off); 599 600 if (ndo->ndo_vflag) { 601 ND_PRINT((ndo, "(tos 0x%x", (int)ipds->ip->ip_tos)); 602 /* ECN bits */ 603 switch (ipds->ip->ip_tos & 0x03) { 604 605 case 0: 606 break; 607 608 case 1: 609 ND_PRINT((ndo, ",ECT(1)")); 610 break; 611 612 case 2: 613 ND_PRINT((ndo, ",ECT(0)")); 614 break; 615 616 case 3: 617 ND_PRINT((ndo, ",CE")); 618 break; 619 } 620 621 if (ipds->ip->ip_ttl >= 1) 622 ND_PRINT((ndo, ", ttl %u", ipds->ip->ip_ttl)); 623 624 /* 625 * for the firewall guys, print id, offset. 626 * On all but the last stick a "+" in the flags portion. 627 * For unfragmented datagrams, note the don't fragment flag. 628 */ 629 630 ND_PRINT((ndo, ", id %u, offset %u, flags [%s], proto %s (%u)", 631 EXTRACT_16BITS(&ipds->ip->ip_id), 632 (ipds->off & 0x1fff) * 8, 633 bittok2str(ip_frag_values, "none", ipds->off&0xe000), 634 tok2str(ipproto_values,"unknown",ipds->ip->ip_p), 635 ipds->ip->ip_p)); 636 637 ND_PRINT((ndo, ", length %u", EXTRACT_16BITS(&ipds->ip->ip_len))); 638 639 if ((hlen - sizeof(struct ip)) > 0) { 640 ND_PRINT((ndo, ", options (")); 641 ip_optprint(ndo, (const u_char *)(ipds->ip + 1), hlen - sizeof(struct ip)); 642 ND_PRINT((ndo, ")")); 643 } 644 645 if (!ndo->ndo_Kflag && (const u_char *)ipds->ip + hlen <= ndo->ndo_snapend) { 646 vec[0].ptr = (const uint8_t *)(const void *)ipds->ip; 647 vec[0].len = hlen; 648 sum = in_cksum(vec, 1); 649 if (sum != 0) { 650 ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum); 651 ND_PRINT((ndo, ", bad cksum %x (->%x)!", ip_sum, 652 in_cksum_shouldbe(ip_sum, sum))); 653 } 654 } 655 656 ND_PRINT((ndo, ")\n ")); 657 } 658 659 /* 660 * If this is fragment zero, hand it to the next higher 661 * level protocol. 662 */ 663 if ((ipds->off & 0x1fff) == 0) { 664 ipds->cp = (const u_char *)ipds->ip + hlen; 665 ipds->nh = ipds->ip->ip_p; 666 667 if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP && 668 ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) { 669 ND_PRINT((ndo, "%s > %s: ", 670 ipaddr_string(ndo, &ipds->ip->ip_src), 671 ipaddr_string(ndo, &ipds->ip->ip_dst))); 672 } 673 ip_print_demux(ndo, ipds); 674 } else { 675 /* 676 * Ultra quiet now means that all this stuff should be 677 * suppressed. 678 */ 679 if (ndo->ndo_qflag > 1) 680 return; 681 682 /* 683 * This isn't the first frag, so we're missing the 684 * next level protocol header. print the ip addr 685 * and the protocol. 686 */ 687 ND_PRINT((ndo, "%s > %s:", ipaddr_string(ndo, &ipds->ip->ip_src), 688 ipaddr_string(ndo, &ipds->ip->ip_dst))); 689 if (!ndo->ndo_nflag && (p_name = netdb_protoname(ipds->ip->ip_p)) != NULL) 690 ND_PRINT((ndo, " %s", p_name)); 691 else 692 ND_PRINT((ndo, " ip-proto-%d", ipds->ip->ip_p)); 693 } 694 return; 695 696 trunc: 697 ND_PRINT((ndo, "%s", tstr)); 698 return; 699 } 700 701 void 702 ipN_print(netdissect_options *ndo, register const u_char *bp, register u_int length) 703 { 704 if (length < 1) { 705 ND_PRINT((ndo, "truncated-ip %d", length)); 706 return; 707 } 708 709 ND_TCHECK(*bp); 710 switch (*bp & 0xF0) { 711 case 0x40: 712 ip_print (ndo, bp, length); 713 break; 714 case 0x60: 715 ip6_print (ndo, bp, length); 716 break; 717 default: 718 ND_PRINT((ndo, "unknown ip %d", (*bp & 0xF0) >> 4)); 719 break; 720 } 721 return; 722 723 trunc: 724 ND_PRINT((ndo, "%s", tstr)); 725 return; 726 } 727 728 /* 729 * Local Variables: 730 * c-style: whitesmith 731 * c-basic-offset: 8 732 * End: 733 */ 734 735 736