natm.c revision 118824
1118824Sharti/*
2118824Sharti * Copyright (c) 2003
3118824Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4118824Sharti * 	All rights reserved.
5118824Sharti *
6118824Sharti * Redistribution and use in source and binary forms, with or without
7118824Sharti * modification, are permitted provided that the following conditions
8118824Sharti * are met:
9118824Sharti * 1. Redistributions of source code must retain the above copyright
10118824Sharti *    notice, this list of conditions and the following disclaimer.
11118824Sharti * 2. Redistributions in binary form must reproduce the above copyright
12118824Sharti *    notice, this list of conditions and the following disclaimer in the
13118824Sharti *    documentation and/or other materials provided with the distribution.
14118824Sharti *
15118824Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16118824Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17118824Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18118824Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19118824Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20118824Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21118824Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22118824Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23118824Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24118824Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25118824Sharti * SUCH DAMAGE.
26118824Sharti *
27118824Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28118824Sharti */
29118824Sharti#include <sys/cdefs.h>
30118824Sharti__FBSDID("$FreeBSD: head/sbin/atm/atmconfig/natm.c 118824 2003-08-12 14:25:57Z harti $");
31118824Sharti
32118824Sharti#include <sys/types.h>
33118824Sharti#include <sys/socket.h>
34118824Sharti#include <sys/sysctl.h>
35118824Sharti#include <net/if.h>
36118824Sharti#include <net/if_var.h>
37118824Sharti#include <net/if_mib.h>
38118824Sharti#include <net/if_atm.h>
39118824Sharti#include <net/if_dl.h>
40118824Sharti#include <net/route.h>
41118824Sharti#include <netinet/in.h>
42118824Sharti#include <arpa/inet.h>
43118824Sharti#include <netdb.h>
44118824Sharti#include "atmconfig.h"
45118824Sharti#include "private.h"
46118824Sharti#include "diag.h"
47118824Sharti
48118824Shartistatic void natm_add(int, char *[]);
49118824Shartistatic void natm_delete(int, char *[]);
50118824Shartistatic void natm_show(int, char *[]);
51118824Sharti
52118824Sharticonst struct cmdtab natm_tab[] = {
53118824Sharti	{ "add",	NULL,		natm_add },
54118824Sharti	{ "delete",	NULL,		natm_delete },
55118824Sharti	{ "show",	NULL,		natm_show },
56118824Sharti	{ NULL, 	NULL, 		NULL }
57118824Sharti};
58118824Sharti
59118824Sharti/*
60118824Sharti * Structure to hold a route
61118824Sharti */
62118824Shartistruct natm_route {
63118824Sharti	TAILQ_ENTRY(natm_route) link;
64118824Sharti	struct in_addr	host;
65118824Sharti	struct diagif	*aif;
66118824Sharti	u_int		flags;
67118824Sharti	int		llcsnap;
68118824Sharti	u_int		vpi, vci;
69118824Sharti	u_int		traffic;
70118824Sharti	u_int		pcr, scr, mbs, icr, mcr;
71118824Sharti	u_int		tbe, nrm, trm, adtf, rif, rdf, cdf;
72118824Sharti};
73118824Shartistatic TAILQ_HEAD(, natm_route) natm_route_list =
74118824Sharti    TAILQ_HEAD_INITIALIZER(natm_route_list);
75118824Sharti
76118824Shartistatic void
77118824Shartistore_route(struct rt_msghdr *rtm)
78118824Sharti{
79118824Sharti	u_int i;
80118824Sharti	struct natm_route *r;
81118824Sharti	char *cp;
82118824Sharti	struct sockaddr *sa;
83118824Sharti	struct sockaddr_in *sain;
84118824Sharti	struct sockaddr_dl *sdl;
85118824Sharti	struct diagif *aif;
86118824Sharti	u_int n;
87118824Sharti
88118824Sharti	r = malloc(sizeof(*r));
89118824Sharti	if (r == NULL)
90118824Sharti		err(1, "allocate route");
91118824Sharti
92118824Sharti	r->flags = rtm->rtm_flags;
93118824Sharti	cp = (char *)(rtm + 1);
94118824Sharti	for (i = 1; i != 0; i <<= 1) {
95118824Sharti		if (rtm->rtm_addrs & i) {
96118824Sharti			sa = (struct sockaddr *)cp;
97118824Sharti			cp += roundup(sa->sa_len, sizeof(long));
98118824Sharti			switch (i) {
99118824Sharti
100118824Sharti			  case RTA_DST:
101118824Sharti				if (sa->sa_family != AF_INET) {
102118824Sharti					warnx("RTA_DST not AF_INET %u", sa->sa_family);
103118824Sharti					goto fail;
104118824Sharti				}
105118824Sharti				sain = (struct sockaddr_in *)(void *)sa;
106118824Sharti				if (sain->sin_len < 4)
107118824Sharti					r->host.s_addr = INADDR_ANY;
108118824Sharti				else
109118824Sharti					r->host = sain->sin_addr;
110118824Sharti				break;
111118824Sharti
112118824Sharti			  case RTA_GATEWAY:
113118824Sharti				if (sa->sa_family != AF_LINK) {
114118824Sharti					warnx("RTA_GATEWAY not AF_LINK");
115118824Sharti					goto fail;
116118824Sharti				}
117118824Sharti				sdl = (struct sockaddr_dl *)(void *)sa;
118118824Sharti				TAILQ_FOREACH(aif, &diagif_list, link)
119118824Sharti					if (strlen(aif->ifname) ==
120118824Sharti					    sdl->sdl_nlen &&
121118824Sharti					    strncmp(aif->ifname, sdl->sdl_data,
122118824Sharti					    sdl->sdl_nlen) == 0)
123118824Sharti						break;
124118824Sharti				if (aif == NULL) {
125118824Sharti					warnx("interface '%.*s' not found",
126118824Sharti					    sdl->sdl_nlen, sdl->sdl_data);
127118824Sharti					goto fail;
128118824Sharti				}
129118824Sharti				r->aif = aif;
130118824Sharti
131118824Sharti				/* parse ATM stuff */
132118824Sharti
133118824Sharti#define	GET3()	(((sdl->sdl_data[n] & 0xff) << 16) |	\
134118824Sharti		 ((sdl->sdl_data[n + 1] & 0xff) << 8) |	\
135118824Sharti		 ((sdl->sdl_data[n + 2] & 0xff) << 0))
136118824Sharti#define	GET2()	(((sdl->sdl_data[n] & 0xff) << 8) |	\
137118824Sharti		 ((sdl->sdl_data[n + 1] & 0xff) << 0))
138118824Sharti#define	GET1()	(((sdl->sdl_data[n] & 0xff) << 0))
139118824Sharti
140118824Sharti				n = sdl->sdl_nlen;
141118824Sharti				if (sdl->sdl_alen < 4) {
142118824Sharti					warnx("RTA_GATEWAY alen too short");
143118824Sharti					goto fail;
144118824Sharti				}
145118824Sharti				r->llcsnap = GET1() & ATM_PH_LLCSNAP;
146118824Sharti				n++;
147118824Sharti				r->vpi = GET1();
148118824Sharti				n++;
149118824Sharti				r->vci = GET2();
150118824Sharti				n += 2;
151118824Sharti				if (sdl->sdl_alen == 4) {
152118824Sharti					/* old address */
153118824Sharti					r->traffic = ATMIO_TRAFFIC_UBR;
154118824Sharti					r->pcr = 0;
155118824Sharti					break;
156118824Sharti				}
157118824Sharti				/* new address */
158118824Sharti				r->traffic = GET1();
159118824Sharti				n++;
160118824Sharti				switch (r->traffic) {
161118824Sharti
162118824Sharti				  case ATMIO_TRAFFIC_UBR:
163118824Sharti					if (sdl->sdl_alen >= 5 + 3) {
164118824Sharti						r->pcr = GET3();
165118824Sharti						n += 3;
166118824Sharti					} else
167118824Sharti						r->pcr = 0;
168118824Sharti					break;
169118824Sharti
170118824Sharti				  case ATMIO_TRAFFIC_CBR:
171118824Sharti					if (sdl->sdl_alen < 5 + 3) {
172118824Sharti						warnx("CBR address too short");
173118824Sharti						goto fail;
174118824Sharti					}
175118824Sharti					r->pcr = GET3();
176118824Sharti					n += 3;
177118824Sharti					break;
178118824Sharti
179118824Sharti				  case ATMIO_TRAFFIC_VBR:
180118824Sharti					if (sdl->sdl_alen < 5 + 3 * 3) {
181118824Sharti						warnx("VBR address too short");
182118824Sharti						goto fail;
183118824Sharti					}
184118824Sharti					r->pcr = GET3();
185118824Sharti					n += 3;
186118824Sharti					r->scr = GET3();
187118824Sharti					n += 3;
188118824Sharti					r->mbs = GET3();
189118824Sharti					n += 3;
190118824Sharti					break;
191118824Sharti
192118824Sharti				  case ATMIO_TRAFFIC_ABR:
193118824Sharti					if (sdl->sdl_alen < 5 + 4 * 3 + 2 +
194118824Sharti					    1 * 2 + 3) {
195118824Sharti						warnx("ABR address too short");
196118824Sharti						goto fail;
197118824Sharti					}
198118824Sharti					r->pcr = GET3();
199118824Sharti					n += 3;
200118824Sharti					r->mcr = GET3();
201118824Sharti					n += 3;
202118824Sharti					r->icr = GET3();
203118824Sharti					n += 3;
204118824Sharti					r->tbe = GET3();
205118824Sharti					n += 3;
206118824Sharti					r->nrm = GET1();
207118824Sharti					n++;
208118824Sharti					r->trm = GET1();
209118824Sharti					n++;
210118824Sharti					r->adtf = GET2();
211118824Sharti					n += 2;
212118824Sharti					r->rif = GET1();
213118824Sharti					n++;
214118824Sharti					r->rdf = GET1();
215118824Sharti					n++;
216118824Sharti					r->cdf = GET1();
217118824Sharti					n++;
218118824Sharti					break;
219118824Sharti
220118824Sharti				  default:
221118824Sharti					goto fail;
222118824Sharti				}
223118824Sharti				break;
224118824Sharti			}
225118824Sharti		}
226118824Sharti	}
227118824Sharti
228118824Sharti	TAILQ_INSERT_TAIL(&natm_route_list, r, link);
229118824Sharti
230118824Sharti	return;
231118824Sharti  fail:
232118824Sharti	free(r);
233118824Sharti}
234118824Sharti
235118824Sharti/*
236118824Sharti * Fetch the INET routes that a ours
237118824Sharti */
238118824Shartistatic void
239118824Shartinatm_route_fetch(void)
240118824Sharti{
241118824Sharti	int name[6];
242118824Sharti	size_t needed;
243118824Sharti	u_char *buf, *next;
244118824Sharti	struct rt_msghdr *rtm;
245118824Sharti
246118824Sharti	name[0] = CTL_NET;
247118824Sharti	name[1] = PF_ROUTE;
248118824Sharti	name[2] = 0;
249118824Sharti	name[3] = AF_INET;
250118824Sharti	name[4] = NET_RT_DUMP;
251118824Sharti	name[5] = 0;
252118824Sharti
253118824Sharti	if (sysctl(name, 6, NULL, &needed, NULL, 0) == -1)
254118824Sharti		err(1, "rtable estimate");
255118824Sharti	needed *= 2;
256118824Sharti	if ((buf = malloc(needed)) == NULL)
257118824Sharti		err(1, "rtable buffer (%zu)", needed);
258118824Sharti	if (sysctl(name, 6, buf, &needed, NULL, 0) == -1)
259118824Sharti		err(1, "rtable get");
260118824Sharti
261118824Sharti	next = buf;
262118824Sharti	while (next < buf + needed) {
263118824Sharti		rtm = (struct rt_msghdr *)(void *)next;
264118824Sharti		next += rtm->rtm_msglen;
265118824Sharti
266118824Sharti		if (rtm->rtm_type == RTM_GET) {
267118824Sharti			if ((rtm->rtm_flags & (RTF_UP | RTF_HOST |
268118824Sharti			    RTF_STATIC)) == (RTF_UP | RTF_HOST | RTF_STATIC) &&
269118824Sharti			    (rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY |
270118824Sharti			    RTA_IFP)) == (RTA_DST | RTA_GATEWAY | RTA_IFP))
271118824Sharti				store_route(rtm);
272118824Sharti		}
273118824Sharti	}
274118824Sharti}
275118824Sharti
276118824Shartistatic u_long
277118824Shartiparse_num(const char *arg, const char *name, u_long limit)
278118824Sharti{
279118824Sharti	u_long res;
280118824Sharti	char *end;
281118824Sharti
282118824Sharti	errno = 0;
283118824Sharti	res = strtoul(arg, &end, 10);
284118824Sharti	if (*end != '\0' || end == arg || errno != 0)
285118824Sharti		errx(1, "cannot parse %s '%s'", name, arg);
286118824Sharti	if (res > limit)
287118824Sharti		errx(1, "%s out of range (0...%lu)", name, limit);
288118824Sharti	return (res);
289118824Sharti}
290118824Sharti
291118824Shartistatic void
292118824Shartido_route(u_int type, u_int flags, const struct sockaddr_in *sain,
293118824Sharti    const struct sockaddr_dl *sdl)
294118824Sharti{
295118824Sharti	struct {
296118824Sharti		struct rt_msghdr h;
297118824Sharti		char	space[512];
298118824Sharti	} msg;
299118824Sharti	char *ptr;
300118824Sharti	int s;
301118824Sharti	ssize_t rlen;
302118824Sharti
303118824Sharti	/* create routing message */
304118824Sharti	bzero(&msg, sizeof(msg));
305118824Sharti	msg.h.rtm_msglen = sizeof(msg.h);
306118824Sharti	msg.h.rtm_version = RTM_VERSION;
307118824Sharti	msg.h.rtm_type = type;
308118824Sharti	msg.h.rtm_index = 0;
309118824Sharti	msg.h.rtm_flags = flags;
310118824Sharti	msg.h.rtm_addrs = RTA_DST | (sdl != NULL ? RTA_GATEWAY : 0);
311118824Sharti	msg.h.rtm_pid = getpid();
312118824Sharti
313118824Sharti	ptr = (char *)&msg + sizeof(msg.h);
314118824Sharti	memcpy(ptr, sain, sain->sin_len);
315118824Sharti	ptr += roundup(sain->sin_len, sizeof(long));
316118824Sharti	msg.h.rtm_msglen += roundup(sain->sin_len, sizeof(long));
317118824Sharti
318118824Sharti	if (sdl != NULL) {
319118824Sharti		memcpy(ptr, sdl, sdl->sdl_len);
320118824Sharti		ptr += roundup(sdl->sdl_len, sizeof(long));
321118824Sharti		msg.h.rtm_msglen += roundup(sdl->sdl_len, sizeof(long));
322118824Sharti	}
323118824Sharti
324118824Sharti	/* open socket */
325118824Sharti	s = socket(PF_ROUTE, SOCK_RAW, AF_INET);
326118824Sharti	if (s == -1)
327118824Sharti		err(1, "cannot open routing socket");
328118824Sharti
329118824Sharti	rlen = write(s, &msg, msg.h.rtm_msglen);
330118824Sharti	if (rlen == -1)
331118824Sharti		err(1, "writing to routing socket");
332118824Sharti	if ((size_t)rlen != msg.h.rtm_msglen)
333118824Sharti		errx(1, "short write to routing socket: %zu %u",
334118824Sharti		    (size_t)rlen, msg.h.rtm_msglen);
335118824Sharti	close(s);
336118824Sharti}
337118824Sharti
338118824Sharti/*
339118824Sharti * Add a new NATM route
340118824Sharti */
341118824Shartistatic void
342118824Shartinatm_add(int argc, char *argv[])
343118824Sharti{
344118824Sharti	int opt;
345118824Sharti	struct hostent *hp;
346118824Sharti	struct sockaddr_in sain;
347118824Sharti	struct sockaddr_dl sdl;
348118824Sharti	struct diagif *aif;
349118824Sharti	u_long num, num1;
350118824Sharti	u_int idx;
351118824Sharti
352118824Sharti	static int printonly;
353118824Sharti
354118824Sharti	static const struct option opts[] = {
355118824Sharti	    { "printonly", OPT_SIMPLE, &printonly },
356118824Sharti	    { NULL, 0, NULL }
357118824Sharti	};
358118824Sharti
359118824Sharti	while ((opt = parse_options(&argc, &argv, opts)) != -1)
360118824Sharti		switch (opt) {
361118824Sharti		}
362118824Sharti
363118824Sharti	if (argc < 5)
364118824Sharti		errx(1, "missing arguments for 'natm add'");
365118824Sharti
366118824Sharti	memset(&sdl, 0, sizeof(sdl));
367118824Sharti	sdl.sdl_len = sizeof(sdl);
368118824Sharti	sdl.sdl_family = AF_LINK;
369118824Sharti
370118824Sharti	/* get the IP address for <dest> */
371118824Sharti	memset(&sain, 0, sizeof(sain));
372118824Sharti	hp = gethostbyname(argv[0]);
373118824Sharti	if (hp == NULL)
374118824Sharti		errx(1, "bad hostname %s: %s", argv[0], hstrerror(h_errno));
375118824Sharti	if (hp->h_addrtype != AF_INET)
376118824Sharti		errx(1, "bad address type for %s", argv[0]);
377118824Sharti	sain.sin_len = sizeof(sain);
378118824Sharti	sain.sin_family = AF_INET;
379118824Sharti	memcpy(&sain.sin_addr, hp->h_addr, sizeof(sain.sin_addr));
380118824Sharti
381118824Sharti	/* find interface */
382118824Sharti	diagif_fetch();
383118824Sharti	TAILQ_FOREACH(aif, &diagif_list, link)
384118824Sharti		if (strcmp(aif->ifname, argv[1]) == 0)
385118824Sharti			break;
386118824Sharti	if (aif == NULL)
387118824Sharti		errx(1, "unknown ATM interface '%s'", argv[1]);
388118824Sharti	sdl.sdl_index = aif->index;
389118824Sharti	strcpy(sdl.sdl_data, aif->ifname);
390118824Sharti	idx = sdl.sdl_nlen = strlen(aif->ifname);
391118824Sharti	idx++;
392118824Sharti
393118824Sharti	/* verify VPI/VCI */
394118824Sharti	num = parse_num(argv[2], "VPI", (1U << aif->mib.vpi_bits));
395118824Sharti	sdl.sdl_data[idx++] = num & 0xff;
396118824Sharti	num = parse_num(argv[3], "VCI", (1U << aif->mib.vci_bits));
397118824Sharti	if (num == 0)
398118824Sharti		errx(1, "VCI may not be 0");
399118824Sharti	sdl.sdl_data[idx++] = (num >> 8) & 0xff;
400118824Sharti	sdl.sdl_data[idx++] = num & 0xff;
401118824Sharti
402118824Sharti	/* encapsulation */
403118824Sharti	if (strcasecmp(argv[4], "llc/snap") == 0) {
404118824Sharti		sdl.sdl_data[sdl.sdl_nlen] = ATM_PH_LLCSNAP;
405118824Sharti	} else if (strcasecmp(argv[4], "aal5") == 0) {
406118824Sharti		sdl.sdl_data[sdl.sdl_nlen] = 0;
407118824Sharti	} else
408118824Sharti		errx(1, "bad encapsulation type '%s'", argv[4]);
409118824Sharti
410118824Sharti	/* look at the traffic */
411118824Sharti	argc -= 5;
412118824Sharti	argv += 5;
413118824Sharti
414118824Sharti	if (argc != 0) {
415118824Sharti		if (strcasecmp(argv[0], "ubr") == 0) {
416118824Sharti			sdl.sdl_data[idx++] = ATMIO_TRAFFIC_UBR;
417118824Sharti			if (argc == 1)
418118824Sharti				/* ok */;
419118824Sharti			else if (argc == 2) {
420118824Sharti				num = parse_num(argv[1], "PCR", aif->mib.pcr);
421118824Sharti				sdl.sdl_data[idx++] = (num >> 16) & 0xff;
422118824Sharti				sdl.sdl_data[idx++] = (num >>  8) & 0xff;
423118824Sharti				sdl.sdl_data[idx++] = (num >>  0) & 0xff;
424118824Sharti			} else
425118824Sharti				errx(1, "too many parameters for UBR");
426118824Sharti
427118824Sharti		} else if (strcasecmp(argv[0], "cbr") == 0) {
428118824Sharti			sdl.sdl_data[idx++] = ATMIO_TRAFFIC_CBR;
429118824Sharti			if (argc == 1)
430118824Sharti				errx(1, "missing PCR for CBR");
431118824Sharti			if (argc > 2)
432118824Sharti				errx(1, "too many parameters for CBR");
433118824Sharti			num = parse_num(argv[1], "PCR", aif->mib.pcr);
434118824Sharti			sdl.sdl_data[idx++] = (num >> 16) & 0xff;
435118824Sharti			sdl.sdl_data[idx++] = (num >>  8) & 0xff;
436118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
437118824Sharti
438118824Sharti		} else if (strcasecmp(argv[0], "vbr") == 0) {
439118824Sharti			sdl.sdl_data[idx++] = ATMIO_TRAFFIC_VBR;
440118824Sharti
441118824Sharti			if (argc < 4)
442118824Sharti				errx(1, "missing arg(s) for VBR");
443118824Sharti			if (argc > 4)
444118824Sharti				errx(1, "too many parameters for VBR");
445118824Sharti
446118824Sharti			num = parse_num(argv[1], "PCR", aif->mib.pcr);
447118824Sharti			sdl.sdl_data[idx++] = (num >> 16) & 0xff;
448118824Sharti			sdl.sdl_data[idx++] = (num >>  8) & 0xff;
449118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
450118824Sharti			num = parse_num(argv[2], "SCR", num);
451118824Sharti			sdl.sdl_data[idx++] = (num >> 16) & 0xff;
452118824Sharti			sdl.sdl_data[idx++] = (num >>  8) & 0xff;
453118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
454118824Sharti			num = parse_num(argv[3], "MBS", 0xffffffLU);
455118824Sharti			sdl.sdl_data[idx++] = (num >> 16) & 0xff;
456118824Sharti			sdl.sdl_data[idx++] = (num >>  8) & 0xff;
457118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
458118824Sharti
459118824Sharti		} else if (strcasecmp(argv[0], "abr") == 0) {
460118824Sharti			sdl.sdl_data[idx++] = ATMIO_TRAFFIC_ABR;
461118824Sharti			if (argc < 11)
462118824Sharti				errx(1, "missing arg(s) for ABR");
463118824Sharti			if (argc > 11)
464118824Sharti				errx(1, "too many parameters for ABR");
465118824Sharti
466118824Sharti			num = parse_num(argv[1], "PCR", aif->mib.pcr);
467118824Sharti			sdl.sdl_data[idx++] = (num >> 16) & 0xff;
468118824Sharti			sdl.sdl_data[idx++] = (num >>  8) & 0xff;
469118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
470118824Sharti
471118824Sharti			num1 = parse_num(argv[2], "MCR", num);
472118824Sharti			sdl.sdl_data[idx++] = (num1 >> 16) & 0xff;
473118824Sharti			sdl.sdl_data[idx++] = (num1 >>  8) & 0xff;
474118824Sharti			sdl.sdl_data[idx++] = (num1 >>  0) & 0xff;
475118824Sharti
476118824Sharti			num = parse_num(argv[3], "ICR", num);
477118824Sharti			sdl.sdl_data[idx++] = (num >> 16) & 0xff;
478118824Sharti			sdl.sdl_data[idx++] = (num >>  8) & 0xff;
479118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
480118824Sharti
481118824Sharti			if (num < num1)
482118824Sharti				errx(1, "ICR must be >= MCR");
483118824Sharti
484118824Sharti			num = parse_num(argv[4], "TBE", 0xffffffUL);
485118824Sharti			sdl.sdl_data[idx++] = (num >> 16) & 0xff;
486118824Sharti			sdl.sdl_data[idx++] = (num >>  8) & 0xff;
487118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
488118824Sharti
489118824Sharti			num = parse_num(argv[5], "NRM", 0x7UL);
490118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
491118824Sharti
492118824Sharti			num = parse_num(argv[6], "TRM", 0x7UL);
493118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
494118824Sharti
495118824Sharti			num = parse_num(argv[7], "ADTF", 0x3ffUL);
496118824Sharti			sdl.sdl_data[idx++] = (num >>  8) & 0xff;
497118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
498118824Sharti
499118824Sharti			num = parse_num(argv[8], "RIF", 0xfUL);
500118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
501118824Sharti
502118824Sharti			num = parse_num(argv[9], "RDF", 0xfUL);
503118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
504118824Sharti
505118824Sharti			num = parse_num(argv[10], "CDF", 0x7UL);
506118824Sharti			sdl.sdl_data[idx++] = (num >>  0) & 0xff;
507118824Sharti
508118824Sharti		} else
509118824Sharti			errx(1, "bad traffic type '%s'", argv[0]);
510118824Sharti	} else
511118824Sharti		sdl.sdl_data[idx++] = ATMIO_TRAFFIC_UBR;
512118824Sharti
513118824Sharti	sdl.sdl_alen = idx - sdl.sdl_nlen;
514118824Sharti	sdl.sdl_len += sdl.sdl_nlen + sdl.sdl_alen;
515118824Sharti
516118824Sharti	if (printonly) {
517118824Sharti		printf("route add -iface %s -link %.*s",
518118824Sharti		    inet_ntoa(sain.sin_addr), sdl.sdl_nlen, sdl.sdl_data);
519118824Sharti		for (idx = 0; idx < sdl.sdl_alen; idx++)
520118824Sharti			printf("%c%x", ".:"[idx == 0],
521118824Sharti			    (u_int)sdl.sdl_data[sdl.sdl_nlen + idx] & 0xffU);
522118824Sharti		printf("\n");
523118824Sharti		exit(0);
524118824Sharti	}
525118824Sharti
526118824Sharti	do_route(RTM_ADD, RTF_HOST | RTF_STATIC | RTF_UP, &sain, &sdl);
527118824Sharti}
528118824Sharti
529118824Sharti/*
530118824Sharti * Delete an NATM route
531118824Sharti */
532118824Shartistatic void
533118824Shartinatm_delete(int argc, char *argv[])
534118824Sharti{
535118824Sharti	int opt;
536118824Sharti	struct hostent *hp;
537118824Sharti	struct sockaddr_in sain;
538118824Sharti	u_int vpi, vci;
539118824Sharti	struct diagif *aif;
540118824Sharti	struct natm_route *r;
541118824Sharti
542118824Sharti	static int printonly;
543118824Sharti
544118824Sharti	static const struct option opts[] = {
545118824Sharti	    { "printonly", OPT_SIMPLE, &printonly },
546118824Sharti	    { NULL, 0, NULL }
547118824Sharti	};
548118824Sharti
549118824Sharti	while ((opt = parse_options(&argc, &argv, opts)) != -1)
550118824Sharti		switch (opt) {
551118824Sharti		}
552118824Sharti
553118824Sharti	diagif_fetch();
554118824Sharti	natm_route_fetch();
555118824Sharti
556118824Sharti	memset(&sain, 0, sizeof(sain));
557118824Sharti	sain.sin_len = sizeof(sain);
558118824Sharti	sain.sin_family = AF_INET;
559118824Sharti
560118824Sharti	if (argc == 1) {
561118824Sharti		/* get the IP address for <dest> */
562118824Sharti		hp = gethostbyname(argv[0]);
563118824Sharti		if (hp == NULL)
564118824Sharti			errx(1, "bad hostname %s: %s", argv[0],
565118824Sharti			    hstrerror(h_errno));
566118824Sharti		if (hp->h_addrtype != AF_INET)
567118824Sharti			errx(1, "bad address type for %s", argv[0]);
568118824Sharti		memcpy(&sain.sin_addr, hp->h_addr, sizeof(sain.sin_addr));
569118824Sharti
570118824Sharti		TAILQ_FOREACH(r, &natm_route_list, link)
571118824Sharti			if (r->host.s_addr == sain.sin_addr.s_addr)
572118824Sharti				break;
573118824Sharti		if (r == NULL)
574118824Sharti			errx(1, "no NATM route to host '%s' (%s)", argv[0],
575118824Sharti			    inet_ntoa(sain.sin_addr));
576118824Sharti
577118824Sharti	} else if (argc == 3) {
578118824Sharti		TAILQ_FOREACH(aif, &diagif_list, link)
579118824Sharti			if (strcmp(aif->ifname, argv[0]) == 0)
580118824Sharti				break;
581118824Sharti		if (aif == 0)
582118824Sharti			errx(1, "no such interface '%s'", argv[0]);
583118824Sharti
584118824Sharti		vpi = parse_num(argv[1], "VPI", 0xff);
585118824Sharti		vci = parse_num(argv[2], "VCI", 0xffff);
586118824Sharti
587118824Sharti		TAILQ_FOREACH(r, &natm_route_list, link)
588118824Sharti			if (r->aif == aif && r->vpi == vpi && r->vci == vci)
589118824Sharti				break;
590118824Sharti		if (r == NULL)
591118824Sharti			errx(1, "no such NATM route %s %u %u", argv[0],
592118824Sharti			    vpi, vci);
593118824Sharti		sain.sin_addr = r->host;
594118824Sharti
595118824Sharti	} else
596118824Sharti		errx(1, "bad number of arguments for 'natm delete'");
597118824Sharti
598118824Sharti	if (printonly) {
599118824Sharti		printf("route delete %s\n", inet_ntoa(r->host));
600118824Sharti		exit(0);
601118824Sharti	}
602118824Sharti
603118824Sharti	do_route(RTM_DELETE, r->flags, &sain, NULL);
604118824Sharti}
605118824Sharti
606118824Sharti/*
607118824Sharti * Show NATM routes
608118824Sharti */
609118824Shartistatic void
610118824Shartinatm_show(int argc, char *argv[])
611118824Sharti{
612118824Sharti	int opt;
613118824Sharti	struct natm_route *r;
614118824Sharti	struct hostent *hp;
615118824Sharti
616118824Sharti	static const char *const traffics[] = {
617118824Sharti		[ATMIO_TRAFFIC_UBR] = "UBR",
618118824Sharti		[ATMIO_TRAFFIC_CBR] = "CBR",
619118824Sharti		[ATMIO_TRAFFIC_VBR] = "VBR",
620118824Sharti		[ATMIO_TRAFFIC_ABR] = "ABR"
621118824Sharti	};
622118824Sharti
623118824Sharti	static int numeric, abr;
624118824Sharti
625118824Sharti	static const struct option opts[] = {
626118824Sharti	    { "abr", OPT_SIMPLE, &abr },
627118824Sharti	    { "numeric", OPT_SIMPLE, &numeric },
628118824Sharti	    { NULL, 0, NULL }
629118824Sharti	};
630118824Sharti
631118824Sharti	static const char head[] =
632118824Sharti	    "Destination         Iface       VPI VCI   Encaps   Trf PCR     "
633118824Sharti	    "SCR/MCR MBS/ICR\n";
634118824Sharti	static const char head_abr[] =
635118824Sharti	    "Destination         Iface       VPI VCI   Encaps   Trf PCR     "
636118824Sharti	    "SCR/MCR MBS/ICR TBE     NRM TRM ADTF RIF RDF CDF\n";
637118824Sharti
638118824Sharti	while ((opt = parse_options(&argc, &argv, opts)) != -1)
639118824Sharti		switch (opt) {
640118824Sharti		}
641118824Sharti
642118824Sharti	diagif_fetch();
643118824Sharti	natm_route_fetch();
644118824Sharti
645118824Sharti	heading_init();
646118824Sharti	TAILQ_FOREACH(r, &natm_route_list, link) {
647118824Sharti		heading(abr ? head_abr : head);
648118824Sharti		if (numeric)
649118824Sharti			printf("%-20s", inet_ntoa(r->host));
650118824Sharti		else if (r->host.s_addr == INADDR_ANY)
651118824Sharti			printf("%-20s", "default");
652118824Sharti		else {
653118824Sharti			hp = gethostbyaddr((char *)&r->host, sizeof(r->host),
654118824Sharti			    AF_INET);
655118824Sharti			if (hp != NULL)
656118824Sharti				printf("%-20s", hp->h_name);
657118824Sharti			else
658118824Sharti				printf("%-20s", inet_ntoa(r->host));
659118824Sharti		}
660118824Sharti		printf("%-12s%-4u%-6u%-9s%-4s", r->aif->ifname, r->vpi, r->vci,
661118824Sharti		    r->llcsnap ? "LLC/SNAP" : "AAL5", traffics[r->traffic]);
662118824Sharti		switch (r->traffic) {
663118824Sharti
664118824Sharti		  case ATMIO_TRAFFIC_UBR:
665118824Sharti		  case ATMIO_TRAFFIC_CBR:
666118824Sharti			printf("%-8u", r->pcr);
667118824Sharti			break;
668118824Sharti
669118824Sharti		  case ATMIO_TRAFFIC_VBR:
670118824Sharti			printf("%-8u%-8u%-8u", r->pcr, r->scr, r->mbs);
671118824Sharti			break;
672118824Sharti
673118824Sharti		  case ATMIO_TRAFFIC_ABR:
674118824Sharti			printf("%-8u%-8u%-8u", r->pcr, r->mcr, r->icr);
675118824Sharti			if (abr)
676118824Sharti				printf("%-8u%-4u%-4u%-5u%-4u%-4u%-4u",
677118824Sharti				    r->tbe, r->nrm, r->trm, r->adtf,
678118824Sharti				    r->rif, r->rdf, r->cdf);
679118824Sharti			break;
680118824Sharti		}
681118824Sharti		printf("\n");
682118824Sharti	}
683118824Sharti}
684