natm.c revision 298234
1/* 2 * Copyright (c) 2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * Author: Hartmut Brandt <harti@freebsd.org> 28 */ 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: head/sbin/atm/atmconfig/natm.c 298234 2016-04-19 00:59:15Z araujo $"); 31 32#include <sys/types.h> 33#include <sys/socket.h> 34#include <sys/sysctl.h> 35#include <net/if_atm.h> 36#include <net/if_dl.h> 37#include <net/route.h> 38#include <netinet/in.h> 39#include <arpa/inet.h> 40#include <netdb.h> 41#include "atmconfig.h" 42#include "private.h" 43#include "diag.h" 44 45static void natm_add(int, char *[]); 46static void natm_delete(int, char *[]); 47static void natm_show(int, char *[]); 48 49const struct cmdtab natm_tab[] = { 50 { "add", NULL, natm_add }, 51 { "delete", NULL, natm_delete }, 52 { "show", NULL, natm_show }, 53 { NULL, NULL, NULL } 54}; 55 56/* 57 * Structure to hold a route 58 */ 59struct natm_route { 60 TAILQ_ENTRY(natm_route) link; 61 struct in_addr host; 62 struct diagif *aif; 63 u_int flags; 64 int llcsnap; 65 u_int vpi, vci; 66 u_int traffic; 67 u_int pcr, scr, mbs, icr, mcr; 68 u_int tbe, nrm, trm, adtf, rif, rdf, cdf; 69}; 70static TAILQ_HEAD(, natm_route) natm_route_list = 71 TAILQ_HEAD_INITIALIZER(natm_route_list); 72 73static void 74store_route(struct rt_msghdr *rtm) 75{ 76 u_int i; 77 struct natm_route *r; 78 char *cp; 79 struct sockaddr *sa; 80 struct sockaddr_in *sain; 81 struct sockaddr_dl *sdl; 82 struct diagif *aif; 83 u_int n; 84 85 r = malloc(sizeof(*r)); 86 if (r == NULL) 87 err(1, "allocate route"); 88 89 r->flags = rtm->rtm_flags; 90 cp = (char *)(rtm + 1); 91 for (i = 1; i != 0; i <<= 1) { 92 if (rtm->rtm_addrs & i) { 93 sa = (struct sockaddr *)cp; 94 cp += roundup(sa->sa_len, sizeof(long)); 95 switch (i) { 96 97 case RTA_DST: 98 if (sa->sa_family != AF_INET) { 99 warnx("RTA_DST not AF_INET %u", sa->sa_family); 100 goto fail; 101 } 102 sain = (struct sockaddr_in *)(void *)sa; 103 if (sain->sin_len < 4) 104 r->host.s_addr = INADDR_ANY; 105 else 106 r->host = sain->sin_addr; 107 break; 108 109 case RTA_GATEWAY: 110 if (sa->sa_family != AF_LINK) { 111 warnx("RTA_GATEWAY not AF_LINK"); 112 goto fail; 113 } 114 sdl = (struct sockaddr_dl *)(void *)sa; 115 TAILQ_FOREACH(aif, &diagif_list, link) 116 if (strlen(aif->ifname) == 117 sdl->sdl_nlen && 118 strncmp(aif->ifname, sdl->sdl_data, 119 sdl->sdl_nlen) == 0) 120 break; 121 if (aif == NULL) { 122 warnx("interface '%.*s' not found", 123 sdl->sdl_nlen, sdl->sdl_data); 124 goto fail; 125 } 126 r->aif = aif; 127 128 /* parse ATM stuff */ 129 130#define GET3() (((sdl->sdl_data[n] & 0xff) << 16) | \ 131 ((sdl->sdl_data[n + 1] & 0xff) << 8) | \ 132 ((sdl->sdl_data[n + 2] & 0xff) << 0)) 133#define GET2() (((sdl->sdl_data[n] & 0xff) << 8) | \ 134 ((sdl->sdl_data[n + 1] & 0xff) << 0)) 135#define GET1() (((sdl->sdl_data[n] & 0xff) << 0)) 136 137 n = sdl->sdl_nlen; 138 if (sdl->sdl_alen < 4) { 139 warnx("RTA_GATEWAY alen too short"); 140 goto fail; 141 } 142 r->llcsnap = GET1() & ATM_PH_LLCSNAP; 143 n++; 144 r->vpi = GET1(); 145 n++; 146 r->vci = GET2(); 147 n += 2; 148 if (sdl->sdl_alen == 4) { 149 /* old address */ 150 r->traffic = ATMIO_TRAFFIC_UBR; 151 r->pcr = 0; 152 break; 153 } 154 /* new address */ 155 r->traffic = GET1(); 156 n++; 157 switch (r->traffic) { 158 159 case ATMIO_TRAFFIC_UBR: 160 if (sdl->sdl_alen >= 5 + 3) { 161 r->pcr = GET3(); 162 n += 3; 163 } else 164 r->pcr = 0; 165 break; 166 167 case ATMIO_TRAFFIC_CBR: 168 if (sdl->sdl_alen < 5 + 3) { 169 warnx("CBR address too short"); 170 goto fail; 171 } 172 r->pcr = GET3(); 173 n += 3; 174 break; 175 176 case ATMIO_TRAFFIC_VBR: 177 if (sdl->sdl_alen < 5 + 3 * 3) { 178 warnx("VBR address too short"); 179 goto fail; 180 } 181 r->pcr = GET3(); 182 n += 3; 183 r->scr = GET3(); 184 n += 3; 185 r->mbs = GET3(); 186 n += 3; 187 break; 188 189 case ATMIO_TRAFFIC_ABR: 190 if (sdl->sdl_alen < 5 + 4 * 3 + 2 + 191 1 * 2 + 3) { 192 warnx("ABR address too short"); 193 goto fail; 194 } 195 r->pcr = GET3(); 196 n += 3; 197 r->mcr = GET3(); 198 n += 3; 199 r->icr = GET3(); 200 n += 3; 201 r->tbe = GET3(); 202 n += 3; 203 r->nrm = GET1(); 204 n++; 205 r->trm = GET1(); 206 n++; 207 r->adtf = GET2(); 208 n += 2; 209 r->rif = GET1(); 210 n++; 211 r->rdf = GET1(); 212 n++; 213 r->cdf = GET1(); 214 n++; 215 break; 216 217 default: 218 goto fail; 219 } 220 break; 221 } 222 } 223 } 224 225 TAILQ_INSERT_TAIL(&natm_route_list, r, link); 226 227 return; 228 fail: 229 free(r); 230} 231 232/* 233 * Fetch the INET routes that a ours 234 */ 235static void 236natm_route_fetch(void) 237{ 238 int name[6]; 239 size_t needed; 240 u_char *buf, *next; 241 struct rt_msghdr *rtm; 242 243 name[0] = CTL_NET; 244 name[1] = PF_ROUTE; 245 name[2] = 0; 246 name[3] = AF_INET; 247 name[4] = NET_RT_DUMP; 248 name[5] = 0; 249 250 if (sysctl(name, 6, NULL, &needed, NULL, 0) == -1) 251 err(1, "rtable estimate"); 252 needed *= 2; 253 if ((buf = malloc(needed)) == NULL) 254 err(1, "rtable buffer (%zu)", needed); 255 if (sysctl(name, 6, buf, &needed, NULL, 0) == -1) 256 err(1, "rtable get"); 257 258 next = buf; 259 while (next < buf + needed) { 260 rtm = (struct rt_msghdr *)(void *)next; 261 next += rtm->rtm_msglen; 262 263 if (rtm->rtm_type == RTM_GET) { 264 if ((rtm->rtm_flags & (RTF_UP | RTF_HOST | 265 RTF_STATIC)) == (RTF_UP | RTF_HOST | RTF_STATIC) && 266 (rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY | 267 RTA_IFP)) == (RTA_DST | RTA_GATEWAY | RTA_IFP)) 268 store_route(rtm); 269 } 270 } 271} 272 273static u_long 274parse_num(const char *arg, const char *name, u_long limit) 275{ 276 u_long res; 277 char *end; 278 279 errno = 0; 280 res = strtoul(arg, &end, 10); 281 if (*end != '\0' || end == arg || errno != 0) 282 errx(1, "cannot parse %s '%s'", name, arg); 283 if (res > limit) 284 errx(1, "%s out of range (0...%lu)", name, limit); 285 return (res); 286} 287 288static void 289do_route(u_int type, u_int flags, const struct sockaddr_in *sain, 290 const struct sockaddr_dl *sdl) 291{ 292 struct { 293 struct rt_msghdr h; 294 char space[512]; 295 } msg; 296 char *ptr; 297 int s; 298 ssize_t rlen; 299 300 /* create routing message */ 301 bzero(&msg, sizeof(msg)); 302 msg.h.rtm_msglen = sizeof(msg.h); 303 msg.h.rtm_version = RTM_VERSION; 304 msg.h.rtm_type = type; 305 msg.h.rtm_index = 0; 306 msg.h.rtm_flags = flags; 307 msg.h.rtm_addrs = RTA_DST | (sdl != NULL ? RTA_GATEWAY : 0); 308 msg.h.rtm_pid = getpid(); 309 310 ptr = (char *)&msg + sizeof(msg.h); 311 memcpy(ptr, sain, sain->sin_len); 312 ptr += roundup(sain->sin_len, sizeof(long)); 313 msg.h.rtm_msglen += roundup(sain->sin_len, sizeof(long)); 314 315 if (sdl != NULL) { 316 memcpy(ptr, sdl, sdl->sdl_len); 317 ptr += roundup(sdl->sdl_len, sizeof(long)); 318 msg.h.rtm_msglen += roundup(sdl->sdl_len, sizeof(long)); 319 } 320 321 /* open socket */ 322 s = socket(PF_ROUTE, SOCK_RAW, AF_INET); 323 if (s == -1) 324 err(1, "cannot open routing socket"); 325 326 rlen = write(s, &msg, msg.h.rtm_msglen); 327 if (rlen == -1) 328 err(1, "writing to routing socket"); 329 if ((size_t)rlen != msg.h.rtm_msglen) 330 errx(1, "short write to routing socket: %zu %u", 331 (size_t)rlen, msg.h.rtm_msglen); 332 close(s); 333} 334 335/* 336 * Add a new NATM route 337 */ 338static void 339natm_add(int argc, char *argv[]) 340{ 341 int opt; 342 struct hostent *hp; 343 struct sockaddr_in sain; 344 struct sockaddr_dl sdl; 345 struct diagif *aif; 346 u_long num, num1; 347 u_int idx; 348 349 static int printonly; 350 351 static const struct option opts[] = { 352 { "printonly", OPT_SIMPLE, &printonly }, 353 { NULL, 0, NULL } 354 }; 355 356 while ((opt = parse_options(&argc, &argv, opts)) != -1) 357 switch (opt) { 358 } 359 360 if (argc < 5) 361 errx(1, "missing arguments for 'natm add'"); 362 363 memset(&sdl, 0, sizeof(sdl)); 364 sdl.sdl_len = sizeof(sdl); 365 sdl.sdl_family = AF_LINK; 366 367 /* get the IP address for <dest> */ 368 memset(&sain, 0, sizeof(sain)); 369 hp = gethostbyname(argv[0]); 370 if (hp == NULL) 371 errx(1, "bad hostname %s: %s", argv[0], hstrerror(h_errno)); 372 if (hp->h_addrtype != AF_INET) 373 errx(1, "bad address type for %s", argv[0]); 374 sain.sin_len = sizeof(sain); 375 sain.sin_family = AF_INET; 376 memcpy(&sain.sin_addr, hp->h_addr, sizeof(sain.sin_addr)); 377 378 /* find interface */ 379 diagif_fetch(); 380 TAILQ_FOREACH(aif, &diagif_list, link) 381 if (strcmp(aif->ifname, argv[1]) == 0) 382 break; 383 if (aif == NULL) 384 errx(1, "unknown ATM interface '%s'", argv[1]); 385 sdl.sdl_index = aif->index; 386 strcpy(sdl.sdl_data, aif->ifname); 387 idx = sdl.sdl_nlen = strlen(aif->ifname); 388 idx++; 389 390 /* verify VPI/VCI */ 391 num = parse_num(argv[2], "VPI", (1U << aif->mib.vpi_bits)); 392 sdl.sdl_data[idx++] = num & 0xff; 393 num = parse_num(argv[3], "VCI", (1U << aif->mib.vci_bits)); 394 if (num == 0) 395 errx(1, "VCI may not be 0"); 396 sdl.sdl_data[idx++] = (num >> 8) & 0xff; 397 sdl.sdl_data[idx++] = num & 0xff; 398 399 /* encapsulation */ 400 if (strcasecmp(argv[4], "llc/snap") == 0) { 401 sdl.sdl_data[sdl.sdl_nlen] = ATM_PH_LLCSNAP; 402 } else if (strcasecmp(argv[4], "aal5") == 0) { 403 sdl.sdl_data[sdl.sdl_nlen] = 0; 404 } else 405 errx(1, "bad encapsulation type '%s'", argv[4]); 406 407 /* look at the traffic */ 408 argc -= 5; 409 argv += 5; 410 411 if (argc != 0) { 412 if (strcasecmp(argv[0], "ubr") == 0) { 413 sdl.sdl_data[idx++] = ATMIO_TRAFFIC_UBR; 414 if (argc == 1) 415 /* ok */; 416 else if (argc == 2) { 417 num = parse_num(argv[1], "PCR", aif->mib.pcr); 418 sdl.sdl_data[idx++] = (num >> 16) & 0xff; 419 sdl.sdl_data[idx++] = (num >> 8) & 0xff; 420 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 421 } else 422 errx(1, "too many parameters for UBR"); 423 424 } else if (strcasecmp(argv[0], "cbr") == 0) { 425 sdl.sdl_data[idx++] = ATMIO_TRAFFIC_CBR; 426 if (argc == 1) 427 errx(1, "missing PCR for CBR"); 428 if (argc > 2) 429 errx(1, "too many parameters for CBR"); 430 num = parse_num(argv[1], "PCR", aif->mib.pcr); 431 sdl.sdl_data[idx++] = (num >> 16) & 0xff; 432 sdl.sdl_data[idx++] = (num >> 8) & 0xff; 433 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 434 435 } else if (strcasecmp(argv[0], "vbr") == 0) { 436 sdl.sdl_data[idx++] = ATMIO_TRAFFIC_VBR; 437 438 if (argc < 4) 439 errx(1, "missing arg(s) for VBR"); 440 if (argc > 4) 441 errx(1, "too many parameters for VBR"); 442 443 num = parse_num(argv[1], "PCR", aif->mib.pcr); 444 sdl.sdl_data[idx++] = (num >> 16) & 0xff; 445 sdl.sdl_data[idx++] = (num >> 8) & 0xff; 446 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 447 num = parse_num(argv[2], "SCR", num); 448 sdl.sdl_data[idx++] = (num >> 16) & 0xff; 449 sdl.sdl_data[idx++] = (num >> 8) & 0xff; 450 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 451 num = parse_num(argv[3], "MBS", 0xffffffLU); 452 sdl.sdl_data[idx++] = (num >> 16) & 0xff; 453 sdl.sdl_data[idx++] = (num >> 8) & 0xff; 454 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 455 456 } else if (strcasecmp(argv[0], "abr") == 0) { 457 sdl.sdl_data[idx++] = ATMIO_TRAFFIC_ABR; 458 if (argc < 11) 459 errx(1, "missing arg(s) for ABR"); 460 if (argc > 11) 461 errx(1, "too many parameters for ABR"); 462 463 num = parse_num(argv[1], "PCR", aif->mib.pcr); 464 sdl.sdl_data[idx++] = (num >> 16) & 0xff; 465 sdl.sdl_data[idx++] = (num >> 8) & 0xff; 466 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 467 468 num1 = parse_num(argv[2], "MCR", num); 469 sdl.sdl_data[idx++] = (num1 >> 16) & 0xff; 470 sdl.sdl_data[idx++] = (num1 >> 8) & 0xff; 471 sdl.sdl_data[idx++] = (num1 >> 0) & 0xff; 472 473 num = parse_num(argv[3], "ICR", num); 474 sdl.sdl_data[idx++] = (num >> 16) & 0xff; 475 sdl.sdl_data[idx++] = (num >> 8) & 0xff; 476 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 477 478 if (num < num1) 479 errx(1, "ICR must be >= MCR"); 480 481 num = parse_num(argv[4], "TBE", 0xffffffUL); 482 sdl.sdl_data[idx++] = (num >> 16) & 0xff; 483 sdl.sdl_data[idx++] = (num >> 8) & 0xff; 484 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 485 486 num = parse_num(argv[5], "NRM", 0x7UL); 487 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 488 489 num = parse_num(argv[6], "TRM", 0x7UL); 490 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 491 492 num = parse_num(argv[7], "ADTF", 0x3ffUL); 493 sdl.sdl_data[idx++] = (num >> 8) & 0xff; 494 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 495 496 num = parse_num(argv[8], "RIF", 0xfUL); 497 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 498 499 num = parse_num(argv[9], "RDF", 0xfUL); 500 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 501 502 num = parse_num(argv[10], "CDF", 0x7UL); 503 sdl.sdl_data[idx++] = (num >> 0) & 0xff; 504 505 } else 506 errx(1, "bad traffic type '%s'", argv[0]); 507 } else 508 sdl.sdl_data[idx++] = ATMIO_TRAFFIC_UBR; 509 510 sdl.sdl_alen = idx - sdl.sdl_nlen; 511 sdl.sdl_len += sdl.sdl_nlen + sdl.sdl_alen; 512 513 if (printonly) { 514 printf("route add -iface %s -link %.*s", 515 inet_ntoa(sain.sin_addr), sdl.sdl_nlen, sdl.sdl_data); 516 for (idx = 0; idx < sdl.sdl_alen; idx++) 517 printf("%c%x", ".:"[idx == 0], 518 (u_int)sdl.sdl_data[sdl.sdl_nlen + idx] & 0xffU); 519 printf("\n"); 520 exit(0); 521 } 522 523 do_route(RTM_ADD, RTF_HOST | RTF_STATIC | RTF_UP, &sain, &sdl); 524} 525 526/* 527 * Delete an NATM route 528 */ 529static void 530natm_delete(int argc, char *argv[]) 531{ 532 int opt; 533 struct hostent *hp; 534 struct sockaddr_in sain; 535 u_int vpi, vci; 536 struct diagif *aif; 537 struct natm_route *r; 538 539 static int printonly; 540 541 static const struct option opts[] = { 542 { "printonly", OPT_SIMPLE, &printonly }, 543 { NULL, 0, NULL } 544 }; 545 546 while ((opt = parse_options(&argc, &argv, opts)) != -1) 547 switch (opt) { 548 } 549 550 diagif_fetch(); 551 natm_route_fetch(); 552 553 memset(&sain, 0, sizeof(sain)); 554 sain.sin_len = sizeof(sain); 555 sain.sin_family = AF_INET; 556 557 if (argc == 1) { 558 /* get the IP address for <dest> */ 559 hp = gethostbyname(argv[0]); 560 if (hp == NULL) 561 errx(1, "bad hostname %s: %s", argv[0], 562 hstrerror(h_errno)); 563 if (hp->h_addrtype != AF_INET) 564 errx(1, "bad address type for %s", argv[0]); 565 memcpy(&sain.sin_addr, hp->h_addr, sizeof(sain.sin_addr)); 566 567 TAILQ_FOREACH(r, &natm_route_list, link) 568 if (r->host.s_addr == sain.sin_addr.s_addr) 569 break; 570 if (r == NULL) 571 errx(1, "no NATM route to host '%s' (%s)", argv[0], 572 inet_ntoa(sain.sin_addr)); 573 574 } else if (argc == 3) { 575 TAILQ_FOREACH(aif, &diagif_list, link) 576 if (strcmp(aif->ifname, argv[0]) == 0) 577 break; 578 if (aif == NULL) 579 errx(1, "no such interface '%s'", argv[0]); 580 581 vpi = parse_num(argv[1], "VPI", 0xff); 582 vci = parse_num(argv[2], "VCI", 0xffff); 583 584 TAILQ_FOREACH(r, &natm_route_list, link) 585 if (r->aif == aif && r->vpi == vpi && r->vci == vci) 586 break; 587 if (r == NULL) 588 errx(1, "no such NATM route %s %u %u", argv[0], 589 vpi, vci); 590 sain.sin_addr = r->host; 591 592 } else 593 errx(1, "bad number of arguments for 'natm delete'"); 594 595 if (printonly) { 596 printf("route delete %s\n", inet_ntoa(r->host)); 597 exit(0); 598 } 599 600 do_route(RTM_DELETE, r->flags, &sain, NULL); 601} 602 603/* 604 * Show NATM routes 605 */ 606static void 607natm_show(int argc, char *argv[]) 608{ 609 int opt; 610 struct natm_route *r; 611 struct hostent *hp; 612 613 static const char *const traffics[] = { 614 [ATMIO_TRAFFIC_UBR] = "UBR", 615 [ATMIO_TRAFFIC_CBR] = "CBR", 616 [ATMIO_TRAFFIC_VBR] = "VBR", 617 [ATMIO_TRAFFIC_ABR] = "ABR" 618 }; 619 620 static int numeric, abr; 621 622 static const struct option opts[] = { 623 { "abr", OPT_SIMPLE, &abr }, 624 { "numeric", OPT_SIMPLE, &numeric }, 625 { NULL, 0, NULL } 626 }; 627 628 static const char head[] = 629 "Destination Iface VPI VCI Encaps Trf PCR " 630 "SCR/MCR MBS/ICR\n"; 631 static const char head_abr[] = 632 "Destination Iface VPI VCI Encaps Trf PCR " 633 "SCR/MCR MBS/ICR TBE NRM TRM ADTF RIF RDF CDF\n"; 634 635 while ((opt = parse_options(&argc, &argv, opts)) != -1) 636 switch (opt) { 637 } 638 639 diagif_fetch(); 640 natm_route_fetch(); 641 642 heading_init(); 643 TAILQ_FOREACH(r, &natm_route_list, link) { 644 heading(abr ? head_abr : head); 645 if (numeric) 646 printf("%-20s", inet_ntoa(r->host)); 647 else if (r->host.s_addr == INADDR_ANY) 648 printf("%-20s", "default"); 649 else { 650 hp = gethostbyaddr((char *)&r->host, sizeof(r->host), 651 AF_INET); 652 if (hp != NULL) 653 printf("%-20s", hp->h_name); 654 else 655 printf("%-20s", inet_ntoa(r->host)); 656 } 657 printf("%-12s%-4u%-6u%-9s%-4s", r->aif->ifname, r->vpi, r->vci, 658 r->llcsnap ? "LLC/SNAP" : "AAL5", traffics[r->traffic]); 659 switch (r->traffic) { 660 661 case ATMIO_TRAFFIC_UBR: 662 case ATMIO_TRAFFIC_CBR: 663 printf("%-8u", r->pcr); 664 break; 665 666 case ATMIO_TRAFFIC_VBR: 667 printf("%-8u%-8u%-8u", r->pcr, r->scr, r->mbs); 668 break; 669 670 case ATMIO_TRAFFIC_ABR: 671 printf("%-8u%-8u%-8u", r->pcr, r->mcr, r->icr); 672 if (abr) 673 printf("%-8u%-4u%-4u%-5u%-4u%-4u%-4u", 674 r->tbe, r->nrm, r->trm, r->adtf, 675 r->rif, r->rdf, r->cdf); 676 break; 677 } 678 printf("\n"); 679 } 680} 681