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