]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sbin/atm/atmconfig/natm.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sbin / atm / atmconfig / natm.c
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$");
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
45 static void natm_add(int, char *[]);
46 static void natm_delete(int, char *[]);
47 static void natm_show(int, char *[]);
48
49 const 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  */
59 struct 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 };
70 static TAILQ_HEAD(, natm_route) natm_route_list =
71     TAILQ_HEAD_INITIALIZER(natm_route_list);
72
73 static void
74 store_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  */
235 static void
236 natm_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
273 static u_long
274 parse_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
288 static void
289 do_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  */
338 static void
339 natm_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  */
529 static void
530 natm_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 == 0)
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  */
606 static void
607 natm_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 }