File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libpdel / net / uroute.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:25:53 2012 UTC (13 years, 4 months ago) by misho
Branches: libpdel, MAIN
CVS tags: v0_5_3, HEAD
libpdel

    1: 
    2: /*
    3:  * Copyright (c) 2001-2002 Packet Design, LLC.
    4:  * All rights reserved.
    5:  * 
    6:  * Subject to the following obligations and disclaimer of warranty,
    7:  * use and redistribution of this software, in source or object code
    8:  * forms, with or without modifications are expressly permitted by
    9:  * Packet Design; provided, however, that:
   10:  * 
   11:  *    (i)  Any and all reproductions of the source or object code
   12:  *         must include the copyright notice above and the following
   13:  *         disclaimer of warranties; and
   14:  *    (ii) No rights are granted, in any manner or form, to use
   15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
   16:  *         on advertising, endorsements, or otherwise except as such
   17:  *         appears in the above copyright notice or in the software.
   18:  * 
   19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
   20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
   21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
   22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
   23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
   24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
   25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
   26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
   27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
   28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
   29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
   30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
   31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
   32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
   33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
   35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
   36:  * THE POSSIBILITY OF SUCH DAMAGE.
   37:  *
   38:  * Author: Archie Cobbs <archie@freebsd.org>
   39:  */
   40: 
   41: #include <sys/types.h>
   42: #include <sys/param.h>
   43: #include <sys/socket.h>
   44: #include <sys/sysctl.h>
   45: #include <sys/sockio.h>
   46: #include <sys/ioctl.h>
   47: 
   48: #include <net/if.h>
   49: #include <net/if_dl.h>
   50: #include <net/if_types.h>
   51: #include <net/route.h>
   52: 
   53: #include <netinet/in.h>
   54: #include <netinet/if_ether.h>
   55: #include <arpa/inet.h>
   56: 
   57: #include <stdio.h>
   58: #include <stdlib.h>
   59: #include <stdarg.h>
   60: #include <unistd.h>
   61: #include <assert.h>
   62: #include <string.h>
   63: #include <errno.h>
   64: #include <err.h>
   65: 
   66: #include "structs/structs.h"
   67: #include "structs/type/array.h"
   68: 
   69: #include "net/route_msg.h"
   70: #include "net/uroute.h"
   71: #include "util/typed_mem.h"
   72: 
   73: #define ROUNDUP(a) \
   74: 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
   75: #define ADVANCE(x, n)	((x) += ROUNDUP((n)->sa_len))
   76: 
   77: #ifdef RTF_CLONING
   78: #define WRITABLE_FLAGS	(RTF_STATIC | RTF_LLINFO | RTF_REJECT | RTF_BLACKHOLE \
   79: 			    | RTF_PROTO1 | RTF_PROTO2 | RTF_CLONING \
   80: 			    | RTF_XRESOLVE | RTF_UP | RTF_GATEWAY)
   81: #else
   82: #define WRITABLE_FLAGS	(RTF_STATIC | RTF_REJECT | RTF_BLACKHOLE \
   83: 			    | RTF_PROTO1 | RTF_PROTO2 \
   84: 			    | RTF_XRESOLVE | RTF_UP | RTF_GATEWAY)
   85: #endif
   86: 
   87: struct route_flag {
   88: 	const char	*name;
   89: 	int		bit;
   90: };
   91: 
   92: static const	struct route_flag route_flags[] = {
   93: #define FLAG(x)	{ #x, RTF_ ## x }
   94: 	FLAG(UP),
   95: 	FLAG(GATEWAY),
   96: 	FLAG(HOST),
   97: 	FLAG(REJECT),
   98: 	FLAG(DYNAMIC),
   99: 	FLAG(MODIFIED),
  100: 	FLAG(DONE),
  101: #ifdef RTF_CLONING
  102: 	FLAG(CLONING),
  103: #endif
  104: 	FLAG(XRESOLVE),
  105: #ifdef RTF_LLINFO
  106: 	FLAG(LLINFO),
  107: #endif
  108: 	FLAG(STATIC),
  109: 	FLAG(BLACKHOLE),
  110: 	FLAG(PROTO2),
  111: 	FLAG(PROTO1),
  112: 	FLAG(PRCLONING),
  113: #ifdef RTF_WASCLONED
  114: 	FLAG(WASCLONED),
  115: #endif
  116: 	FLAG(PROTO3),
  117: 	FLAG(PINNED),
  118: 	FLAG(LOCAL),
  119: 	FLAG(BROADCAST),
  120: 	FLAG(MULTICAST),
  121: #undef FLAG
  122: 	{ NULL, 0 }
  123: };
  124: 
  125: /* Route structure */
  126: struct uroute {
  127: 	int flags;
  128: 	struct sockaddr	*dest;
  129: 	struct sockaddr	*gateway;
  130: 	struct sockaddr	*netmask;
  131: };
  132: 
  133: /*
  134:  * Internal functions
  135:  */
  136: static int	uroute_do_route(struct uroute *route, int sock, int type);
  137: static const	char *uroute_sockaddr_string(const struct sockaddr *sa);
  138: 
  139: /*
  140:  * Create a new route.
  141:  */
  142: struct uroute *
  143: uroute_create(const struct sockaddr *dest, const struct sockaddr *gateway,
  144: 	const struct sockaddr *netmask)
  145: {
  146: 	struct uroute *route;
  147: 
  148: 	if (dest == NULL || gateway == NULL) {
  149: 		errno = EINVAL;
  150: 		return (NULL);
  151: 	}
  152: 	if ((route = MALLOC("uroute", sizeof(*route))) == NULL)
  153: 		return (NULL);
  154: 	memset(route, 0, sizeof(*route));
  155: 	if ((route->dest = MALLOC("uroute.dest", dest->sa_len)) == NULL)
  156: 		goto fail;
  157: 	memcpy(route->dest, dest, dest->sa_len);
  158: 	if ((route->gateway = MALLOC("uroute.gateway",
  159: 	    gateway->sa_len)) == NULL)
  160: 		goto fail;
  161: 	memcpy(route->gateway, gateway, gateway->sa_len);
  162: 	if (netmask != NULL) {
  163: 		if ((route->netmask = MALLOC("uroute.netmask",
  164: 		    netmask->sa_len)) == NULL)
  165: 			goto fail;
  166: 		memcpy(route->netmask, netmask, netmask->sa_len);
  167: 	}
  168: 	route->flags = RTF_STATIC;
  169: 	return (route);
  170: 
  171: fail:
  172: 	/* Clean up */
  173: 	uroute_destroy(&route);
  174: 	return (NULL);
  175: }
  176: 
  177: /*
  178:  * Free a route.
  179:  */
  180: void
  181: uroute_destroy(struct uroute **routep)
  182: {
  183: 	struct uroute *const route = *routep;
  184: 
  185: 	if (route == NULL)
  186: 		return;
  187: 	FREE("uroute.dest", route->dest);
  188: 	FREE("uroute.gateway", route->gateway);
  189: 	FREE("uroute.netmask", route->netmask);
  190: 	FREE("uroute", route);
  191: 	*routep = NULL;
  192: }
  193: 
  194: /*
  195:  * Get the destination address.
  196:  */
  197: const struct sockaddr *
  198: uroute_get_dest(struct uroute *route)
  199: {
  200: 	return (route->dest);
  201: }
  202: 
  203: /*
  204:  * Get the gateway address.
  205:  */
  206: const struct sockaddr *
  207: uroute_get_gateway(struct uroute *route)
  208: {
  209: 	return (route->gateway);
  210: }
  211: 
  212: /*
  213:  * Get the netmask.
  214:  *
  215:  * Returns NULL for a host route.
  216:  */
  217: const struct sockaddr *
  218: uroute_get_netmask(struct uroute *route)
  219: {
  220: 	return (route->netmask);
  221: }
  222: 
  223: /*
  224:  * Get the flags.
  225:  */
  226: int
  227: uroute_get_flags(struct uroute *route)
  228: {
  229: 	return (route->flags);
  230: }
  231: 
  232: /*
  233:  * Set the flags.
  234:  */
  235: void
  236: uroute_set_flags(struct uroute *route, int flags)
  237: {
  238: 	route->flags = flags;
  239: }
  240: 
  241: /*
  242:  * Add route to the kernel routing table.
  243:  */
  244: int
  245: uroute_add(struct uroute *route)
  246: {
  247: 	return (uroute_do_route(route, -1, RTM_ADD));
  248: }
  249: 
  250: /*
  251:  * Delete a route.
  252:  */
  253: int
  254: uroute_delete(struct uroute *route)
  255: {
  256: 	return (uroute_do_route(route, -1, RTM_DELETE));
  257: }
  258: 
  259: /*
  260:  * Get the installed kernel route that matches the destination "dest".
  261:  */
  262: struct uroute *
  263: uroute_get(const struct sockaddr *dest)
  264: {
  265: 	struct uroute *route = NULL;
  266: 	struct route_msg *msg = NULL;
  267: 	struct route_msg **list = NULL;
  268: 	struct sockaddr_dl sdl;
  269: 	int errno_save;
  270: 	int sock = -1;
  271: 	int num = 0;
  272: 	int seq;
  273: 	int i;
  274: 
  275: 	/* Build new route message */
  276: 	if ((msg = route_msg_create()) == NULL)
  277: 		goto fail;
  278: 	seq = route_msg_get_seq(msg);
  279: 	route_msg_set_type(msg, RTM_GET);
  280: 	if (route_msg_set_dest(msg, dest) == -1)
  281: 		goto fail;
  282: 	memset(&sdl, 0, sizeof(sdl));
  283: 	sdl.sdl_type = IFT_OTHER;
  284: 	sdl.sdl_len = 8;
  285: 	sdl.sdl_family = AF_LINK;
  286: 	if (route_msg_set_ifp(msg, (struct sockaddr *)&sdl) == -1)
  287: 		goto fail;
  288: 	route_msg_set_flags(msg, RTF_UP|RTF_GATEWAY|RTF_HOST|RTF_STATIC);
  289: 
  290: 	/* Send request */
  291: 	if ((sock = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
  292: 		goto fail;
  293: 	if (route_msg_send(msg, sock) == -1)
  294: 		goto fail;
  295: 	route_msg_destroy(&msg);
  296: 	msg = NULL;
  297: 
  298: 	/* Get response */
  299: 	while (1) {
  300: 
  301: 		/* Decode it */
  302: 		if ((num = route_msg_recv(&list, sock, TYPED_MEM_TEMP)) == -1)
  303: 			goto fail;
  304: 
  305: 		/* Check returned messages for a match */
  306: 		for (i = 0; i < num; i++) {
  307: 			struct route_msg *const msg = list[i];
  308: 
  309: 			if (route_msg_get_pid(msg) == getpid()
  310: 			    && route_msg_get_seq(msg) == seq) {
  311: 				if ((route = uroute_create(route_msg_get_dest(
  312: 				    msg), route_msg_get_gateway(msg),
  313: 				    route_msg_get_netmask(msg))) == NULL)
  314: 					goto fail;
  315: 				break;
  316: 			}
  317: 		}
  318: 		if (route != NULL)
  319: 			break;
  320: 
  321: 		/* Free list and try again */
  322: 		for (i = 0; i < num; i++)
  323: 			route_msg_destroy(&list[i]);
  324: 		FREE(TYPED_MEM_TEMP, list);
  325: 		list = NULL;
  326: 	}
  327: 
  328: fail:
  329: 	/* Clean up and exit */
  330: 	errno_save = errno;
  331: 	if (sock != -1)
  332: 		(void)close(sock);
  333: 	if (msg != NULL)
  334: 		route_msg_destroy(&msg);
  335: 	if (list != NULL) {
  336: 		for (i = 0; i < num; i++)
  337: 			route_msg_destroy(&list[i]);
  338: 		FREE(TYPED_MEM_TEMP, list);
  339: 	}
  340: 	errno = errno_save;
  341: 	return (route);
  342: }
  343: 
  344: /*
  345:  * Build and send a route message by type.
  346:  */
  347: static int
  348: uroute_do_route(struct uroute *route, int sock, int type)
  349: {
  350: 	struct route_msg *msg;
  351: 	int close_sock = 0;
  352: 	int r = -1;
  353: 	int flags;
  354: 
  355: 	/* Create new route message */
  356: 	if ((msg = route_msg_create()) == NULL)
  357: 		return (-1);
  358: 
  359: 	/* Open socket if requested */
  360: 	if (sock == -1) {
  361: 		if ((sock = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
  362: 			goto fail;
  363: 		close_sock = 1;
  364: 	}
  365: 
  366: 	/* Build message */
  367: 	route_msg_set_type(msg, type);
  368: 	flags = route->flags & WRITABLE_FLAGS;
  369: 	flags |= RTF_UP;
  370: 	if (route->gateway->sa_family != AF_LINK)
  371: 		flags |= RTF_GATEWAY;
  372: 	if (route->netmask == NULL)
  373: 		flags |= RTF_HOST;
  374: 	else
  375: 		flags &= ~RTF_HOST;
  376: 	route_msg_set_flags(msg, flags);
  377: 	if (route_msg_set_dest(msg, route->dest) == -1)
  378: 		goto fail;
  379: 	if (route_msg_set_gateway(msg, route->gateway) == -1)
  380: 		goto fail;
  381: 	if (route_msg_set_netmask(msg, route->netmask) == -1)
  382: 		goto fail;
  383: 
  384: 	/* Send messsage */
  385: 	r = route_msg_send(msg, sock);
  386: 
  387: fail:
  388: 	/* Clean up */
  389: 	route_msg_destroy(&msg);
  390: 	if (close_sock)
  391: 		(void)close(sock);
  392: 
  393: 	/* Done */
  394: 	return (r);
  395: }
  396: 
  397: /*
  398:  * Get the entire routing table.
  399:  */
  400: int
  401: uroute_get_all(struct uroute ***listp, const char *mtype)
  402: {
  403: 	static int oid[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 };
  404: 	static const int noid = sizeof(oid) / sizeof(*oid);
  405: 	struct route_msg **list = NULL;
  406: 	struct uroute **routes = NULL;
  407: 	u_char *buf = NULL;
  408: 	size_t actual;
  409: 	size_t needed;
  410: 	int num = 0;
  411: 	int i;
  412: 
  413: 	/* Get size estimate */
  414: 	if (sysctl(oid, noid, NULL, &needed, NULL, 0) < 0)
  415: 		goto fail;
  416: 
  417: 	/* Allocate buffer for returned value */
  418: 	if ((buf = MALLOC(TYPED_MEM_TEMP, needed)) == NULL)
  419: 		goto fail;
  420: 
  421: 	/* Get actual data */
  422: 	actual = needed;
  423: 	if (sysctl(oid, noid, buf, &actual, NULL, 0) < 0)
  424: 		goto fail;
  425: 
  426: 	/* Decode route messages */
  427: 	if ((num = route_msg_decode(buf, actual, &list, TYPED_MEM_TEMP)) == -1)
  428: 		goto fail;
  429: 
  430: 	/* Create routes array from route message array */
  431: 	if ((routes = MALLOC(mtype, num * sizeof(*routes))) == NULL)
  432: 		goto fail;
  433: 	memset(routes, 0, num * sizeof(*routes));
  434: 	for (i = 0; i < num; i++) {
  435: 		struct route_msg *const msg = list[i];
  436: 
  437: 		if ((routes[i] = uroute_create(route_msg_get_dest(msg),
  438: 		    route_msg_get_gateway(msg),
  439: 		    route_msg_get_netmask(msg))) == NULL) {
  440: 			while (i > 0)
  441: 				uroute_destroy(&routes[--i]);
  442: 			FREE(mtype, routes);
  443: 			routes = NULL;
  444: 			goto fail;
  445: 		}
  446: 		routes[i]->flags = route_msg_get_flags(msg);
  447: 	}
  448: 
  449: fail:
  450: 	/* Clean up and exit */
  451: 	if (buf != NULL)
  452: 		FREE(TYPED_MEM_TEMP, buf);
  453: 	if (list != NULL) {
  454: 		for (i = 0; i < num; i++)
  455: 			route_msg_destroy(&list[i]);
  456: 		FREE(TYPED_MEM_TEMP, list);
  457: 	}
  458: 	if (routes != NULL) {
  459: 		*listp = routes;
  460: 		return (num);
  461: 	}
  462: 	return (-1);
  463: }
  464: 
  465: /*
  466:  * Print a route.
  467:  */
  468: void
  469: uroute_print(struct uroute *route, FILE *fp)
  470: {
  471: 	int didflag;
  472: 	int i;
  473: 
  474: 	fprintf(fp, "dest %s gateway %s",
  475: 	    uroute_sockaddr_string(route->dest),
  476: 	    uroute_sockaddr_string(route->gateway));
  477: 	if (route->netmask != NULL) {
  478: 		fprintf(fp, " netmask %s",
  479: 		    uroute_sockaddr_string(route->netmask));
  480: 	}
  481: 	fprintf(fp, " flags=<");
  482: 	for (i = didflag = 0; route_flags[i].name != NULL; i++) {
  483: 		if ((route->flags & route_flags[i].bit) != 0) {
  484: 			if (didflag)
  485: 				fprintf(fp, ",");
  486: 			didflag = 1;
  487: 			fprintf(fp, "%s", route_flags[i].name);
  488: 		}
  489: 	}
  490: 	fprintf(fp, ">");
  491: }
  492: 
  493: static const char *
  494: uroute_sockaddr_string(const struct sockaddr *sa)
  495: {
  496: 	static char buf[2][256];
  497: 	static int n;
  498: 	int i;
  499: 
  500: 	n ^= 1;
  501: 	switch (sa->sa_family) {
  502: 	case AF_INET:
  503: 		strlcpy(buf[n], inet_ntoa(((struct sockaddr_in *)(void *)
  504: 		    sa)->sin_addr), sizeof(buf[n]));
  505: 		break;
  506: 	case AF_LINK:
  507: 		/* XXX implement me */
  508: 	default:
  509: 		snprintf(buf[n], sizeof(buf[n]), "{ len=%d af=%d data=[",
  510: 		    sa->sa_len, sa->sa_family);
  511: 		for (i = 2; i < sa->sa_len; i++) {
  512: 			snprintf(buf[n] + strlen(buf[n]),
  513: 			    sizeof(buf[n]) - strlen(buf[n]),
  514: 			    " %02X", ((u_char *)sa)[i]);
  515: 		}
  516: 		strlcat(buf[n], " ] }", sizeof(buf[n]));
  517: 	}
  518: 	return (buf[n]);
  519: }
  520: 
  521: 
  522: #ifdef UROUTE_TEST
  523: 
  524: int
  525: main(int ac, char **av)
  526: {
  527: 	struct sockaddr_in dest;
  528: 	struct sockaddr_in gateway;
  529: 	struct sockaddr_in netmask;
  530: 	struct uroute *route = NULL;
  531: 	int do_netmask = 0;
  532: 	int fail = 0;
  533: 	int cmd = 0;
  534: 
  535: 	memset(&dest, 0, sizeof(dest));
  536: 	dest.sin_family = AF_INET;
  537: 	dest.sin_len = sizeof(dest);
  538: 	memset(&gateway, 0, sizeof(gateway));
  539: 	gateway.sin_family = AF_INET;
  540: 	gateway.sin_len = sizeof(gateway);
  541: 	memset(&netmask, 0, sizeof(netmask));
  542: 	netmask.sin_family = AF_INET;
  543: 	netmask.sin_len = sizeof(netmask);
  544: 
  545: 	av++;
  546: 	ac--;
  547: 	switch (ac) {
  548: 	case 4:
  549: 		if (inet_aton(av[3], &netmask.sin_addr))
  550: 			;
  551: 		else {
  552: 			u_long haddr;
  553: 
  554: 			if (sscanf(av[3], "%lu", &haddr) != 1)
  555: 				err(1, "invalid netmask \"%s\"", av[3]);
  556: 			netmask.sin_addr.s_addr = htonl(haddr);
  557: 		}
  558: 		do_netmask = 1;
  559: 		// fall through
  560: 	case 3:
  561: 		if (!inet_aton(av[2], &gateway.sin_addr))
  562: 			err(1, "invalid IP address \"%s\"", av[2]);
  563: 		if (!strcmp(av[0], "add"))
  564: 			cmd = 1;
  565: 		else if (!strcmp(av[0], "delete"))
  566: 			cmd = 2;
  567: 		else {
  568: 			fail = 1;
  569: 			break;
  570: 		}
  571: 		if (!inet_aton(av[1], &dest.sin_addr))
  572: 			err(1, "invalid IP address \"%s\"", av[1]);
  573: 		if ((route = uroute_create((struct sockaddr *)&dest,
  574: 		    (struct sockaddr *)&gateway,
  575: 		    do_netmask ? (struct sockaddr *)&netmask : NULL)) == NULL)
  576: 			err(1, "uroute_create");
  577: 		break;
  578: 	case 2:
  579: 		if (strcmp(av[0], "get") != 0) {
  580: 			fail = 1;
  581: 			break;
  582: 		}
  583: 		if (!inet_aton(av[1], &dest.sin_addr))
  584: 			err(1, "invalid IP address \"%s\"", av[1]);
  585: 		break;
  586: 	case 1:
  587: 		if (strcmp(av[0], "list") != 0) {
  588: 			fail = 1;
  589: 			break;
  590: 		}
  591: 		// fall through
  592: 	case 0:
  593: 		cmd = 3;
  594: 		break;
  595: 	default:
  596: 		fail = 1;
  597: 		break;
  598: 	}
  599: 	if (fail) {
  600: 		fprintf(stderr, "Usage: uroute <add | delete | get | list>"
  601: 		    " [dest [ gateway [netmask] ]]\n");
  602: 		exit(1);
  603: 	}
  604: 
  605: 	switch (cmd) {
  606: 	case 0:				// get
  607: 		if ((route = uroute_get((struct sockaddr *)&dest)) == NULL)
  608: 			err(1, "uroute_get");
  609: 		uroute_print(route, stdout);
  610: 		printf("\n");
  611: 		uroute_destroy(&route);
  612: 		break;
  613: 	case 1:				// add
  614: 		if (uroute_add(route) == -1)
  615: 			err(1, "uroute_add");
  616: 		uroute_destroy(&route);
  617: 		break;
  618: 	case 2:				// delete
  619: 		if (uroute_delete(route) == -1)
  620: 			err(1, "uroute_delete");
  621: 		uroute_destroy(&route);
  622: 		break;
  623: 	case 3:				// list
  624: 	    {
  625: 		struct uroute **list;
  626: 		int num;
  627: 		int i;
  628: 
  629: 		if ((num = uroute_get_all(&list, "main")) == -1)
  630: 			err(1, "uroute_get_all");
  631: 		for (i = 0; i < num; i++) {
  632: 			uroute_print(list[i], stdout);
  633: 			printf("\n");
  634: 		}
  635: 		for (i = 0; i < num; i++)
  636: 			uroute_destroy(&list[i]);
  637: 		FREE("main", list);
  638: 		break;
  639: 	    }
  640: 	default:
  641: 		assert(0);
  642: 	}
  643: 
  644: 	/* Done */
  645: 	typed_mem_dump(stdout);
  646: 	return (0);
  647: }
  648: #endif
  649: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>