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