3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * Author: Hartmut Brandt <harti@freebsd.org>
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
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>
41 #include "atmconfig.h"
45 static void natm_add(int, char *[]);
46 static void natm_delete(int, char *[]);
47 static void natm_show(int, char *[]);
49 const struct cmdtab natm_tab[] = {
50 { "add", NULL, natm_add },
51 { "delete", NULL, natm_delete },
52 { "show", NULL, natm_show },
57 * Structure to hold a route
60 TAILQ_ENTRY(natm_route) link;
67 u_int pcr, scr, mbs, icr, mcr;
68 u_int tbe, nrm, trm, adtf, rif, rdf, cdf;
70 static TAILQ_HEAD(, natm_route) natm_route_list =
71 TAILQ_HEAD_INITIALIZER(natm_route_list);
74 store_route(struct rt_msghdr *rtm)
80 struct sockaddr_in *sain;
81 struct sockaddr_dl *sdl;
85 r = malloc(sizeof(*r));
87 err(1, "allocate route");
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));
98 if (sa->sa_family != AF_INET) {
99 warnx("RTA_DST not AF_INET %u", sa->sa_family);
102 sain = (struct sockaddr_in *)(void *)sa;
103 if (sain->sin_len < 4)
104 r->host.s_addr = INADDR_ANY;
106 r->host = sain->sin_addr;
110 if (sa->sa_family != AF_LINK) {
111 warnx("RTA_GATEWAY not AF_LINK");
114 sdl = (struct sockaddr_dl *)(void *)sa;
115 TAILQ_FOREACH(aif, &diagif_list, link)
116 if (strlen(aif->ifname) ==
118 strncmp(aif->ifname, sdl->sdl_data,
122 warnx("interface '%.*s' not found",
123 sdl->sdl_nlen, sdl->sdl_data);
128 /* parse ATM stuff */
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))
138 if (sdl->sdl_alen < 4) {
139 warnx("RTA_GATEWAY alen too short");
142 r->llcsnap = GET1() & ATM_PH_LLCSNAP;
148 if (sdl->sdl_alen == 4) {
150 r->traffic = ATMIO_TRAFFIC_UBR;
157 switch (r->traffic) {
159 case ATMIO_TRAFFIC_UBR:
160 if (sdl->sdl_alen >= 5 + 3) {
167 case ATMIO_TRAFFIC_CBR:
168 if (sdl->sdl_alen < 5 + 3) {
169 warnx("CBR address too short");
176 case ATMIO_TRAFFIC_VBR:
177 if (sdl->sdl_alen < 5 + 3 * 3) {
178 warnx("VBR address too short");
189 case ATMIO_TRAFFIC_ABR:
190 if (sdl->sdl_alen < 5 + 4 * 3 + 2 +
192 warnx("ABR address too short");
225 TAILQ_INSERT_TAIL(&natm_route_list, r, link);
233 * Fetch the INET routes that a ours
236 natm_route_fetch(void)
241 struct rt_msghdr *rtm;
247 name[4] = NET_RT_DUMP;
250 if (sysctl(name, 6, NULL, &needed, NULL, 0) == -1)
251 err(1, "rtable estimate");
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");
259 while (next < buf + needed) {
260 rtm = (struct rt_msghdr *)(void *)next;
261 next += rtm->rtm_msglen;
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))
274 parse_num(const char *arg, const char *name, u_long limit)
280 res = strtoul(arg, &end, 10);
281 if (*end != '\0' || end == arg || errno != 0)
282 errx(1, "cannot parse %s '%s'", name, arg);
284 errx(1, "%s out of range (0...%lu)", name, limit);
289 do_route(u_int type, u_int flags, const struct sockaddr_in *sain,
290 const struct sockaddr_dl *sdl)
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;
306 msg.h.rtm_flags = flags;
307 msg.h.rtm_addrs = RTA_DST | (sdl != NULL ? RTA_GATEWAY : 0);
308 msg.h.rtm_pid = getpid();
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));
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));
322 s = socket(PF_ROUTE, SOCK_RAW, AF_INET);
324 err(1, "cannot open routing socket");
326 rlen = write(s, &msg, msg.h.rtm_msglen);
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);
336 * Add a new NATM route
339 natm_add(int argc, char *argv[])
343 struct sockaddr_in sain;
344 struct sockaddr_dl sdl;
349 static int printonly;
351 static const struct option opts[] = {
352 { "printonly", OPT_SIMPLE, &printonly },
356 while ((opt = parse_options(&argc, &argv, opts)) != -1)
361 errx(1, "missing arguments for 'natm add'");
363 memset(&sdl, 0, sizeof(sdl));
364 sdl.sdl_len = sizeof(sdl);
365 sdl.sdl_family = AF_LINK;
367 /* get the IP address for <dest> */
368 memset(&sain, 0, sizeof(sain));
369 hp = gethostbyname(argv[0]);
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));
380 TAILQ_FOREACH(aif, &diagif_list, link)
381 if (strcmp(aif->ifname, argv[1]) == 0)
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);
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));
395 errx(1, "VCI may not be 0");
396 sdl.sdl_data[idx++] = (num >> 8) & 0xff;
397 sdl.sdl_data[idx++] = num & 0xff;
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;
405 errx(1, "bad encapsulation type '%s'", argv[4]);
407 /* look at the traffic */
412 if (strcasecmp(argv[0], "ubr") == 0) {
413 sdl.sdl_data[idx++] = ATMIO_TRAFFIC_UBR;
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;
422 errx(1, "too many parameters for UBR");
424 } else if (strcasecmp(argv[0], "cbr") == 0) {
425 sdl.sdl_data[idx++] = ATMIO_TRAFFIC_CBR;
427 errx(1, "missing PCR for CBR");
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;
435 } else if (strcasecmp(argv[0], "vbr") == 0) {
436 sdl.sdl_data[idx++] = ATMIO_TRAFFIC_VBR;
439 errx(1, "missing arg(s) for VBR");
441 errx(1, "too many parameters for VBR");
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;
456 } else if (strcasecmp(argv[0], "abr") == 0) {
457 sdl.sdl_data[idx++] = ATMIO_TRAFFIC_ABR;
459 errx(1, "missing arg(s) for ABR");
461 errx(1, "too many parameters for ABR");
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;
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;
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;
479 errx(1, "ICR must be >= MCR");
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;
486 num = parse_num(argv[5], "NRM", 0x7UL);
487 sdl.sdl_data[idx++] = (num >> 0) & 0xff;
489 num = parse_num(argv[6], "TRM", 0x7UL);
490 sdl.sdl_data[idx++] = (num >> 0) & 0xff;
492 num = parse_num(argv[7], "ADTF", 0x3ffUL);
493 sdl.sdl_data[idx++] = (num >> 8) & 0xff;
494 sdl.sdl_data[idx++] = (num >> 0) & 0xff;
496 num = parse_num(argv[8], "RIF", 0xfUL);
497 sdl.sdl_data[idx++] = (num >> 0) & 0xff;
499 num = parse_num(argv[9], "RDF", 0xfUL);
500 sdl.sdl_data[idx++] = (num >> 0) & 0xff;
502 num = parse_num(argv[10], "CDF", 0x7UL);
503 sdl.sdl_data[idx++] = (num >> 0) & 0xff;
506 errx(1, "bad traffic type '%s'", argv[0]);
508 sdl.sdl_data[idx++] = ATMIO_TRAFFIC_UBR;
510 sdl.sdl_alen = idx - sdl.sdl_nlen;
511 sdl.sdl_len += sdl.sdl_nlen + sdl.sdl_alen;
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);
523 do_route(RTM_ADD, RTF_HOST | RTF_STATIC | RTF_UP, &sain, &sdl);
527 * Delete an NATM route
530 natm_delete(int argc, char *argv[])
534 struct sockaddr_in sain;
537 struct natm_route *r;
539 static int printonly;
541 static const struct option opts[] = {
542 { "printonly", OPT_SIMPLE, &printonly },
546 while ((opt = parse_options(&argc, &argv, opts)) != -1)
553 memset(&sain, 0, sizeof(sain));
554 sain.sin_len = sizeof(sain);
555 sain.sin_family = AF_INET;
558 /* get the IP address for <dest> */
559 hp = gethostbyname(argv[0]);
561 errx(1, "bad hostname %s: %s", argv[0],
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));
567 TAILQ_FOREACH(r, &natm_route_list, link)
568 if (r->host.s_addr == sain.sin_addr.s_addr)
571 errx(1, "no NATM route to host '%s' (%s)", argv[0],
572 inet_ntoa(sain.sin_addr));
574 } else if (argc == 3) {
575 TAILQ_FOREACH(aif, &diagif_list, link)
576 if (strcmp(aif->ifname, argv[0]) == 0)
579 errx(1, "no such interface '%s'", argv[0]);
581 vpi = parse_num(argv[1], "VPI", 0xff);
582 vci = parse_num(argv[2], "VCI", 0xffff);
584 TAILQ_FOREACH(r, &natm_route_list, link)
585 if (r->aif == aif && r->vpi == vpi && r->vci == vci)
588 errx(1, "no such NATM route %s %u %u", argv[0],
590 sain.sin_addr = r->host;
593 errx(1, "bad number of arguments for 'natm delete'");
596 printf("route delete %s\n", inet_ntoa(r->host));
600 do_route(RTM_DELETE, r->flags, &sain, NULL);
607 natm_show(int argc, char *argv[])
610 struct natm_route *r;
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"
620 static int numeric, abr;
622 static const struct option opts[] = {
623 { "abr", OPT_SIMPLE, &abr },
624 { "numeric", OPT_SIMPLE, &numeric },
628 static const char head[] =
629 "Destination Iface VPI VCI Encaps Trf PCR "
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";
635 while ((opt = parse_options(&argc, &argv, opts)) != -1)
643 TAILQ_FOREACH(r, &natm_route_list, link) {
644 heading(abr ? head_abr : head);
646 printf("%-20s", inet_ntoa(r->host));
647 else if (r->host.s_addr == INADDR_ANY)
648 printf("%-20s", "default");
650 hp = gethostbyaddr((char *)&r->host, sizeof(r->host),
653 printf("%-20s", hp->h_name);
655 printf("%-20s", inet_ntoa(r->host));
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) {
661 case ATMIO_TRAFFIC_UBR:
662 case ATMIO_TRAFFIC_CBR:
663 printf("%-8u", r->pcr);
666 case ATMIO_TRAFFIC_VBR:
667 printf("%-8u%-8u%-8u", r->pcr, r->scr, r->mbs);
670 case ATMIO_TRAFFIC_ABR:
671 printf("%-8u%-8u%-8u", r->pcr, r->mcr, r->icr);
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);