681 lines
17 KiB
C
681 lines
17 KiB
C
|
/*
|
||
|
* Copyright (c) 2003
|
||
|
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
* 1. Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
|
* SUCH DAMAGE.
|
||
|
*
|
||
|
* Author: Hartmut Brandt <harti@freebsd.org>
|
||
|
*/
|
||
|
#include <sys/cdefs.h>
|
||
|
__FBSDID("$FreeBSD$");
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <sys/sysctl.h>
|
||
|
#include <net/if_atm.h>
|
||
|
#include <net/if_dl.h>
|
||
|
#include <net/route.h>
|
||
|
#include <netinet/in.h>
|
||
|
#include <arpa/inet.h>
|
||
|
#include <netdb.h>
|
||
|
#include "atmconfig.h"
|
||
|
#include "private.h"
|
||
|
#include "diag.h"
|
||
|
|
||
|
static void natm_add(int, char *[]);
|
||
|
static void natm_delete(int, char *[]);
|
||
|
static void natm_show(int, char *[]);
|
||
|
|
||
|
const struct cmdtab natm_tab[] = {
|
||
|
{ "add", NULL, natm_add },
|
||
|
{ "delete", NULL, natm_delete },
|
||
|
{ "show", NULL, natm_show },
|
||
|
{ NULL, NULL, NULL }
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Structure to hold a route
|
||
|
*/
|
||
|
struct natm_route {
|
||
|
TAILQ_ENTRY(natm_route) link;
|
||
|
struct in_addr host;
|
||
|
struct diagif *aif;
|
||
|
u_int flags;
|
||
|
int llcsnap;
|
||
|
u_int vpi, vci;
|
||
|
u_int traffic;
|
||
|
u_int pcr, scr, mbs, icr, mcr;
|
||
|
u_int tbe, nrm, trm, adtf, rif, rdf, cdf;
|
||
|
};
|
||
|
static TAILQ_HEAD(, natm_route) natm_route_list =
|
||
|
TAILQ_HEAD_INITIALIZER(natm_route_list);
|
||
|
|
||
|
static void
|
||
|
store_route(struct rt_msghdr *rtm)
|
||
|
{
|
||
|
u_int i;
|
||
|
struct natm_route *r;
|
||
|
char *cp;
|
||
|
struct sockaddr *sa;
|
||
|
struct sockaddr_in *sain;
|
||
|
struct sockaddr_dl *sdl;
|
||
|
struct diagif *aif;
|
||
|
u_int n;
|
||
|
|
||
|
r = malloc(sizeof(*r));
|
||
|
if (r == NULL)
|
||
|
err(1, "allocate route");
|
||
|
|
||
|
r->flags = rtm->rtm_flags;
|
||
|
cp = (char *)(rtm + 1);
|
||
|
for (i = 1; i != 0; i <<= 1) {
|
||
|
if (rtm->rtm_addrs & i) {
|
||
|
sa = (struct sockaddr *)cp;
|
||
|
cp += roundup(sa->sa_len, sizeof(long));
|
||
|
switch (i) {
|
||
|
|
||
|
case RTA_DST:
|
||
|
if (sa->sa_family != AF_INET) {
|
||
|
warnx("RTA_DST not AF_INET %u", sa->sa_family);
|
||
|
goto fail;
|
||
|
}
|
||
|
sain = (struct sockaddr_in *)(void *)sa;
|
||
|
if (sain->sin_len < 4)
|
||
|
r->host.s_addr = INADDR_ANY;
|
||
|
else
|
||
|
r->host = sain->sin_addr;
|
||
|
break;
|
||
|
|
||
|
case RTA_GATEWAY:
|
||
|
if (sa->sa_family != AF_LINK) {
|
||
|
warnx("RTA_GATEWAY not AF_LINK");
|
||
|
goto fail;
|
||
|
}
|
||
|
sdl = (struct sockaddr_dl *)(void *)sa;
|
||
|
TAILQ_FOREACH(aif, &diagif_list, link)
|
||
|
if (strlen(aif->ifname) ==
|
||
|
sdl->sdl_nlen &&
|
||
|
strncmp(aif->ifname, sdl->sdl_data,
|
||
|
sdl->sdl_nlen) == 0)
|
||
|
break;
|
||
|
if (aif == NULL) {
|
||
|
warnx("interface '%.*s' not found",
|
||
|
sdl->sdl_nlen, sdl->sdl_data);
|
||
|
goto fail;
|
||
|
}
|
||
|
r->aif = aif;
|
||
|
|
||
|
/* parse ATM stuff */
|
||
|
|
||
|
#define GET3() (((sdl->sdl_data[n] & 0xff) << 16) | \
|
||
|
((sdl->sdl_data[n + 1] & 0xff) << 8) | \
|
||
|
((sdl->sdl_data[n + 2] & 0xff) << 0))
|
||
|
#define GET2() (((sdl->sdl_data[n] & 0xff) << 8) | \
|
||
|
((sdl->sdl_data[n + 1] & 0xff) << 0))
|
||
|
#define GET1() (((sdl->sdl_data[n] & 0xff) << 0))
|
||
|
|
||
|
n = sdl->sdl_nlen;
|
||
|
if (sdl->sdl_alen < 4) {
|
||
|
warnx("RTA_GATEWAY alen too short");
|
||
|
goto fail;
|
||
|
}
|
||
|
r->llcsnap = GET1() & ATM_PH_LLCSNAP;
|
||
|
n++;
|
||
|
r->vpi = GET1();
|
||
|
n++;
|
||
|
r->vci = GET2();
|
||
|
n += 2;
|
||
|
if (sdl->sdl_alen == 4) {
|
||
|
/* old address */
|
||
|
r->traffic = ATMIO_TRAFFIC_UBR;
|
||
|
r->pcr = 0;
|
||
|
break;
|
||
|
}
|
||
|
/* new address */
|
||
|
r->traffic = GET1();
|
||
|
n++;
|
||
|
switch (r->traffic) {
|
||
|
|
||
|
case ATMIO_TRAFFIC_UBR:
|
||
|
if (sdl->sdl_alen >= 5 + 3) {
|
||
|
r->pcr = GET3();
|
||
|
n += 3;
|
||
|
} else
|
||
|
r->pcr = 0;
|
||
|
break;
|
||
|
|
||
|
case ATMIO_TRAFFIC_CBR:
|
||
|
if (sdl->sdl_alen < 5 + 3) {
|
||
|
warnx("CBR address too short");
|
||
|
goto fail;
|
||
|
}
|
||
|
r->pcr = GET3();
|
||
|
n += 3;
|
||
|
break;
|
||
|
|
||
|
case ATMIO_TRAFFIC_VBR:
|
||
|
if (sdl->sdl_alen < 5 + 3 * 3) {
|
||
|
warnx("VBR address too short");
|
||
|
goto fail;
|
||
|
}
|
||
|
r->pcr = GET3();
|
||
|
n += 3;
|
||
|
r->scr = GET3();
|
||
|
n += 3;
|
||
|
r->mbs = GET3();
|
||
|
n += 3;
|
||
|
break;
|
||
|
|
||
|
case ATMIO_TRAFFIC_ABR:
|
||
|
if (sdl->sdl_alen < 5 + 4 * 3 + 2 +
|
||
|
1 * 2 + 3) {
|
||
|
warnx("ABR address too short");
|
||
|
goto fail;
|
||
|
}
|
||
|
r->pcr = GET3();
|
||
|
n += 3;
|
||
|
r->mcr = GET3();
|
||
|
n += 3;
|
||
|
r->icr = GET3();
|
||
|
n += 3;
|
||
|
r->tbe = GET3();
|
||
|
n += 3;
|
||
|
r->nrm = GET1();
|
||
|
n++;
|
||
|
r->trm = GET1();
|
||
|
n++;
|
||
|
r->adtf = GET2();
|
||
|
n += 2;
|
||
|
r->rif = GET1();
|
||
|
n++;
|
||
|
r->rdf = GET1();
|
||
|
n++;
|
||
|
r->cdf = GET1();
|
||
|
n++;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
goto fail;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TAILQ_INSERT_TAIL(&natm_route_list, r, link);
|
||
|
|
||
|
return;
|
||
|
fail:
|
||
|
free(r);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Fetch the INET routes that a ours
|
||
|
*/
|
||
|
static void
|
||
|
natm_route_fetch(void)
|
||
|
{
|
||
|
int name[6];
|
||
|
size_t needed;
|
||
|
u_char *buf, *next;
|
||
|
struct rt_msghdr *rtm;
|
||
|
|
||
|
name[0] = CTL_NET;
|
||
|
name[1] = PF_ROUTE;
|
||
|
name[2] = 0;
|
||
|
name[3] = AF_INET;
|
||
|
name[4] = NET_RT_DUMP;
|
||
|
name[5] = 0;
|
||
|
|
||
|
if (sysctl(name, 6, NULL, &needed, NULL, 0) == -1)
|
||
|
err(1, "rtable estimate");
|
||
|
needed *= 2;
|
||
|
if ((buf = malloc(needed)) == NULL)
|
||
|
err(1, "rtable buffer (%zu)", needed);
|
||
|
if (sysctl(name, 6, buf, &needed, NULL, 0) == -1)
|
||
|
err(1, "rtable get");
|
||
|
|
||
|
next = buf;
|
||
|
while (next < buf + needed) {
|
||
|
rtm = (struct rt_msghdr *)(void *)next;
|
||
|
next += rtm->rtm_msglen;
|
||
|
|
||
|
if (rtm->rtm_type == RTM_GET) {
|
||
|
if ((rtm->rtm_flags & (RTF_UP | RTF_HOST |
|
||
|
RTF_STATIC)) == (RTF_UP | RTF_HOST | RTF_STATIC) &&
|
||
|
(rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY |
|
||
|
RTA_IFP)) == (RTA_DST | RTA_GATEWAY | RTA_IFP))
|
||
|
store_route(rtm);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static u_long
|
||
|
parse_num(const char *arg, const char *name, u_long limit)
|
||
|
{
|
||
|
u_long res;
|
||
|
char *end;
|
||
|
|
||
|
errno = 0;
|
||
|
res = strtoul(arg, &end, 10);
|
||
|
if (*end != '\0' || end == arg || errno != 0)
|
||
|
errx(1, "cannot parse %s '%s'", name, arg);
|
||
|
if (res > limit)
|
||
|
errx(1, "%s out of range (0...%lu)", name, limit);
|
||
|
return (res);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
do_route(u_int type, u_int flags, const struct sockaddr_in *sain,
|
||
|
const struct sockaddr_dl *sdl)
|
||
|
{
|
||
|
struct {
|
||
|
struct rt_msghdr h;
|
||
|
char space[512];
|
||
|
} msg;
|
||
|
char *ptr;
|
||
|
int s;
|
||
|
ssize_t rlen;
|
||
|
|
||
|
/* create routing message */
|
||
|
bzero(&msg, sizeof(msg));
|
||
|
msg.h.rtm_msglen = sizeof(msg.h);
|
||
|
msg.h.rtm_version = RTM_VERSION;
|
||
|
msg.h.rtm_type = type;
|
||
|
msg.h.rtm_index = 0;
|
||
|
msg.h.rtm_flags = flags;
|
||
|
msg.h.rtm_addrs = RTA_DST | (sdl != NULL ? RTA_GATEWAY : 0);
|
||
|
msg.h.rtm_pid = getpid();
|
||
|
|
||
|
ptr = (char *)&msg + sizeof(msg.h);
|
||
|
memcpy(ptr, sain, sain->sin_len);
|
||
|
ptr += roundup(sain->sin_len, sizeof(long));
|
||
|
msg.h.rtm_msglen += roundup(sain->sin_len, sizeof(long));
|
||
|
|
||
|
if (sdl != NULL) {
|
||
|
memcpy(ptr, sdl, sdl->sdl_len);
|
||
|
ptr += roundup(sdl->sdl_len, sizeof(long));
|
||
|
msg.h.rtm_msglen += roundup(sdl->sdl_len, sizeof(long));
|
||
|
}
|
||
|
|
||
|
/* open socket */
|
||
|
s = socket(PF_ROUTE, SOCK_RAW, AF_INET);
|
||
|
if (s == -1)
|
||
|
err(1, "cannot open routing socket");
|
||
|
|
||
|
rlen = write(s, &msg, msg.h.rtm_msglen);
|
||
|
if (rlen == -1)
|
||
|
err(1, "writing to routing socket");
|
||
|
if ((size_t)rlen != msg.h.rtm_msglen)
|
||
|
errx(1, "short write to routing socket: %zu %u",
|
||
|
(size_t)rlen, msg.h.rtm_msglen);
|
||
|
close(s);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Add a new NATM route
|
||
|
*/
|
||
|
static void
|
||
|
natm_add(int argc, char *argv[])
|
||
|
{
|
||
|
int opt;
|
||
|
struct hostent *hp;
|
||
|
struct sockaddr_in sain;
|
||
|
struct sockaddr_dl sdl;
|
||
|
struct diagif *aif;
|
||
|
u_long num, num1;
|
||
|
u_int idx;
|
||
|
|
||
|
static int printonly;
|
||
|
|
||
|
static const struct option opts[] = {
|
||
|
{ "printonly", OPT_SIMPLE, &printonly },
|
||
|
{ NULL, 0, NULL }
|
||
|
};
|
||
|
|
||
|
while ((opt = parse_options(&argc, &argv, opts)) != -1)
|
||
|
switch (opt) {
|
||
|
}
|
||
|
|
||
|
if (argc < 5)
|
||
|
errx(1, "missing arguments for 'natm add'");
|
||
|
|
||
|
memset(&sdl, 0, sizeof(sdl));
|
||
|
sdl.sdl_len = sizeof(sdl);
|
||
|
sdl.sdl_family = AF_LINK;
|
||
|
|
||
|
/* get the IP address for <dest> */
|
||
|
memset(&sain, 0, sizeof(sain));
|
||
|
hp = gethostbyname(argv[0]);
|
||
|
if (hp == NULL)
|
||
|
errx(1, "bad hostname %s: %s", argv[0], hstrerror(h_errno));
|
||
|
if (hp->h_addrtype != AF_INET)
|
||
|
errx(1, "bad address type for %s", argv[0]);
|
||
|
sain.sin_len = sizeof(sain);
|
||
|
sain.sin_family = AF_INET;
|
||
|
memcpy(&sain.sin_addr, hp->h_addr, sizeof(sain.sin_addr));
|
||
|
|
||
|
/* find interface */
|
||
|
diagif_fetch();
|
||
|
TAILQ_FOREACH(aif, &diagif_list, link)
|
||
|
if (strcmp(aif->ifname, argv[1]) == 0)
|
||
|
break;
|
||
|
if (aif == NULL)
|
||
|
errx(1, "unknown ATM interface '%s'", argv[1]);
|
||
|
sdl.sdl_index = aif->index;
|
||
|
strcpy(sdl.sdl_data, aif->ifname);
|
||
|
idx = sdl.sdl_nlen = strlen(aif->ifname);
|
||
|
idx++;
|
||
|
|
||
|
/* verify VPI/VCI */
|
||
|
num = parse_num(argv[2], "VPI", (1U << aif->mib.vpi_bits));
|
||
|
sdl.sdl_data[idx++] = num & 0xff;
|
||
|
num = parse_num(argv[3], "VCI", (1U << aif->mib.vci_bits));
|
||
|
if (num == 0)
|
||
|
errx(1, "VCI may not be 0");
|
||
|
sdl.sdl_data[idx++] = (num >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = num & 0xff;
|
||
|
|
||
|
/* encapsulation */
|
||
|
if (strcasecmp(argv[4], "llc/snap") == 0) {
|
||
|
sdl.sdl_data[sdl.sdl_nlen] = ATM_PH_LLCSNAP;
|
||
|
} else if (strcasecmp(argv[4], "aal5") == 0) {
|
||
|
sdl.sdl_data[sdl.sdl_nlen] = 0;
|
||
|
} else
|
||
|
errx(1, "bad encapsulation type '%s'", argv[4]);
|
||
|
|
||
|
/* look at the traffic */
|
||
|
argc -= 5;
|
||
|
argv += 5;
|
||
|
|
||
|
if (argc != 0) {
|
||
|
if (strcasecmp(argv[0], "ubr") == 0) {
|
||
|
sdl.sdl_data[idx++] = ATMIO_TRAFFIC_UBR;
|
||
|
if (argc == 1)
|
||
|
/* ok */;
|
||
|
else if (argc == 2) {
|
||
|
num = parse_num(argv[1], "PCR", aif->mib.pcr);
|
||
|
sdl.sdl_data[idx++] = (num >> 16) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
} else
|
||
|
errx(1, "too many parameters for UBR");
|
||
|
|
||
|
} else if (strcasecmp(argv[0], "cbr") == 0) {
|
||
|
sdl.sdl_data[idx++] = ATMIO_TRAFFIC_CBR;
|
||
|
if (argc == 1)
|
||
|
errx(1, "missing PCR for CBR");
|
||
|
if (argc > 2)
|
||
|
errx(1, "too many parameters for CBR");
|
||
|
num = parse_num(argv[1], "PCR", aif->mib.pcr);
|
||
|
sdl.sdl_data[idx++] = (num >> 16) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
} else if (strcasecmp(argv[0], "vbr") == 0) {
|
||
|
sdl.sdl_data[idx++] = ATMIO_TRAFFIC_VBR;
|
||
|
|
||
|
if (argc < 4)
|
||
|
errx(1, "missing arg(s) for VBR");
|
||
|
if (argc > 4)
|
||
|
errx(1, "too many parameters for VBR");
|
||
|
|
||
|
num = parse_num(argv[1], "PCR", aif->mib.pcr);
|
||
|
sdl.sdl_data[idx++] = (num >> 16) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
num = parse_num(argv[2], "SCR", num);
|
||
|
sdl.sdl_data[idx++] = (num >> 16) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
num = parse_num(argv[3], "MBS", 0xffffffLU);
|
||
|
sdl.sdl_data[idx++] = (num >> 16) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
} else if (strcasecmp(argv[0], "abr") == 0) {
|
||
|
sdl.sdl_data[idx++] = ATMIO_TRAFFIC_ABR;
|
||
|
if (argc < 11)
|
||
|
errx(1, "missing arg(s) for ABR");
|
||
|
if (argc > 11)
|
||
|
errx(1, "too many parameters for ABR");
|
||
|
|
||
|
num = parse_num(argv[1], "PCR", aif->mib.pcr);
|
||
|
sdl.sdl_data[idx++] = (num >> 16) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
num1 = parse_num(argv[2], "MCR", num);
|
||
|
sdl.sdl_data[idx++] = (num1 >> 16) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num1 >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num1 >> 0) & 0xff;
|
||
|
|
||
|
num = parse_num(argv[3], "ICR", num);
|
||
|
sdl.sdl_data[idx++] = (num >> 16) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
if (num < num1)
|
||
|
errx(1, "ICR must be >= MCR");
|
||
|
|
||
|
num = parse_num(argv[4], "TBE", 0xffffffUL);
|
||
|
sdl.sdl_data[idx++] = (num >> 16) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
num = parse_num(argv[5], "NRM", 0x7UL);
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
num = parse_num(argv[6], "TRM", 0x7UL);
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
num = parse_num(argv[7], "ADTF", 0x3ffUL);
|
||
|
sdl.sdl_data[idx++] = (num >> 8) & 0xff;
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
num = parse_num(argv[8], "RIF", 0xfUL);
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
num = parse_num(argv[9], "RDF", 0xfUL);
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
num = parse_num(argv[10], "CDF", 0x7UL);
|
||
|
sdl.sdl_data[idx++] = (num >> 0) & 0xff;
|
||
|
|
||
|
} else
|
||
|
errx(1, "bad traffic type '%s'", argv[0]);
|
||
|
} else
|
||
|
sdl.sdl_data[idx++] = ATMIO_TRAFFIC_UBR;
|
||
|
|
||
|
sdl.sdl_alen = idx - sdl.sdl_nlen;
|
||
|
sdl.sdl_len += sdl.sdl_nlen + sdl.sdl_alen;
|
||
|
|
||
|
if (printonly) {
|
||
|
printf("route add -iface %s -link %.*s",
|
||
|
inet_ntoa(sain.sin_addr), sdl.sdl_nlen, sdl.sdl_data);
|
||
|
for (idx = 0; idx < sdl.sdl_alen; idx++)
|
||
|
printf("%c%x", ".:"[idx == 0],
|
||
|
(u_int)sdl.sdl_data[sdl.sdl_nlen + idx] & 0xffU);
|
||
|
printf("\n");
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
do_route(RTM_ADD, RTF_HOST | RTF_STATIC | RTF_UP, &sain, &sdl);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Delete an NATM route
|
||
|
*/
|
||
|
static void
|
||
|
natm_delete(int argc, char *argv[])
|
||
|
{
|
||
|
int opt;
|
||
|
struct hostent *hp;
|
||
|
struct sockaddr_in sain;
|
||
|
u_int vpi, vci;
|
||
|
struct diagif *aif;
|
||
|
struct natm_route *r;
|
||
|
|
||
|
static int printonly;
|
||
|
|
||
|
static const struct option opts[] = {
|
||
|
{ "printonly", OPT_SIMPLE, &printonly },
|
||
|
{ NULL, 0, NULL }
|
||
|
};
|
||
|
|
||
|
while ((opt = parse_options(&argc, &argv, opts)) != -1)
|
||
|
switch (opt) {
|
||
|
}
|
||
|
|
||
|
diagif_fetch();
|
||
|
natm_route_fetch();
|
||
|
|
||
|
memset(&sain, 0, sizeof(sain));
|
||
|
sain.sin_len = sizeof(sain);
|
||
|
sain.sin_family = AF_INET;
|
||
|
|
||
|
if (argc == 1) {
|
||
|
/* get the IP address for <dest> */
|
||
|
hp = gethostbyname(argv[0]);
|
||
|
if (hp == NULL)
|
||
|
errx(1, "bad hostname %s: %s", argv[0],
|
||
|
hstrerror(h_errno));
|
||
|
if (hp->h_addrtype != AF_INET)
|
||
|
errx(1, "bad address type for %s", argv[0]);
|
||
|
memcpy(&sain.sin_addr, hp->h_addr, sizeof(sain.sin_addr));
|
||
|
|
||
|
TAILQ_FOREACH(r, &natm_route_list, link)
|
||
|
if (r->host.s_addr == sain.sin_addr.s_addr)
|
||
|
break;
|
||
|
if (r == NULL)
|
||
|
errx(1, "no NATM route to host '%s' (%s)", argv[0],
|
||
|
inet_ntoa(sain.sin_addr));
|
||
|
|
||
|
} else if (argc == 3) {
|
||
|
TAILQ_FOREACH(aif, &diagif_list, link)
|
||
|
if (strcmp(aif->ifname, argv[0]) == 0)
|
||
|
break;
|
||
|
if (aif == 0)
|
||
|
errx(1, "no such interface '%s'", argv[0]);
|
||
|
|
||
|
vpi = parse_num(argv[1], "VPI", 0xff);
|
||
|
vci = parse_num(argv[2], "VCI", 0xffff);
|
||
|
|
||
|
TAILQ_FOREACH(r, &natm_route_list, link)
|
||
|
if (r->aif == aif && r->vpi == vpi && r->vci == vci)
|
||
|
break;
|
||
|
if (r == NULL)
|
||
|
errx(1, "no such NATM route %s %u %u", argv[0],
|
||
|
vpi, vci);
|
||
|
sain.sin_addr = r->host;
|
||
|
|
||
|
} else
|
||
|
errx(1, "bad number of arguments for 'natm delete'");
|
||
|
|
||
|
if (printonly) {
|
||
|
printf("route delete %s\n", inet_ntoa(r->host));
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
do_route(RTM_DELETE, r->flags, &sain, NULL);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Show NATM routes
|
||
|
*/
|
||
|
static void
|
||
|
natm_show(int argc, char *argv[])
|
||
|
{
|
||
|
int opt;
|
||
|
struct natm_route *r;
|
||
|
struct hostent *hp;
|
||
|
|
||
|
static const char *const traffics[] = {
|
||
|
[ATMIO_TRAFFIC_UBR] = "UBR",
|
||
|
[ATMIO_TRAFFIC_CBR] = "CBR",
|
||
|
[ATMIO_TRAFFIC_VBR] = "VBR",
|
||
|
[ATMIO_TRAFFIC_ABR] = "ABR"
|
||
|
};
|
||
|
|
||
|
static int numeric, abr;
|
||
|
|
||
|
static const struct option opts[] = {
|
||
|
{ "abr", OPT_SIMPLE, &abr },
|
||
|
{ "numeric", OPT_SIMPLE, &numeric },
|
||
|
{ NULL, 0, NULL }
|
||
|
};
|
||
|
|
||
|
static const char head[] =
|
||
|
"Destination Iface VPI VCI Encaps Trf PCR "
|
||
|
"SCR/MCR MBS/ICR\n";
|
||
|
static const char head_abr[] =
|
||
|
"Destination Iface VPI VCI Encaps Trf PCR "
|
||
|
"SCR/MCR MBS/ICR TBE NRM TRM ADTF RIF RDF CDF\n";
|
||
|
|
||
|
while ((opt = parse_options(&argc, &argv, opts)) != -1)
|
||
|
switch (opt) {
|
||
|
}
|
||
|
|
||
|
diagif_fetch();
|
||
|
natm_route_fetch();
|
||
|
|
||
|
heading_init();
|
||
|
TAILQ_FOREACH(r, &natm_route_list, link) {
|
||
|
heading(abr ? head_abr : head);
|
||
|
if (numeric)
|
||
|
printf("%-20s", inet_ntoa(r->host));
|
||
|
else if (r->host.s_addr == INADDR_ANY)
|
||
|
printf("%-20s", "default");
|
||
|
else {
|
||
|
hp = gethostbyaddr((char *)&r->host, sizeof(r->host),
|
||
|
AF_INET);
|
||
|
if (hp != NULL)
|
||
|
printf("%-20s", hp->h_name);
|
||
|
else
|
||
|
printf("%-20s", inet_ntoa(r->host));
|
||
|
}
|
||
|
printf("%-12s%-4u%-6u%-9s%-4s", r->aif->ifname, r->vpi, r->vci,
|
||
|
r->llcsnap ? "LLC/SNAP" : "AAL5", traffics[r->traffic]);
|
||
|
switch (r->traffic) {
|
||
|
|
||
|
case ATMIO_TRAFFIC_UBR:
|
||
|
case ATMIO_TRAFFIC_CBR:
|
||
|
printf("%-8u", r->pcr);
|
||
|
break;
|
||
|
|
||
|
case ATMIO_TRAFFIC_VBR:
|
||
|
printf("%-8u%-8u%-8u", r->pcr, r->scr, r->mbs);
|
||
|
break;
|
||
|
|
||
|
case ATMIO_TRAFFIC_ABR:
|
||
|
printf("%-8u%-8u%-8u", r->pcr, r->mcr, r->icr);
|
||
|
if (abr)
|
||
|
printf("%-8u%-4u%-4u%-5u%-4u%-4u%-4u",
|
||
|
r->tbe, r->nrm, r->trm, r->adtf,
|
||
|
r->rif, r->rdf, r->cdf);
|
||
|
break;
|
||
|
}
|
||
|
printf("\n");
|
||
|
}
|
||
|
}
|