xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/revarp.c (revision 13:938f6f798e05)
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
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include "defs.h"
320Sstevel@tonic-gate #include "ifconfig.h"
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/dlpi.h>
350Sstevel@tonic-gate #include <libdlpi.h>
360Sstevel@tonic-gate #include <sys/sysmacros.h>
370Sstevel@tonic-gate #include <deflt.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #define	IPADDRL		sizeof (struct in_addr)
400Sstevel@tonic-gate #define	RARPRETRIES	5
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * The following value (8) is determined to work reliably in switched 10/100MB
440Sstevel@tonic-gate  * ethernet environments. Use caution if you plan on decreasing it.
450Sstevel@tonic-gate  */
460Sstevel@tonic-gate #define	RARPTIMEOUT	8
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static char	defaultfile[] = "/etc/inet/rarp";
490Sstevel@tonic-gate static char	retries_var[] = "RARP_RETRIES=";
500Sstevel@tonic-gate static int rarp_timeout = RARPTIMEOUT;
510Sstevel@tonic-gate static int rarp_retries = RARPRETRIES;
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static int	rarp_write(int, struct arphdr *, uchar_t *, size_t, size_t);
540Sstevel@tonic-gate static int	rarp_open(char *, t_uscalar_t, size_t *, uchar_t **,
550Sstevel@tonic-gate     uchar_t **);
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /* ARGSUSED */
580Sstevel@tonic-gate int
590Sstevel@tonic-gate doifrevarp(char *ifname, struct sockaddr_in *laddr)
600Sstevel@tonic-gate {
610Sstevel@tonic-gate 	int			if_fd;
620Sstevel@tonic-gate 	struct pollfd		pfd;
630Sstevel@tonic-gate 	int			s, flags, ret;
640Sstevel@tonic-gate 	char			*ctlbuf, *databuf, *cause;
650Sstevel@tonic-gate 	struct strbuf		ctl, data;
660Sstevel@tonic-gate 	struct arphdr		*req, *ans;
670Sstevel@tonic-gate 	struct in_addr		from;
680Sstevel@tonic-gate 	struct in_addr		answer;
690Sstevel@tonic-gate 	union DL_primitives	*dlp;
700Sstevel@tonic-gate 	struct lifreq		lifr;
710Sstevel@tonic-gate 	struct timeval		senttime;
720Sstevel@tonic-gate 	struct timeval		currenttime;
730Sstevel@tonic-gate 	int			waittime;
740Sstevel@tonic-gate 	int			tries_left;
750Sstevel@tonic-gate 	size_t			ifaddrlen, ifrarplen;
760Sstevel@tonic-gate 	uchar_t			*my_macaddr = NULL, *my_broadcast = NULL;
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	if (ifname[0] == '\0') {
800Sstevel@tonic-gate 		(void) fprintf(stderr, "ifconfig: doifrevarp: name not set\n");
810Sstevel@tonic-gate 		exit(1);
820Sstevel@tonic-gate 	}
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	if (debug)
850Sstevel@tonic-gate 		(void) printf("doifrevarp interface %s\n", ifname);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
880Sstevel@tonic-gate 		Perror0_exit("socket");
890Sstevel@tonic-gate 	}
900Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
910Sstevel@tonic-gate 	if (ioctl(s, SIOCGLIFFLAGS, (char *)&lifr) < 0)
920Sstevel@tonic-gate 		Perror0_exit("SIOCGLIFFLAGS");
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	/* don't try to revarp if we know it won't work */
950Sstevel@tonic-gate 	if ((lifr.lifr_flags & IFF_LOOPBACK) ||
960Sstevel@tonic-gate 	    (lifr.lifr_flags & IFF_NOARP) ||
970Sstevel@tonic-gate 	    (lifr.lifr_flags & IFF_POINTOPOINT))
980Sstevel@tonic-gate 		return (0);
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	/* open rarp interface */
1010Sstevel@tonic-gate 	if_fd = rarp_open(ifname, ETHERTYPE_REVARP, &ifaddrlen, &my_macaddr,
1020Sstevel@tonic-gate 	    &my_broadcast);
1030Sstevel@tonic-gate 	if (if_fd < 0)
1040Sstevel@tonic-gate 		return (0);
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	/*
1070Sstevel@tonic-gate 	 * RARP looks at /etc/ethers and NIS, which only works
1080Sstevel@tonic-gate 	 * with 6 byte addresses currently.
1090Sstevel@tonic-gate 	 */
1100Sstevel@tonic-gate 	if (ifaddrlen != ETHERADDRL) {
1110Sstevel@tonic-gate 		(void) close(if_fd);
1120Sstevel@tonic-gate 		free(my_macaddr);
1130Sstevel@tonic-gate 		free(my_broadcast);
1140Sstevel@tonic-gate 		return (0);
1150Sstevel@tonic-gate 	}
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	ifrarplen = sizeof (struct arphdr) + (2 * IPADDRL) + (2 * ifaddrlen);
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	/* look for adjustments to rarp_retries in the RARP defaults file */
1200Sstevel@tonic-gate 	if (defopen(defaultfile) == 0) {
1210Sstevel@tonic-gate 		char	*cp;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 		if (cp = defread(retries_var)) {
1240Sstevel@tonic-gate 			int	ntries;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 			ntries = atoi(cp);
1270Sstevel@tonic-gate 			if (ntries > 0)
1280Sstevel@tonic-gate 				rarp_retries = ntries;
1290Sstevel@tonic-gate 		}
1300Sstevel@tonic-gate 		(void) defopen(NULL);	/* close default file */
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	/* allocate request and response buffers */
1340Sstevel@tonic-gate 	if (((req = (struct arphdr *)malloc(ifrarplen)) == NULL) ||
1350Sstevel@tonic-gate 	    ((ans = (struct arphdr *)malloc(ifrarplen)) == NULL)) {
1360Sstevel@tonic-gate 		(void) close(if_fd);
1370Sstevel@tonic-gate 		free(req);
1380Sstevel@tonic-gate 		free(my_macaddr);
1390Sstevel@tonic-gate 		free(my_broadcast);
1400Sstevel@tonic-gate 		return (0);
1410Sstevel@tonic-gate 	}
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	/* create rarp request */
1440Sstevel@tonic-gate 	(void) memset(req, 0, ifrarplen);
1450Sstevel@tonic-gate 	req->ar_hrd = htons(ARPHRD_ETHER);
1460Sstevel@tonic-gate 	req->ar_pro = htons(ETHERTYPE_IP);
1470Sstevel@tonic-gate 	req->ar_hln = ifaddrlen;
1480Sstevel@tonic-gate 	req->ar_pln = IPADDRL;
1490Sstevel@tonic-gate 	req->ar_op = htons(REVARP_REQUEST);
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	(void) memcpy((uchar_t *)req + sizeof (struct arphdr), my_macaddr,
1520Sstevel@tonic-gate 	    ifaddrlen);
1530Sstevel@tonic-gate 	(void) memcpy((uchar_t *)req + sizeof (struct arphdr) + IPADDRL +
1540Sstevel@tonic-gate 	    ifaddrlen, my_macaddr, ifaddrlen);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	tries_left = rarp_retries;
1570Sstevel@tonic-gate rarp_retry:
1580Sstevel@tonic-gate 	/* send the request */
1590Sstevel@tonic-gate 	if (rarp_write(if_fd, req, my_broadcast, ifaddrlen, ifrarplen) < 0)
1600Sstevel@tonic-gate 		goto fail;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	gettimeofday(&senttime, NULL);
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	if (debug)
1650Sstevel@tonic-gate 		(void) printf("rarp sent\n");
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	/* read the answers */
1690Sstevel@tonic-gate 	if ((databuf = malloc(BUFSIZ)) == NULL) {
1700Sstevel@tonic-gate 		(void) fprintf(stderr, "ifconfig: malloc() failed\n");
1710Sstevel@tonic-gate 		goto fail;
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 	if ((ctlbuf = malloc(BUFSIZ)) == NULL) {
1740Sstevel@tonic-gate 		(void) fprintf(stderr, "ifconfig: malloc() failed\n");
1750Sstevel@tonic-gate 		goto fail;
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 	for (;;) {
1780Sstevel@tonic-gate 		ctl.len = 0;
1790Sstevel@tonic-gate 		ctl.maxlen = BUFSIZ;
1800Sstevel@tonic-gate 		ctl.buf = ctlbuf;
1810Sstevel@tonic-gate 		data.len = 0;
1820Sstevel@tonic-gate 		data.maxlen = BUFSIZ;
1830Sstevel@tonic-gate 		data.buf = databuf;
1840Sstevel@tonic-gate 		flags = 0;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 		/*
1870Sstevel@tonic-gate 		 * Check to see when the packet was last sent.
1880Sstevel@tonic-gate 		 * If we have not sent a packet in the last
1890Sstevel@tonic-gate 		 * RARP_TIMEOUT seconds, we should send one now.
1900Sstevel@tonic-gate 		 * Note that if some other host on the network is
1910Sstevel@tonic-gate 		 * sending a broadcast packet, poll will return and we
1920Sstevel@tonic-gate 		 * will find out that it does not match the reply we
1930Sstevel@tonic-gate 		 * are waiting for and then go back to poll. If the
1940Sstevel@tonic-gate 		 * frequency of such packets is > rarp_timeout, we don't
1950Sstevel@tonic-gate 		 * want to just go back to poll. We should send out one
1960Sstevel@tonic-gate 		 * more RARP request before blocking in poll.
1970Sstevel@tonic-gate 		 */
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 		gettimeofday(&currenttime, NULL);
2000Sstevel@tonic-gate 		waittime = rarp_timeout -
2010Sstevel@tonic-gate 				(currenttime.tv_sec - senttime.tv_sec);
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 		if (waittime <= 0) {
2040Sstevel@tonic-gate 			if (--tries_left > 0) {
2050Sstevel@tonic-gate 				if (debug)
2060Sstevel@tonic-gate 					(void) printf("rarp retry\n");
2070Sstevel@tonic-gate 				goto rarp_retry;
2080Sstevel@tonic-gate 			} else {
2090Sstevel@tonic-gate 				if (debug)
2100Sstevel@tonic-gate 					(void) printf("rarp timeout\n");
2110Sstevel@tonic-gate 				goto fail;
2120Sstevel@tonic-gate 			}
2130Sstevel@tonic-gate 		}
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 		/* start RARP reply timeout */
2160Sstevel@tonic-gate 		pfd.fd = if_fd;
2170Sstevel@tonic-gate 		pfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
2180Sstevel@tonic-gate 		if ((ret = poll(&pfd, 1, waittime * 1000)) == 0) {
2190Sstevel@tonic-gate 			if (--tries_left > 0) {
2200Sstevel@tonic-gate 				if (debug)
2210Sstevel@tonic-gate 					(void) printf("rarp retry\n");
2220Sstevel@tonic-gate 				goto rarp_retry;
2230Sstevel@tonic-gate 			} else {
2240Sstevel@tonic-gate 				if (debug)
2250Sstevel@tonic-gate 					(void) printf("rarp timeout\n");
2260Sstevel@tonic-gate 				goto fail;
2270Sstevel@tonic-gate 			}
2280Sstevel@tonic-gate 		} else if (ret == -1) {
2290Sstevel@tonic-gate 			perror("ifconfig:  RARP reply poll");
2300Sstevel@tonic-gate 			goto fail;
2310Sstevel@tonic-gate 		}
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 		/* poll returned > 0 for this fd so getmsg should not block */
2340Sstevel@tonic-gate 		if ((ret = getmsg(if_fd, &ctl, &data, &flags)) < 0) {
2350Sstevel@tonic-gate 			perror("ifconfig: RARP reply getmsg");
2360Sstevel@tonic-gate 			goto fail;
2370Sstevel@tonic-gate 		}
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 		if (debug) {
2400Sstevel@tonic-gate 			(void) printf("rarp: ret[%d] ctl.len[%d] data.len[%d] "
2410Sstevel@tonic-gate 			    "flags[%d]\n", ret, ctl.len, data.len, flags);
2420Sstevel@tonic-gate 		}
2430Sstevel@tonic-gate 		/* Validate DL_UNITDATA_IND.  */
2440Sstevel@tonic-gate 		/* LINTED: malloc returns a pointer aligned for any use */
2450Sstevel@tonic-gate 		dlp = (union DL_primitives *)ctlbuf;
2460Sstevel@tonic-gate 		if (debug) {
2470Sstevel@tonic-gate 			(void) printf("rarp: dl_primitive[%lu]\n",
2480Sstevel@tonic-gate 				dlp->dl_primitive);
2490Sstevel@tonic-gate 			if (dlp->dl_primitive == DL_ERROR_ACK) {
2500Sstevel@tonic-gate 				(void) printf(
2510Sstevel@tonic-gate 				    "rarp: err ak: dl_errno %lu errno %lu\n",
2520Sstevel@tonic-gate 				    dlp->error_ack.dl_errno,
2530Sstevel@tonic-gate 				    dlp->error_ack.dl_unix_errno);
2540Sstevel@tonic-gate 			}
2550Sstevel@tonic-gate 			if (dlp->dl_primitive == DL_UDERROR_IND) {
2560Sstevel@tonic-gate 				(void) printf("rarp: ud err: err[%lu] len[%lu] "
2570Sstevel@tonic-gate 				    "off[%lu]\n",
2580Sstevel@tonic-gate 				    dlp->uderror_ind.dl_errno,
2590Sstevel@tonic-gate 				    dlp->uderror_ind.dl_dest_addr_length,
2600Sstevel@tonic-gate 				    dlp->uderror_ind.dl_dest_addr_offset);
2610Sstevel@tonic-gate 			}
2620Sstevel@tonic-gate 		}
2630Sstevel@tonic-gate 		(void) memcpy(ans, databuf, ifrarplen);
2640Sstevel@tonic-gate 		cause = NULL;
2650Sstevel@tonic-gate 		if (ret & MORECTL)
2660Sstevel@tonic-gate 			cause = "MORECTL flag";
2670Sstevel@tonic-gate 		else if (ret & MOREDATA)
2680Sstevel@tonic-gate 			cause = "MOREDATA flag";
2690Sstevel@tonic-gate 		else if (ctl.len == 0)
2700Sstevel@tonic-gate 			cause = "missing control part of message";
2710Sstevel@tonic-gate 		else if (ctl.len < 0)
2720Sstevel@tonic-gate 			cause = "short control part of message";
2730Sstevel@tonic-gate 		else if (dlp->dl_primitive != DL_UNITDATA_IND)
2740Sstevel@tonic-gate 			cause = "not unitdata_ind";
2750Sstevel@tonic-gate 		else if (ctl.len < DL_UNITDATA_IND_SIZE)
2760Sstevel@tonic-gate 			cause = "short unitdata_ind";
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 		else if (data.len < ifrarplen)
2790Sstevel@tonic-gate 			cause = "short arp";
2800Sstevel@tonic-gate 		else if (ans->ar_hrd != htons(ARPHRD_ETHER))
2810Sstevel@tonic-gate 			cause = "hrd";
2820Sstevel@tonic-gate 		else if (ans->ar_pro != htons(ETHERTYPE_IP))
2830Sstevel@tonic-gate 			cause = "pro";
2840Sstevel@tonic-gate 		else if (ans->ar_hln != ifaddrlen)
2850Sstevel@tonic-gate 			cause = "hln";
2860Sstevel@tonic-gate 		else if (ans->ar_pln != IPADDRL)
2870Sstevel@tonic-gate 			cause = "pln";
2880Sstevel@tonic-gate 		if (cause) {
2890Sstevel@tonic-gate 			(void) fprintf(stderr,
2900Sstevel@tonic-gate 				"sanity check failed; cause: %s\n", cause);
2910Sstevel@tonic-gate 			continue;
2920Sstevel@tonic-gate 		}
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 		switch (ntohs(ans->ar_op)) {
2950Sstevel@tonic-gate 		case ARPOP_REQUEST:
2960Sstevel@tonic-gate 			if (debug)
2970Sstevel@tonic-gate 				(void) printf("Got an arp request\n");
2980Sstevel@tonic-gate 			break;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 		case ARPOP_REPLY:
3010Sstevel@tonic-gate 			if (debug)
3020Sstevel@tonic-gate 				(void) printf("Got an arp reply.\n");
3030Sstevel@tonic-gate 			break;
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 		case REVARP_REQUEST:
3060Sstevel@tonic-gate 			if (debug)
3070Sstevel@tonic-gate 				(void) printf("Got a rarp request.\n");
3080Sstevel@tonic-gate 			break;
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		case REVARP_REPLY:
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 			(void) memcpy(&answer, (uchar_t *)ans +
3130Sstevel@tonic-gate 			    sizeof (struct arphdr) + (2 * ifaddrlen) +
3140Sstevel@tonic-gate 			    IPADDRL, sizeof (answer));
3150Sstevel@tonic-gate 			(void) memcpy(&from, (uchar_t *)ans +
3160Sstevel@tonic-gate 			    sizeof (struct arphdr) + ifaddrlen, sizeof (from));
3170Sstevel@tonic-gate 			if (debug) {
3180Sstevel@tonic-gate 				(void) printf("answer: %s", inet_ntoa(answer));
3190Sstevel@tonic-gate 				(void) printf(" [from %s]\n", inet_ntoa(from));
3200Sstevel@tonic-gate 			}
3210Sstevel@tonic-gate 			laddr->sin_addr = answer;
3220Sstevel@tonic-gate 			(void) close(if_fd);
3230Sstevel@tonic-gate 			free(req);
3240Sstevel@tonic-gate 			free(ans);
3250Sstevel@tonic-gate 			free(my_macaddr);
3260Sstevel@tonic-gate 			free(my_broadcast);
3270Sstevel@tonic-gate 			return (1);
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 		default:
3300Sstevel@tonic-gate 			(void) fprintf(stderr,
3310Sstevel@tonic-gate 			    "ifconfig: unknown opcode 0x%xd\n", ans->ar_op);
3320Sstevel@tonic-gate 			break;
3330Sstevel@tonic-gate 		}
3340Sstevel@tonic-gate 	}
3350Sstevel@tonic-gate 	/* NOTREACHED */
3360Sstevel@tonic-gate fail:
3370Sstevel@tonic-gate 	(void) close(if_fd);
3380Sstevel@tonic-gate 	free(req);
3390Sstevel@tonic-gate 	free(ans);
3400Sstevel@tonic-gate 	free(my_macaddr);
3410Sstevel@tonic-gate 	free(my_broadcast);
3420Sstevel@tonic-gate 	return (0);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate /*
3460Sstevel@tonic-gate  * Open the datalink provider device and bind to the REVARP type.
3470Sstevel@tonic-gate  * Return the resulting descriptor.
3480Sstevel@tonic-gate  */
3490Sstevel@tonic-gate static int
3500Sstevel@tonic-gate rarp_open(char *ifname, t_uscalar_t type, size_t *alen, uchar_t **myaddr,
3510Sstevel@tonic-gate     uchar_t **mybaddr)
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate 	int			fd, len;
3540Sstevel@tonic-gate 	char			*str;
3550Sstevel@tonic-gate 	dl_info_ack_t		dlinfo;
3560Sstevel@tonic-gate 	dlpi_if_attr_t		dia;
3570Sstevel@tonic-gate 	int			i;
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	if (debug)
3600Sstevel@tonic-gate 		(void) printf("rarp_open %s\n", ifname);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	fd = dlpi_if_open(ifname, &dia, _B_FALSE);
3630Sstevel@tonic-gate 	if (fd < 0) {
3640Sstevel@tonic-gate 		(void) fprintf(stderr, "ifconfig: could not open device for "
3650Sstevel@tonic-gate 		    "%s\n", ifname);
3660Sstevel@tonic-gate 		return (-1);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	if (dlpi_info(fd, -1, &dlinfo, NULL, NULL, NULL, NULL, NULL,
3700Sstevel@tonic-gate 	    NULL) < 0) {
3710Sstevel@tonic-gate 		(void) fprintf(stderr, "ifconfig: info req failed\n");
3720Sstevel@tonic-gate 		goto failed;
3730Sstevel@tonic-gate 	}
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	if ((*mybaddr = malloc(dlinfo.dl_brdcst_addr_length)) == NULL) {
3760Sstevel@tonic-gate 		(void) fprintf(stderr, "rarp_open: malloc() failed\n");
3770Sstevel@tonic-gate 		goto failed;
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	if (dlpi_info(fd, -1, &dlinfo, NULL, NULL, NULL, NULL, *mybaddr,
3810Sstevel@tonic-gate 	    NULL) < 0) {
3820Sstevel@tonic-gate 		(void) fprintf(stderr, "ifconfig: info req failed\n");
3830Sstevel@tonic-gate 		goto failed;
3840Sstevel@tonic-gate 	}
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	if (debug) {
3870Sstevel@tonic-gate 		(void) printf("broadcast addr: ");
3880Sstevel@tonic-gate 		for (i = 0; i < dlinfo.dl_brdcst_addr_length; i++)
3890Sstevel@tonic-gate 			(void) printf("%02x", (*mybaddr)[i]);
3900Sstevel@tonic-gate 		(void) printf("\n");
3910Sstevel@tonic-gate 	}
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	len = *alen = dlinfo.dl_addr_length - abs(dlinfo.dl_sap_length);
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	if (debug)
3960Sstevel@tonic-gate 		(void) printf("rarp_open: addr length = %d\n", len);
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	if ((*myaddr = malloc(len)) == NULL) {
3990Sstevel@tonic-gate 		(void) fprintf(stderr, "rarp_open: malloc() failed\n");
4000Sstevel@tonic-gate 		goto failed;
4010Sstevel@tonic-gate 	}
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	if (dlpi_bind(fd, -1, type, DL_CLDLS, _B_FALSE, NULL, NULL,
4040Sstevel@tonic-gate 	    *myaddr, NULL) < 0) {
4050Sstevel@tonic-gate 		(void) fprintf(stderr, "rarp_open: dlpi_bind failed\n");
4060Sstevel@tonic-gate 		goto failed;
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	if (debug) {
4100Sstevel@tonic-gate 		str = _link_ntoa(*myaddr, str, len, IFT_OTHER);
4110Sstevel@tonic-gate 		if (str != NULL) {
4120Sstevel@tonic-gate 			(void) printf("device %s mac address %s\n",
4130Sstevel@tonic-gate 			    ifname, str);
4140Sstevel@tonic-gate 			free(str);
4150Sstevel@tonic-gate 		}
4160Sstevel@tonic-gate 	}
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	return (fd);
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate failed:
4210Sstevel@tonic-gate 	(void) dlpi_close(fd);
4220Sstevel@tonic-gate 	free(*mybaddr);
4230Sstevel@tonic-gate 	free(*myaddr);
4240Sstevel@tonic-gate 	return (-1);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate static int
4280Sstevel@tonic-gate rarp_write(int fd, struct arphdr *ahdr, uchar_t *dhost, size_t maclen,
4290Sstevel@tonic-gate     size_t rarplen)
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate 	struct strbuf		ctl, data;
4320Sstevel@tonic-gate 	union DL_primitives	*dlp;
4330Sstevel@tonic-gate 	char			*ctlbuf;
4340Sstevel@tonic-gate 	int			ret;
4350Sstevel@tonic-gate 	ushort_t		etype = ETHERTYPE_REVARP;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	/*
4380Sstevel@tonic-gate 	 * Construct DL_UNITDATA_REQ. Allocate at least BUFSIZ bytes.
4390Sstevel@tonic-gate 	 */
4400Sstevel@tonic-gate 	ctl.len = DL_UNITDATA_REQ_SIZE + maclen + sizeof (ushort_t);
4410Sstevel@tonic-gate 	if ((ctl.buf = ctlbuf = malloc(ctl.len)) == NULL) {
4420Sstevel@tonic-gate 		(void) fprintf(stderr, "ifconfig: malloc() failed\n");
4430Sstevel@tonic-gate 		return (-1);
4440Sstevel@tonic-gate 	}
4450Sstevel@tonic-gate 	/* LINTED: malloc returns a pointer aligned for any use */
4460Sstevel@tonic-gate 	dlp = (union DL_primitives *)ctlbuf;
4470Sstevel@tonic-gate 	dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
4480Sstevel@tonic-gate 	dlp->unitdata_req.dl_dest_addr_length = maclen + sizeof (ushort_t);
4490Sstevel@tonic-gate 	dlp->unitdata_req.dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE;
4500Sstevel@tonic-gate 	dlp->unitdata_req.dl_priority.dl_min = 0;
4510Sstevel@tonic-gate 	dlp->unitdata_req.dl_priority.dl_max = 0;
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	/*
4540Sstevel@tonic-gate 	 * XXX FIXME Assumes a specific DLPI address format.
4550Sstevel@tonic-gate 	 */
4560Sstevel@tonic-gate 	(void) memcpy(ctlbuf + DL_UNITDATA_REQ_SIZE, dhost, maclen);
4570Sstevel@tonic-gate 	(void) memcpy(ctlbuf + DL_UNITDATA_REQ_SIZE + maclen, &etype,
4580Sstevel@tonic-gate 	    sizeof (etype));
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	/* Send DL_UNITDATA_REQ.  */
4610Sstevel@tonic-gate 	data.len = rarplen;
4620Sstevel@tonic-gate 	data.buf = (char *)ahdr;
4630Sstevel@tonic-gate 	ret = putmsg(fd, &ctl, &data, 0);
4640Sstevel@tonic-gate 	free(ctlbuf);
4650Sstevel@tonic-gate 	return (ret);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate int
4690Sstevel@tonic-gate dlpi_set_address(char *ifname, uchar_t *ea, int length)
4700Sstevel@tonic-gate {
4710Sstevel@tonic-gate 	int		fd;
4720Sstevel@tonic-gate 	dlpi_if_attr_t	dia;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	fd = dlpi_if_open(ifname, &dia, _B_FALSE);
4750Sstevel@tonic-gate 	if (fd < 0) {
4760Sstevel@tonic-gate 		(void) fprintf(stderr, "ifconfig: could not open device for "
4770Sstevel@tonic-gate 		    "%s\n", ifname);
4780Sstevel@tonic-gate 		return (-1);
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	if (dlpi_set_phys_addr(fd, -1, ea, length) < 0) {
4820Sstevel@tonic-gate 		(void) dlpi_close(fd);
4830Sstevel@tonic-gate 		return (-1);
4840Sstevel@tonic-gate 	}
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	(void) dlpi_close(fd);
4870Sstevel@tonic-gate 	return (0);
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate void
4910Sstevel@tonic-gate dlpi_print_address(char *ifname)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate 	int 	fd, len;
4940Sstevel@tonic-gate 	uchar_t	*laddr;
4950Sstevel@tonic-gate 	dl_info_ack_t dl_info;
4960Sstevel@tonic-gate 	char	*str = NULL;
4970Sstevel@tonic-gate 	dlpi_if_attr_t	dia;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	fd = dlpi_if_open(ifname, &dia, _B_FALSE);
5000Sstevel@tonic-gate 	if (fd < 0) {
5010Sstevel@tonic-gate 		/* Do not report an error */
5020Sstevel@tonic-gate 		return;
5030Sstevel@tonic-gate 	}
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	if (dlpi_info(fd, -1, &dl_info, NULL, NULL, NULL, NULL, NULL,
5060Sstevel@tonic-gate 	    NULL) < 0) {
5070Sstevel@tonic-gate 		(void) fprintf(stderr, "ifconfig: info req failed\n");
508*13Syw138387 		(void) dlpi_close(fd);
509*13Syw138387 		return;
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	len = dl_info.dl_addr_length - abs(dl_info.dl_sap_length);
5130Sstevel@tonic-gate 	if ((laddr = malloc(len)) == NULL) {
5140Sstevel@tonic-gate 		goto failed;
5150Sstevel@tonic-gate 	}
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	if (dlpi_phys_addr(fd, -1, DL_CURR_PHYS_ADDR, laddr, NULL) < 0) {
5180Sstevel@tonic-gate 		(void) fprintf(stderr, "ifconfig: phys_addr failed\n");
5190Sstevel@tonic-gate 		goto failed;
5200Sstevel@tonic-gate 	}
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	(void) dlpi_close(fd);
5230Sstevel@tonic-gate 	str = _link_ntoa(laddr, str, len, IFT_OTHER);
5240Sstevel@tonic-gate 	if (str != NULL) {
5250Sstevel@tonic-gate 		switch (dl_info.dl_mac_type) {
5260Sstevel@tonic-gate 			case DL_IB:
5270Sstevel@tonic-gate 				(void) printf("\tipib %s \n", str);
5280Sstevel@tonic-gate 				break;
5290Sstevel@tonic-gate 			default:
5300Sstevel@tonic-gate 				(void) printf("\tether %s \n", str);
5310Sstevel@tonic-gate 				break;
5320Sstevel@tonic-gate 		}
5330Sstevel@tonic-gate 		free(str);
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate failed:
5370Sstevel@tonic-gate 	free(laddr);
5380Sstevel@tonic-gate 	(void) dlpi_close(fd);
5390Sstevel@tonic-gate }
540