xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sadm/dhcpmgr/lib/dd_opt.c (revision 11262:b7ebfbf2359e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55852Ssm26363  * Common Development and Distribution License (the "License").
65852Ssm26363  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11262SRajagopal.Andra@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <netinet/in.h>
280Sstevel@tonic-gate #include <arpa/nameser.h>
290Sstevel@tonic-gate #include <resolv.h>
300Sstevel@tonic-gate #include <string.h>
310Sstevel@tonic-gate #include <malloc.h>
320Sstevel@tonic-gate #include <libintl.h>
330Sstevel@tonic-gate #include <stdio.h>
340Sstevel@tonic-gate #include <netinet/dhcp.h>
350Sstevel@tonic-gate #include <rpcsvc/nis.h>
360Sstevel@tonic-gate #include <netdb.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate #include <sys/sockio.h>
390Sstevel@tonic-gate #include <dirent.h>
400Sstevel@tonic-gate #include <procfs.h>
410Sstevel@tonic-gate #include <netdir.h>
420Sstevel@tonic-gate #include <arpa/inet.h>
430Sstevel@tonic-gate #include <rpcsvc/ypclnt.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include "dd_misc.h"
460Sstevel@tonic-gate #include "dd_opt.h"
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	RDISC_FNAME	"in.rdisc"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static struct dhcp_option opt_nomem = { ENOMEM, NULL };
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate  * Free an allocated dhcp option structure.
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate void
dd_freeopt(struct dhcp_option * opt)560Sstevel@tonic-gate dd_freeopt(struct dhcp_option *opt)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate 	int i;
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 	if (opt->error_code == 0) {
610Sstevel@tonic-gate 		switch (opt->u.ret.datatype) {
620Sstevel@tonic-gate 		case ASCII_OPTION:
630Sstevel@tonic-gate 			for (i = 0; i < opt->u.ret.count; ++i) {
640Sstevel@tonic-gate 				free(opt->u.ret.data.strings[i]);
650Sstevel@tonic-gate 			}
660Sstevel@tonic-gate 			free(opt->u.ret.data.strings);
670Sstevel@tonic-gate 			break;
680Sstevel@tonic-gate 		case BOOLEAN_OPTION:
690Sstevel@tonic-gate 			break;
700Sstevel@tonic-gate 		case IP_OPTION:
710Sstevel@tonic-gate 			for (i = 0; i < opt->u.ret.count; ++i) {
720Sstevel@tonic-gate 				free(opt->u.ret.data.addrs[i]);
730Sstevel@tonic-gate 			}
740Sstevel@tonic-gate 			free(opt->u.ret.data.addrs);
750Sstevel@tonic-gate 			break;
760Sstevel@tonic-gate 		case NUMBER_OPTION:
770Sstevel@tonic-gate 			free(opt->u.ret.data.numbers);
780Sstevel@tonic-gate 			break;
790Sstevel@tonic-gate 		case OCTET_OPTION:
800Sstevel@tonic-gate 			for (i = 0; i < opt->u.ret.count; ++i) {
810Sstevel@tonic-gate 				free(opt->u.ret.data.octets[i]);
820Sstevel@tonic-gate 			}
830Sstevel@tonic-gate 			free(opt->u.ret.data.octets);
840Sstevel@tonic-gate 			break;
850Sstevel@tonic-gate 		default:
860Sstevel@tonic-gate 			return;
870Sstevel@tonic-gate 		}
880Sstevel@tonic-gate 	}
890Sstevel@tonic-gate 	/* Don't free the static no-memory error return */
900Sstevel@tonic-gate 	if (opt != &opt_nomem) {
910Sstevel@tonic-gate 		free(opt);
920Sstevel@tonic-gate 	}
930Sstevel@tonic-gate }
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate  * Allocate an option structure.
970Sstevel@tonic-gate  */
980Sstevel@tonic-gate 
990Sstevel@tonic-gate static struct dhcp_option *
newopt(enum option_type ot,ushort_t count)1000Sstevel@tonic-gate newopt(enum option_type ot, ushort_t count)
1010Sstevel@tonic-gate {
1020Sstevel@tonic-gate 	struct dhcp_option *opt;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	opt = malloc(sizeof (struct dhcp_option));
1050Sstevel@tonic-gate 	if ((opt != NULL) && (ot != ERROR_OPTION)) {
1060Sstevel@tonic-gate 		opt->error_code = 0;
1070Sstevel@tonic-gate 		opt->u.ret.datatype = ot;
1080Sstevel@tonic-gate 		switch (ot) {
1090Sstevel@tonic-gate 		case ASCII_OPTION:
1100Sstevel@tonic-gate 			opt->u.ret.data.strings =
1110Sstevel@tonic-gate 			    calloc(count, sizeof (char *));
1120Sstevel@tonic-gate 			if (opt->u.ret.data.strings == NULL) {
1130Sstevel@tonic-gate 				free(opt);
1140Sstevel@tonic-gate 				opt = NULL;
1150Sstevel@tonic-gate 			} else {
1160Sstevel@tonic-gate 				opt->u.ret.count = count;
1170Sstevel@tonic-gate 			}
1180Sstevel@tonic-gate 			break;
1190Sstevel@tonic-gate 		case BOOLEAN_OPTION:
1200Sstevel@tonic-gate 			opt->u.ret.count = count;
1210Sstevel@tonic-gate 			break;
1220Sstevel@tonic-gate 		case IP_OPTION:
1230Sstevel@tonic-gate 			opt->u.ret.data.addrs = calloc(count,
1240Sstevel@tonic-gate 			    sizeof (struct in_addr *));
1250Sstevel@tonic-gate 			if (opt->u.ret.data.addrs == NULL) {
1260Sstevel@tonic-gate 				free(opt);
1270Sstevel@tonic-gate 				opt = NULL;
1280Sstevel@tonic-gate 			} else {
1290Sstevel@tonic-gate 				opt->u.ret.count = count;
1300Sstevel@tonic-gate 			}
1310Sstevel@tonic-gate 			break;
1320Sstevel@tonic-gate 		case NUMBER_OPTION:
1330Sstevel@tonic-gate 			opt->u.ret.data.numbers = calloc(count,
1340Sstevel@tonic-gate 			    sizeof (int64_t));
1350Sstevel@tonic-gate 			if (opt->u.ret.data.numbers == NULL) {
1360Sstevel@tonic-gate 				free(opt);
1370Sstevel@tonic-gate 				opt = NULL;
1380Sstevel@tonic-gate 			} else {
1390Sstevel@tonic-gate 				opt->u.ret.count = count;
1400Sstevel@tonic-gate 			}
1410Sstevel@tonic-gate 			break;
1420Sstevel@tonic-gate 		case OCTET_OPTION:
1430Sstevel@tonic-gate 			opt->u.ret.data.octets = calloc(count,
1440Sstevel@tonic-gate 			    sizeof (uchar_t *));
1450Sstevel@tonic-gate 			if (opt->u.ret.data.octets == NULL) {
1460Sstevel@tonic-gate 				free(opt);
1470Sstevel@tonic-gate 				opt = NULL;
1480Sstevel@tonic-gate 			} else {
1490Sstevel@tonic-gate 				opt->u.ret.count = count;
1500Sstevel@tonic-gate 			}
1510Sstevel@tonic-gate 			break;
1520Sstevel@tonic-gate 		default:
1530Sstevel@tonic-gate 			free(opt);
1540Sstevel@tonic-gate 			opt = NULL;
1550Sstevel@tonic-gate 		}
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 	return (opt);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate /*
1610Sstevel@tonic-gate  * Return an out of memory error
1620Sstevel@tonic-gate  */
1630Sstevel@tonic-gate static struct dhcp_option *
malloc_failure()1640Sstevel@tonic-gate malloc_failure()
1650Sstevel@tonic-gate {
1660Sstevel@tonic-gate 	if (opt_nomem.u.msg == NULL) {
1670Sstevel@tonic-gate 		opt_nomem.u.msg = strerror(opt_nomem.error_code);
1680Sstevel@tonic-gate 	}
1690Sstevel@tonic-gate 	return (&opt_nomem);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate  * Return an error based on errno value
1740Sstevel@tonic-gate  */
1750Sstevel@tonic-gate static struct dhcp_option *
errno_opt()1760Sstevel@tonic-gate errno_opt() {
1770Sstevel@tonic-gate 	struct dhcp_option *opt;
1780Sstevel@tonic-gate 	int serrno;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	/* Save errno value before allocation attempt */
1810Sstevel@tonic-gate 	serrno = errno;
1820Sstevel@tonic-gate 	opt = newopt(ERROR_OPTION, 0);
1830Sstevel@tonic-gate 	if (opt == NULL) {
1840Sstevel@tonic-gate 		return (malloc_failure());
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate 	opt->error_code = serrno;
1870Sstevel@tonic-gate 	opt->u.msg = strerror(serrno);
1880Sstevel@tonic-gate 	return (opt);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate  * Construct list of default routers.
1920Sstevel@tonic-gate  */
1930Sstevel@tonic-gate /*ARGSUSED*/
1940Sstevel@tonic-gate static struct dhcp_option *
get_default_routers(const char * arg)1950Sstevel@tonic-gate get_default_routers(const char *arg)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	struct dhcp_option *opt;
1980Sstevel@tonic-gate 	FILE *fp;
1990Sstevel@tonic-gate 	char rbuff[BUFSIZ];
2000Sstevel@tonic-gate 	struct in_addr **addrs = NULL;
2010Sstevel@tonic-gate 	struct in_addr **tmpaddrs;
2020Sstevel@tonic-gate 	int addrcnt = 0;
2030Sstevel@tonic-gate 	char *cp;
2040Sstevel@tonic-gate 	int i;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	/*
2070Sstevel@tonic-gate 	 * Method here is completely bogus; read output from netstat and
2080Sstevel@tonic-gate 	 * grab lines with destination of 'default'.  Look at the netstat
2090Sstevel@tonic-gate 	 * code if you think there's a better way...
2100Sstevel@tonic-gate 	 */
2110Sstevel@tonic-gate 	if ((fp = popen("netstat -r -n -f inet", "r")) == NULL) {
2120Sstevel@tonic-gate 		return (errno_opt());
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	while (fgets(rbuff, BUFSIZ, fp) != NULL) {
2160Sstevel@tonic-gate 		cp = strtok(rbuff, " \t");
2170Sstevel@tonic-gate 		if (cp == NULL)
2180Sstevel@tonic-gate 			continue;
2190Sstevel@tonic-gate 		if (strcmp(cp, "default") == 0) {
2200Sstevel@tonic-gate 			/* got one, add to list */
2210Sstevel@tonic-gate 			tmpaddrs = realloc(addrs,
2220Sstevel@tonic-gate 			    (addrcnt+1) * sizeof (struct in_addr *));
2230Sstevel@tonic-gate 			if (tmpaddrs == NULL) {
2240Sstevel@tonic-gate 				opt = errno_opt();
2250Sstevel@tonic-gate 				for (i = addrcnt - 1; i >= 0; --i) {
2260Sstevel@tonic-gate 					free(addrs[i]);
2270Sstevel@tonic-gate 				}
2280Sstevel@tonic-gate 				free(addrs);
2290Sstevel@tonic-gate 				(void) pclose(fp);
2300Sstevel@tonic-gate 				return (opt);
2310Sstevel@tonic-gate 			}
2320Sstevel@tonic-gate 			addrs = tmpaddrs;
2330Sstevel@tonic-gate 			addrs[addrcnt] = malloc(sizeof (struct in_addr));
2340Sstevel@tonic-gate 			if (addrs[addrcnt] == NULL) {
2350Sstevel@tonic-gate 				opt = errno_opt();
2360Sstevel@tonic-gate 				for (i = addrcnt - 1; i >= 0; --i) {
2370Sstevel@tonic-gate 					free(addrs[i]);
2380Sstevel@tonic-gate 				}
2390Sstevel@tonic-gate 				free(addrs);
2400Sstevel@tonic-gate 				(void) pclose(fp);
2410Sstevel@tonic-gate 				return (opt);
2420Sstevel@tonic-gate 			}
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 			cp = strtok(NULL, " \t");
2450Sstevel@tonic-gate 			addrs[addrcnt]->s_addr = inet_addr(cp);
2460Sstevel@tonic-gate 			/* LINTED - comparison */
2470Sstevel@tonic-gate 			if (addrs[addrcnt]->s_addr == -1) {
2480Sstevel@tonic-gate 				/* inet_addr didn't like it */
2490Sstevel@tonic-gate 				opt = newopt(ERROR_OPTION, 0);
2500Sstevel@tonic-gate 				if (opt != NULL) {
2510Sstevel@tonic-gate 					opt->error_code = EINVAL;
2520Sstevel@tonic-gate 					opt->u.msg = strerror(EINVAL);
2530Sstevel@tonic-gate 				}
2540Sstevel@tonic-gate 				while (--addrcnt >= 0)
2550Sstevel@tonic-gate 					free(addrs[addrcnt]);
2560Sstevel@tonic-gate 				free(addrs);
2570Sstevel@tonic-gate 				(void) pclose(fp);
2580Sstevel@tonic-gate 				return (opt);
2590Sstevel@tonic-gate 			}
2600Sstevel@tonic-gate 			++addrcnt;
2610Sstevel@tonic-gate 		}
2620Sstevel@tonic-gate 	}
2630Sstevel@tonic-gate 	(void) pclose(fp);
2640Sstevel@tonic-gate 	/*
2650Sstevel@tonic-gate 	 * Return all the routers we found.
2660Sstevel@tonic-gate 	 */
2670Sstevel@tonic-gate 	if (addrcnt != 0) {
2680Sstevel@tonic-gate 		opt = newopt(IP_OPTION, addrcnt);
2690Sstevel@tonic-gate 		if (opt == NULL) {
2700Sstevel@tonic-gate 			for (i = 0; i < addrcnt; ++i) {
2710Sstevel@tonic-gate 				free(addrs[i]);
2720Sstevel@tonic-gate 				free(addrs);
2730Sstevel@tonic-gate 			}
2740Sstevel@tonic-gate 			return (opt);
2750Sstevel@tonic-gate 		}
2760Sstevel@tonic-gate 		for (i = 0; i < addrcnt; ++i) {
2770Sstevel@tonic-gate 			opt->u.ret.data.addrs[i] = addrs[i];
2780Sstevel@tonic-gate 		}
2790Sstevel@tonic-gate 		free(addrs);
2800Sstevel@tonic-gate 	} else {
2810Sstevel@tonic-gate 		opt = newopt(ERROR_OPTION, 0);
2820Sstevel@tonic-gate 		if (opt != NULL) {
2830Sstevel@tonic-gate 			opt->error_code = 1;
2840Sstevel@tonic-gate 			opt->u.msg = gettext("No default router found");
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 	return (opt);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate /*ARGSUSED*/
2910Sstevel@tonic-gate static struct dhcp_option *
get_dns_domain(const char * arg)2920Sstevel@tonic-gate get_dns_domain(const char *arg)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	struct dhcp_option *opt;
2950Sstevel@tonic-gate 	res_state statp;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	statp = calloc(1, sizeof (*statp));
2980Sstevel@tonic-gate 	if (statp == NULL) {
2990Sstevel@tonic-gate 		opt = malloc_failure();
3000Sstevel@tonic-gate 	} else if (res_ninit(statp) == -1) {
3010Sstevel@tonic-gate 		/* Resolver failed initialization */
3020Sstevel@tonic-gate 		opt = errno_opt();
3030Sstevel@tonic-gate 	} else {
3040Sstevel@tonic-gate 		/* Initialized OK, copy domain name to return structure */
3050Sstevel@tonic-gate 		opt = newopt(ASCII_OPTION, 1);
3060Sstevel@tonic-gate 		if (opt != NULL) {
3070Sstevel@tonic-gate 			/*
3080Sstevel@tonic-gate 			 * If first one is loopback address, we return empty
3090Sstevel@tonic-gate 			 * as this almost certainly means that DNS is not
3100Sstevel@tonic-gate 			 * configured.
3110Sstevel@tonic-gate 			 */
3120Sstevel@tonic-gate 			if (statp->nsaddr_list[0].sin_family == AF_INET &&
3130Sstevel@tonic-gate 			    statp->nsaddr_list[0].sin_addr.s_addr ==
3140Sstevel@tonic-gate 			    ntohl(INADDR_LOOPBACK))
3150Sstevel@tonic-gate 				opt->u.ret.data.strings[0] = strdup("");
3160Sstevel@tonic-gate 			else
3170Sstevel@tonic-gate 				opt->u.ret.data.strings[0] =
3180Sstevel@tonic-gate 				    strdup(statp->defdname);
3190Sstevel@tonic-gate 			if (opt->u.ret.data.strings[0] == NULL) {
3200Sstevel@tonic-gate 				/* Couldn't allocate return memory */
3210Sstevel@tonic-gate 				dd_freeopt(opt);
3220Sstevel@tonic-gate 				opt = malloc_failure();
3230Sstevel@tonic-gate 			}
3240Sstevel@tonic-gate 		}
3250Sstevel@tonic-gate 	}
3265852Ssm26363 	if (statp != NULL) {
3275852Ssm26363 		(void) res_ndestroy(statp);
3285852Ssm26363 		free(statp);
3295852Ssm26363 	}
3300Sstevel@tonic-gate 	return (opt);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate /*ARGSUSED*/
3340Sstevel@tonic-gate static struct dhcp_option *
get_dns_servers(const char * arg)3350Sstevel@tonic-gate get_dns_servers(const char *arg)
3360Sstevel@tonic-gate {
3370Sstevel@tonic-gate 	struct dhcp_option *opt;
3380Sstevel@tonic-gate 	int i, j;
3390Sstevel@tonic-gate 	res_state statp;
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	statp = calloc(1, sizeof (*statp));
3420Sstevel@tonic-gate 	if (statp == NULL) {
3430Sstevel@tonic-gate 		opt = malloc_failure();
3440Sstevel@tonic-gate 	} else if (res_ninit(statp) == -1) {
3450Sstevel@tonic-gate 		/* Resolver initialization failed */
3460Sstevel@tonic-gate 		opt = errno_opt();
3470Sstevel@tonic-gate 	} else if (statp->nsaddr_list[0].sin_family == AF_INET &&
3480Sstevel@tonic-gate 	    statp->nsaddr_list[0].sin_addr.s_addr == ntohl(INADDR_LOOPBACK)) {
3490Sstevel@tonic-gate 		/*
3500Sstevel@tonic-gate 		 * If first one is loopback address, we ignore as this
3510Sstevel@tonic-gate 		 * almost certainly means that DNS is not configured.
3520Sstevel@tonic-gate 		 */
3530Sstevel@tonic-gate 		opt = newopt(IP_OPTION, 0);
3540Sstevel@tonic-gate 	} else {
3550Sstevel@tonic-gate 		/* Success, copy the data into our return structure */
3560Sstevel@tonic-gate 		opt = newopt(IP_OPTION, statp->nscount);
3570Sstevel@tonic-gate 		if (opt != NULL) {
3580Sstevel@tonic-gate 			for (i = 0, j = 0; i < statp->nscount; ++i) {
3590Sstevel@tonic-gate 				if (statp->nsaddr_list[i].sin_family != AF_INET)
3600Sstevel@tonic-gate 					/* IPv4 only, thanks */
3610Sstevel@tonic-gate 					continue;
3620Sstevel@tonic-gate 				opt->u.ret.data.addrs[j] = malloc(
3630Sstevel@tonic-gate 				    sizeof (struct in_addr));
3640Sstevel@tonic-gate 				if (opt->u.ret.data.addrs[j] == NULL) {
3650Sstevel@tonic-gate 					/* Out of memory, return immediately */
3660Sstevel@tonic-gate 					dd_freeopt(opt);
3670Sstevel@tonic-gate 					free(statp);
3680Sstevel@tonic-gate 					return (malloc_failure());
3690Sstevel@tonic-gate 				}
3700Sstevel@tonic-gate 				*opt->u.ret.data.addrs[j++] =
3710Sstevel@tonic-gate 				    statp->nsaddr_list[i].sin_addr;
3720Sstevel@tonic-gate 			}
3730Sstevel@tonic-gate 			/* Adjust number of addresses returned to real count */
3740Sstevel@tonic-gate 			opt->u.ret.count = j;
3750Sstevel@tonic-gate 		}
3760Sstevel@tonic-gate 	}
3775852Ssm26363 	if (statp != NULL) {
3785852Ssm26363 		(void) res_ndestroy(statp);
3795852Ssm26363 		free(statp);
3805852Ssm26363 	}
3810Sstevel@tonic-gate 	return (opt);
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate /* Get parameters related to a specific interface */
3850Sstevel@tonic-gate static struct dhcp_option *
get_if_param(int code,const char * arg)3860Sstevel@tonic-gate get_if_param(int code, const char *arg)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	int s;
3890Sstevel@tonic-gate 	struct ifconf ifc;
3900Sstevel@tonic-gate 	int num_ifs;
3910Sstevel@tonic-gate 	int i;
3920Sstevel@tonic-gate 	struct ifreq *ifr;
3930Sstevel@tonic-gate 	struct dhcp_option *opt;
3940Sstevel@tonic-gate #define	MY_TRUE	1
3950Sstevel@tonic-gate #define	MY_FALSE	0
3960Sstevel@tonic-gate 	int found = MY_FALSE;
3970Sstevel@tonic-gate 	struct sockaddr_in *sin;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/*
4000Sstevel@tonic-gate 	 * Open socket, needed for doing the ioctls.  Then get number of
4010Sstevel@tonic-gate 	 * interfaces so we know how much memory to allocate, then get
4020Sstevel@tonic-gate 	 * all the interface configurations.
4030Sstevel@tonic-gate 	 */
4040Sstevel@tonic-gate 	s = socket(AF_INET, SOCK_DGRAM, 0);
4050Sstevel@tonic-gate 	if (ioctl(s, SIOCGIFNUM, &num_ifs) < 0) {
4060Sstevel@tonic-gate 		return (errno_opt());
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 	ifc.ifc_len = num_ifs * sizeof (struct ifreq);
4090Sstevel@tonic-gate 	ifc.ifc_buf = malloc(ifc.ifc_len);
4100Sstevel@tonic-gate 	if (ifc.ifc_buf == NULL) {
4110Sstevel@tonic-gate 		return (malloc_failure());
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 	if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
4140Sstevel@tonic-gate 		opt = errno_opt();
4150Sstevel@tonic-gate 		free(ifc.ifc_buf);
4160Sstevel@tonic-gate 		(void) close(s);
4170Sstevel@tonic-gate 		return (opt);
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	/*
4210Sstevel@tonic-gate 	 * Find the interface which matches the one requested, and then
4220Sstevel@tonic-gate 	 * return the parameter requested.
4230Sstevel@tonic-gate 	 */
4240Sstevel@tonic-gate 	for (i = 0, ifr = ifc.ifc_req; i < num_ifs; ++i, ++ifr) {
4250Sstevel@tonic-gate 		if (strcmp(ifr->ifr_name, arg) != 0) {
4260Sstevel@tonic-gate 			continue;
4270Sstevel@tonic-gate 		}
4280Sstevel@tonic-gate 		found = MY_TRUE;
4290Sstevel@tonic-gate 		switch (code) {
4300Sstevel@tonic-gate 		case CD_SUBNETMASK:
4310Sstevel@tonic-gate 			if (ioctl(s, SIOCGIFNETMASK, ifr) < 0) {
4320Sstevel@tonic-gate 				opt = errno_opt();
4330Sstevel@tonic-gate 				free(ifc.ifc_buf);
4340Sstevel@tonic-gate 				(void) close(s);
4350Sstevel@tonic-gate 				return (opt);
4360Sstevel@tonic-gate 			}
4370Sstevel@tonic-gate 			opt = newopt(IP_OPTION, 1);
4380Sstevel@tonic-gate 			if (opt == NULL) {
4390Sstevel@tonic-gate 				free(ifc.ifc_buf);
4400Sstevel@tonic-gate 				(void) close(s);
4410Sstevel@tonic-gate 				return (malloc_failure());
4420Sstevel@tonic-gate 			}
4430Sstevel@tonic-gate 			opt->u.ret.data.addrs[0] =
4440Sstevel@tonic-gate 			    malloc(sizeof (struct in_addr));
4450Sstevel@tonic-gate 			if (opt->u.ret.data.addrs[0] == NULL) {
4460Sstevel@tonic-gate 				free(ifc.ifc_buf);
4470Sstevel@tonic-gate 				(void) close(s);
4480Sstevel@tonic-gate 				return (malloc_failure());
4490Sstevel@tonic-gate 			}
4500Sstevel@tonic-gate 			/*LINTED - alignment*/
4510Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&ifr->ifr_addr;
4520Sstevel@tonic-gate 			*opt->u.ret.data.addrs[0] = sin->sin_addr;
4530Sstevel@tonic-gate 			break;
4540Sstevel@tonic-gate 		case CD_MTU:
4550Sstevel@tonic-gate 			if (ioctl(s, SIOCGIFMTU, ifr) < 0) {
4560Sstevel@tonic-gate 				opt = errno_opt();
4570Sstevel@tonic-gate 				free(ifc.ifc_buf);
4580Sstevel@tonic-gate 				(void) close(s);
4590Sstevel@tonic-gate 				return (opt);
4600Sstevel@tonic-gate 			}
4610Sstevel@tonic-gate 			opt = newopt(NUMBER_OPTION, 1);
4620Sstevel@tonic-gate 			if (opt == NULL) {
4630Sstevel@tonic-gate 				free(ifc.ifc_buf);
4640Sstevel@tonic-gate 				(void) close(s);
4650Sstevel@tonic-gate 				return (malloc_failure());
4660Sstevel@tonic-gate 			}
4670Sstevel@tonic-gate 			opt->u.ret.data.numbers[0] = ifr->ifr_metric;
4680Sstevel@tonic-gate 			break;
4690Sstevel@tonic-gate 		case CD_BROADCASTADDR:
4700Sstevel@tonic-gate 			if (ioctl(s, SIOCGIFBRDADDR, ifr) < 0) {
4710Sstevel@tonic-gate 				opt = errno_opt();
4720Sstevel@tonic-gate 				free(ifc.ifc_buf);
4730Sstevel@tonic-gate 				(void) close(s);
4740Sstevel@tonic-gate 				return (opt);
4750Sstevel@tonic-gate 			}
4760Sstevel@tonic-gate 			opt = newopt(IP_OPTION, 1);
4770Sstevel@tonic-gate 			if (opt == NULL) {
4780Sstevel@tonic-gate 				free(ifc.ifc_buf);
4790Sstevel@tonic-gate 				(void) close(s);
4800Sstevel@tonic-gate 				return (malloc_failure());
4810Sstevel@tonic-gate 			}
4820Sstevel@tonic-gate 			opt->u.ret.data.addrs[0] =
4830Sstevel@tonic-gate 			    malloc(sizeof (struct in_addr));
4840Sstevel@tonic-gate 			if (opt->u.ret.data.addrs[0] == NULL) {
4850Sstevel@tonic-gate 				free(ifc.ifc_buf);
4860Sstevel@tonic-gate 				(void) close(s);
4870Sstevel@tonic-gate 				return (malloc_failure());
4880Sstevel@tonic-gate 			}
4890Sstevel@tonic-gate 			/*LINTED - alignment*/
4900Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&ifr->ifr_addr;
4910Sstevel@tonic-gate 			*opt->u.ret.data.addrs[0] = sin->sin_addr;
4920Sstevel@tonic-gate 			break;
4930Sstevel@tonic-gate 		default:
4940Sstevel@tonic-gate 			opt = newopt(ERROR_OPTION, 0);
4950Sstevel@tonic-gate 			opt->error_code = 1;
4960Sstevel@tonic-gate 			opt->u.msg = gettext("Bad option code in get_if_param");
4970Sstevel@tonic-gate 		}
4980Sstevel@tonic-gate 		break;
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 	free(ifc.ifc_buf);
5010Sstevel@tonic-gate 	(void) close(s);
5020Sstevel@tonic-gate 	if (found == MY_FALSE) {
5030Sstevel@tonic-gate 		opt = newopt(ERROR_OPTION, 0);
5040Sstevel@tonic-gate 		opt->error_code = 1;
5050Sstevel@tonic-gate 		opt->u.msg = gettext("No such interface");
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 	return (opt);
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate  * See if we are using router discovery on this system.  Method is to
5120Sstevel@tonic-gate  * read procfs and find out if the in.rdisc daemon is running.
5130Sstevel@tonic-gate  */
5140Sstevel@tonic-gate /*ARGSUSED*/
5150Sstevel@tonic-gate static struct dhcp_option *
get_router_discovery(const char * arg)5160Sstevel@tonic-gate get_router_discovery(const char *arg)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate 	struct dhcp_option *opt;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	opt = newopt(NUMBER_OPTION, 1);
5210Sstevel@tonic-gate 	if (opt == NULL) {
5220Sstevel@tonic-gate 		return (malloc_failure());
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 	if (dd_getpid(RDISC_FNAME) != -1) {
5250Sstevel@tonic-gate 		opt->u.ret.data.numbers[0] = 1;
5260Sstevel@tonic-gate 	} else {
5270Sstevel@tonic-gate 		opt->u.ret.data.numbers[0] = 0;
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate 	return (opt);
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate /*ARGSUSED*/
5330Sstevel@tonic-gate static struct dhcp_option *
get_nis_domain(const char * arg)5340Sstevel@tonic-gate get_nis_domain(const char *arg)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate 	struct dhcp_option *opt;
5370Sstevel@tonic-gate 	char *d;
5380Sstevel@tonic-gate 	int err;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	err = yp_get_default_domain(&d);
5410Sstevel@tonic-gate 	if (err != 0) {
5420Sstevel@tonic-gate 		opt = newopt(ERROR_OPTION, 0);
5430Sstevel@tonic-gate 		if (opt != NULL) {
5440Sstevel@tonic-gate 			opt->error_code = err;
5450Sstevel@tonic-gate 			opt->u.msg = gettext("Error in yp_get_default_domain");
5460Sstevel@tonic-gate 		}
5470Sstevel@tonic-gate 	} else {
5480Sstevel@tonic-gate 		opt = newopt(ASCII_OPTION, 1);
5490Sstevel@tonic-gate 		if (opt == NULL) {
5500Sstevel@tonic-gate 			return (malloc_failure());
5510Sstevel@tonic-gate 		}
5520Sstevel@tonic-gate 		opt->u.ret.data.strings[0] = strdup(d);
5530Sstevel@tonic-gate 		if (opt->u.ret.data.strings[0] == NULL) {
5540Sstevel@tonic-gate 			dd_freeopt(opt);
5550Sstevel@tonic-gate 			return (malloc_failure());
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate 	return (opt);
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate /*
5620Sstevel@tonic-gate  * Provide a default for the NISserv option.  We can only reliably
5630Sstevel@tonic-gate  * find out the master (as that's the only API) so that's what we provide.
5640Sstevel@tonic-gate  */
5650Sstevel@tonic-gate /*ARGSUSED*/
5660Sstevel@tonic-gate static struct dhcp_option *
get_nis_servers(const char * arg)5670Sstevel@tonic-gate get_nis_servers(const char *arg)
5680Sstevel@tonic-gate {
5690Sstevel@tonic-gate 	struct dhcp_option *opt;
5700Sstevel@tonic-gate 	int err;
5710Sstevel@tonic-gate 	char *d;
5720Sstevel@tonic-gate 	char *m;
5730Sstevel@tonic-gate 	struct hostent *hent;
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	/*
5760Sstevel@tonic-gate 	 * Get the default domain name, ask for master of hosts table,
5770Sstevel@tonic-gate 	 * look master up in hosts table to get address.
5780Sstevel@tonic-gate 	 */
5790Sstevel@tonic-gate 	err = yp_get_default_domain(&d);
5800Sstevel@tonic-gate 	if (err != 0) {
5810Sstevel@tonic-gate 		opt = newopt(ERROR_OPTION, 0);
5820Sstevel@tonic-gate 		if (opt != NULL) {
5830Sstevel@tonic-gate 			opt->error_code = err;
5840Sstevel@tonic-gate 			opt->u.msg = gettext("Error in yp_get_default_domain");
5850Sstevel@tonic-gate 		}
5860Sstevel@tonic-gate 	} else if ((err = yp_master(d, "hosts.byname", &m)) != 0) {
5870Sstevel@tonic-gate 		opt = newopt(ERROR_OPTION, 0);
5880Sstevel@tonic-gate 		if (opt != NULL) {
5890Sstevel@tonic-gate 			opt->error_code = err;
5900Sstevel@tonic-gate 			opt->u.msg = gettext("Error in yp_master");
5910Sstevel@tonic-gate 		}
5920Sstevel@tonic-gate 	} else if ((hent = gethostbyname(m)) == NULL) {
5930Sstevel@tonic-gate 		free(m);
5940Sstevel@tonic-gate 		opt = newopt(ERROR_OPTION, 0);
5950Sstevel@tonic-gate 		if (opt != NULL) {
5960Sstevel@tonic-gate 			opt->error_code = h_errno;
5970Sstevel@tonic-gate 			opt->u.msg = gettext("Error in gethostbyname()");
5980Sstevel@tonic-gate 		}
5990Sstevel@tonic-gate 	} else {
6000Sstevel@tonic-gate 		free(m);
6010Sstevel@tonic-gate 		opt = newopt(IP_OPTION, 1);
6020Sstevel@tonic-gate 		if (opt == NULL) {
6030Sstevel@tonic-gate 			return (malloc_failure());
6040Sstevel@tonic-gate 		}
6050Sstevel@tonic-gate 		opt->u.ret.data.addrs[0] = malloc(sizeof (struct in_addr));
6060Sstevel@tonic-gate 		if (opt->u.ret.data.addrs[0] == NULL) {
6070Sstevel@tonic-gate 			dd_freeopt(opt);
6080Sstevel@tonic-gate 			return (malloc_failure());
6090Sstevel@tonic-gate 		}
6100Sstevel@tonic-gate 		/*LINTED - alignment*/
6110Sstevel@tonic-gate 		*opt->u.ret.data.addrs[0] = *(struct in_addr *)hent->h_addr;
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 	return (opt);
6140Sstevel@tonic-gate }
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate /*
6170Sstevel@tonic-gate  * Retrieve the default value for a specified DHCP option.  Option code is
6180Sstevel@tonic-gate  * from the lst in dhcp.h, arg is an option-specific string argument, and
6190Sstevel@tonic-gate  * context is a presently unused parameter intended to allow this mechanism
6200Sstevel@tonic-gate  * to extend to vendor options in the future.  For now, only standard options
6210Sstevel@tonic-gate  * are supported.  Note that in some cases the returned pointer may be NULL,
6220Sstevel@tonic-gate  * so the caller must check for this case.
6230Sstevel@tonic-gate  */
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate /*ARGSUSED*/
6260Sstevel@tonic-gate struct dhcp_option *
dd_getopt(ushort_t code,const char * arg,const char * context)6270Sstevel@tonic-gate dd_getopt(ushort_t code, const char *arg, const char *context)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	struct dhcp_option *opt;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	switch (code) {
6320Sstevel@tonic-gate 	case CD_SUBNETMASK:
6330Sstevel@tonic-gate 	case CD_MTU:
6340Sstevel@tonic-gate 	case CD_BROADCASTADDR:
6350Sstevel@tonic-gate 		return (get_if_param(code, arg));
6360Sstevel@tonic-gate 	case CD_ROUTER:
6370Sstevel@tonic-gate 		return (get_default_routers(arg));
6380Sstevel@tonic-gate 	case CD_DNSSERV:
6390Sstevel@tonic-gate 		return (get_dns_servers(arg));
6400Sstevel@tonic-gate 	case CD_DNSDOMAIN:
6410Sstevel@tonic-gate 		return (get_dns_domain(arg));
6420Sstevel@tonic-gate 	case CD_ROUTER_DISCVRY_ON:
6430Sstevel@tonic-gate 		return (get_router_discovery(arg));
6440Sstevel@tonic-gate 	case CD_NIS_DOMAIN:
6450Sstevel@tonic-gate 		return (get_nis_domain(arg));
6460Sstevel@tonic-gate 	case CD_NIS_SERV:
6470Sstevel@tonic-gate 		return (get_nis_servers(arg));
6480Sstevel@tonic-gate 	default:
6490Sstevel@tonic-gate 		opt = newopt(ERROR_OPTION, 0);
6500Sstevel@tonic-gate 		if (opt != NULL) {
6510Sstevel@tonic-gate 			opt->error_code = 1;
6520Sstevel@tonic-gate 			opt->u.msg = gettext("Unimplemented option requested");
6530Sstevel@tonic-gate 		}
6540Sstevel@tonic-gate 		return (opt);
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate }
657