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
53628Sss150715 * Common Development and Distribution License (the "License").
63628Sss150715 * 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*8485SPeter.Memishian@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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
260Sstevel@tonic-gate /* All Rights Reserved */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include "defs.h"
290Sstevel@tonic-gate #include "ifconfig.h"
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <libdlpi.h>
320Sstevel@tonic-gate #include <sys/sysmacros.h>
333628Sss150715 #include <sys/time.h>
340Sstevel@tonic-gate #include <deflt.h>
350Sstevel@tonic-gate
360Sstevel@tonic-gate #define IPADDRL sizeof (struct in_addr)
370Sstevel@tonic-gate #define RARPRETRIES 5
383628Sss150715 #define MSEC2NSEC(msec) ((msec) * 1000000)
393628Sss150715 #define NSEC2MSEC(nsec) ((nsec) / 1000000)
400Sstevel@tonic-gate
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate * The following value (8) is determined to work reliably in switched 10/100MB
430Sstevel@tonic-gate * ethernet environments. Use caution if you plan on decreasing it.
440Sstevel@tonic-gate */
450Sstevel@tonic-gate #define RARPTIMEOUT 8
460Sstevel@tonic-gate
470Sstevel@tonic-gate static char defaultfile[] = "/etc/inet/rarp";
480Sstevel@tonic-gate static char retries_var[] = "RARP_RETRIES=";
490Sstevel@tonic-gate static int rarp_timeout = RARPTIMEOUT;
500Sstevel@tonic-gate static int rarp_retries = RARPRETRIES;
510Sstevel@tonic-gate
523628Sss150715 static dlpi_handle_t rarp_open(const char *, size_t *, uchar_t *, uchar_t *);
533628Sss150715 static int rarp_recv(dlpi_handle_t, struct arphdr *, size_t, size_t, int64_t);
540Sstevel@tonic-gate
550Sstevel@tonic-gate int
doifrevarp(const char * linkname,struct sockaddr_in * laddr)563628Sss150715 doifrevarp(const char *linkname, struct sockaddr_in *laddr)
570Sstevel@tonic-gate {
583628Sss150715 int s, retval;
590Sstevel@tonic-gate struct arphdr *req, *ans;
600Sstevel@tonic-gate struct in_addr from;
610Sstevel@tonic-gate struct in_addr answer;
620Sstevel@tonic-gate struct lifreq lifr;
630Sstevel@tonic-gate int tries_left;
643628Sss150715 size_t physaddrlen, ifrarplen;
653628Sss150715 uchar_t my_macaddr[DLPI_PHYSADDR_MAX];
663628Sss150715 uchar_t my_broadcast[DLPI_PHYSADDR_MAX];
673628Sss150715 dlpi_handle_t dh;
680Sstevel@tonic-gate
693628Sss150715 if (linkname[0] == '\0') {
700Sstevel@tonic-gate (void) fprintf(stderr, "ifconfig: doifrevarp: name not set\n");
710Sstevel@tonic-gate exit(1);
720Sstevel@tonic-gate }
730Sstevel@tonic-gate
740Sstevel@tonic-gate if (debug)
753628Sss150715 (void) printf("doifrevarp interface %s\n", linkname);
760Sstevel@tonic-gate
773628Sss150715 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
780Sstevel@tonic-gate Perror0_exit("socket");
793628Sss150715
803628Sss150715 (void) strlcpy(lifr.lifr_name, linkname, sizeof (lifr.lifr_name));
813628Sss150715 if (ioctl(s, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
823628Sss150715 (void) close(s);
833628Sss150715 Perror0_exit("SIOCGLIFFLAGS");
840Sstevel@tonic-gate }
850Sstevel@tonic-gate
860Sstevel@tonic-gate /* don't try to revarp if we know it won't work */
870Sstevel@tonic-gate if ((lifr.lifr_flags & IFF_LOOPBACK) ||
880Sstevel@tonic-gate (lifr.lifr_flags & IFF_NOARP) ||
89*8485SPeter.Memishian@Sun.COM (lifr.lifr_flags & IFF_IPMP) ||
903628Sss150715 (lifr.lifr_flags & IFF_POINTOPOINT)) {
913628Sss150715 (void) close(s);
920Sstevel@tonic-gate return (0);
933628Sss150715 }
940Sstevel@tonic-gate
950Sstevel@tonic-gate /* open rarp interface */
963628Sss150715 dh = rarp_open(linkname, &physaddrlen, my_macaddr, my_broadcast);
973628Sss150715 if (dh == NULL) {
983628Sss150715 (void) close(s);
990Sstevel@tonic-gate return (0);
1003628Sss150715 }
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate * RARP looks at /etc/ethers and NIS, which only works
1040Sstevel@tonic-gate * with 6 byte addresses currently.
1050Sstevel@tonic-gate */
1063628Sss150715 if (physaddrlen != ETHERADDRL) {
1073628Sss150715 dlpi_close(dh);
1083628Sss150715 (void) close(s);
1090Sstevel@tonic-gate return (0);
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate
1123628Sss150715 ifrarplen = sizeof (struct arphdr) + (2 * IPADDRL) + (2 * physaddrlen);
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate /* look for adjustments to rarp_retries in the RARP defaults file */
1150Sstevel@tonic-gate if (defopen(defaultfile) == 0) {
1160Sstevel@tonic-gate char *cp;
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate if (cp = defread(retries_var)) {
1190Sstevel@tonic-gate int ntries;
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate ntries = atoi(cp);
1220Sstevel@tonic-gate if (ntries > 0)
1230Sstevel@tonic-gate rarp_retries = ntries;
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate (void) defopen(NULL); /* close default file */
1260Sstevel@tonic-gate }
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate /* allocate request and response buffers */
1293628Sss150715 if (((req = malloc(ifrarplen)) == NULL) ||
1303628Sss150715 ((ans = malloc(ifrarplen)) == NULL)) {
1313628Sss150715 dlpi_close(dh);
1323628Sss150715 (void) close(s);
1330Sstevel@tonic-gate free(req);
1340Sstevel@tonic-gate return (0);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate /* create rarp request */
1380Sstevel@tonic-gate (void) memset(req, 0, ifrarplen);
1390Sstevel@tonic-gate req->ar_hrd = htons(ARPHRD_ETHER);
1400Sstevel@tonic-gate req->ar_pro = htons(ETHERTYPE_IP);
1413628Sss150715 req->ar_hln = physaddrlen;
1420Sstevel@tonic-gate req->ar_pln = IPADDRL;
1430Sstevel@tonic-gate req->ar_op = htons(REVARP_REQUEST);
1440Sstevel@tonic-gate
1453628Sss150715 (void) memcpy(&req[1], my_macaddr, physaddrlen);
1460Sstevel@tonic-gate (void) memcpy((uchar_t *)req + sizeof (struct arphdr) + IPADDRL +
1473628Sss150715 physaddrlen, my_macaddr, physaddrlen);
1480Sstevel@tonic-gate
1493628Sss150715 for (tries_left = rarp_retries; tries_left > 0; --tries_left) {
1503628Sss150715 /* send the request */
1513628Sss150715 retval = dlpi_send(dh, my_broadcast, physaddrlen, req,
1523628Sss150715 ifrarplen, NULL);
1533628Sss150715 if (retval != DLPI_SUCCESS) {
1543628Sss150715 Perrdlpi("doifrevarp: cannot send rarp request",
1553628Sss150715 linkname, retval);
1563628Sss150715 break;
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate
1593628Sss150715 if (debug)
1603628Sss150715 (void) printf("rarp sent\n");
1613628Sss150715
1623628Sss150715 retval = rarp_recv(dh, ans, ifrarplen, physaddrlen,
1633628Sss150715 rarp_timeout * MILLISEC);
1643628Sss150715
1653628Sss150715 if (retval != DLPI_ETIMEDOUT)
1663628Sss150715 break;
1670Sstevel@tonic-gate
1683628Sss150715 if (debug)
1693628Sss150715 (void) printf("rarp retry\n");
1703628Sss150715 }
1713628Sss150715
1723628Sss150715 if (retval == DLPI_SUCCESS) {
1733628Sss150715 (void) memcpy(&answer, (uchar_t *)ans +
1743628Sss150715 sizeof (struct arphdr) + (2 * physaddrlen) + IPADDRL,
1753628Sss150715 sizeof (answer));
1763628Sss150715 (void) memcpy(&from, (uchar_t *)ans + physaddrlen +
1773628Sss150715 sizeof (struct arphdr), sizeof (from));
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate if (debug) {
1803628Sss150715 (void) printf("answer: %s", inet_ntoa(answer));
1813628Sss150715 (void) printf(" [from %s]\n", inet_ntoa(from));
1820Sstevel@tonic-gate }
1833628Sss150715 laddr->sin_addr = answer;
1843628Sss150715 } else if (debug) {
1853628Sss150715 Perrdlpi("doifrevarp: could not receive rarp reply",
1863628Sss150715 linkname, retval);
1873628Sss150715 }
1880Sstevel@tonic-gate
1893628Sss150715 dlpi_close(dh);
1903628Sss150715 (void) close(s);
1910Sstevel@tonic-gate free(req);
1920Sstevel@tonic-gate free(ans);
1933628Sss150715 return (retval == DLPI_SUCCESS);
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate /*
1970Sstevel@tonic-gate * Open the datalink provider device and bind to the REVARP type.
1983628Sss150715 * Return the resulting DLPI handle.
1990Sstevel@tonic-gate */
2003628Sss150715 static dlpi_handle_t
rarp_open(const char * linkname,size_t * alen,uchar_t * myaddr,uchar_t * mybaddr)2013628Sss150715 rarp_open(const char *linkname, size_t *alen, uchar_t *myaddr, uchar_t *mybaddr)
2020Sstevel@tonic-gate {
2033628Sss150715 int retval;
2043628Sss150715 char *physaddr, *bcastaddr;
2053628Sss150715 dlpi_info_t dlinfo;
2063628Sss150715 dlpi_handle_t dh;
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate if (debug)
2093628Sss150715 (void) printf("rarp_open %s\n", linkname);
2100Sstevel@tonic-gate
2113628Sss150715 if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
2123628Sss150715 Perrdlpi("rarp_open: dlpi_open failed", linkname, retval);
2133628Sss150715 return (NULL);
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate
2163628Sss150715 if ((retval = dlpi_bind(dh, ETHERTYPE_REVARP, NULL)) != DLPI_SUCCESS) {
2173628Sss150715 Perrdlpi("rarp_open: dlpi_bind failed", linkname, retval);
2180Sstevel@tonic-gate goto failed;
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
2213628Sss150715 if ((retval = dlpi_info(dh, &dlinfo, 0)) != DLPI_SUCCESS) {
2223628Sss150715 Perrdlpi("rarp_open: dlpi_info failed", linkname, retval);
2230Sstevel@tonic-gate goto failed;
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate
2263628Sss150715 if (dlinfo.di_bcastaddrlen == 0) {
2273628Sss150715 (void) fprintf(stderr, "ifconfig: rarp_open: %s broadcast "
2283628Sss150715 "not supported\n", linkname);
2290Sstevel@tonic-gate goto failed;
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate
2323628Sss150715 /* we assume the following are equal and fill in 'alen' */
2333628Sss150715 assert(dlinfo.di_bcastaddrlen == dlinfo.di_physaddrlen);
2343628Sss150715
2353628Sss150715 (void) memcpy(mybaddr, dlinfo.di_bcastaddr, dlinfo.di_bcastaddrlen);
2363628Sss150715
2373628Sss150715 *alen = dlinfo.di_physaddrlen;
2383628Sss150715
2393628Sss150715 (void) memcpy(myaddr, dlinfo.di_physaddr, dlinfo.di_physaddrlen);
2403628Sss150715
2410Sstevel@tonic-gate if (debug) {
2423628Sss150715 bcastaddr = _link_ntoa(mybaddr, NULL, dlinfo.di_bcastaddrlen,
2433628Sss150715 IFT_OTHER);
2443628Sss150715
2453628Sss150715 physaddr = _link_ntoa(myaddr, NULL, dlinfo.di_physaddrlen,
2463628Sss150715 IFT_OTHER);
2473628Sss150715
2483628Sss150715 if (physaddr != NULL && bcastaddr != NULL) {
2493628Sss150715 (void) printf("device %s: broadcast address %s, mac "
2503628Sss150715 "address %s\n", linkname, bcastaddr, physaddr);
2513628Sss150715 }
2523628Sss150715
2533628Sss150715 free(physaddr);
2543628Sss150715 free(bcastaddr);
2553628Sss150715
2563628Sss150715 (void) printf("rarp_open: addr length = %d\n",
2573628Sss150715 dlinfo.di_physaddrlen);
2583628Sss150715 }
2593628Sss150715
2603628Sss150715 return (dh);
2613628Sss150715
2623628Sss150715 failed:
2633628Sss150715 dlpi_close(dh);
2643628Sss150715 return (NULL);
2653628Sss150715 }
2663628Sss150715
2673628Sss150715 /*
2683628Sss150715 * Read reply for RARP request. If a reply is received within waitms,
2693628Sss150715 * validate the reply. If it is a correct RARP reply return DLPI_SUCCESS,
2703628Sss150715 * otherwise return DLPI_ETIMEDOUT. If there is an error while reading retrun
2713628Sss150715 * the error code.
2723628Sss150715 */
2733628Sss150715 static int
rarp_recv(dlpi_handle_t dh,struct arphdr * ans,size_t msglen,size_t physaddrlen,int64_t waitms)2743628Sss150715 rarp_recv(dlpi_handle_t dh, struct arphdr *ans, size_t msglen,
2753628Sss150715 size_t physaddrlen, int64_t waitms)
2763628Sss150715 {
2773628Sss150715 int retval;
2783628Sss150715 char *cause;
2793628Sss150715 size_t anslen = msglen;
2803628Sss150715 hrtime_t endtime = gethrtime() + MSEC2NSEC(waitms);
2813628Sss150715 hrtime_t currtime;
2823628Sss150715
2833628Sss150715 while ((currtime = gethrtime()) < endtime) {
2843628Sss150715 waitms = NSEC2MSEC(endtime - currtime);
2853628Sss150715 retval = dlpi_recv(dh, NULL, NULL, ans, &anslen, waitms, NULL);
2863628Sss150715 if (retval == DLPI_SUCCESS) {
2873628Sss150715 cause = NULL;
2883628Sss150715
2893628Sss150715 if (anslen < msglen)
2903628Sss150715 cause = "short packet";
2913628Sss150715 else if (ans->ar_hrd != htons(ARPHRD_ETHER))
2923628Sss150715 cause = "hardware type not Ethernet";
2933628Sss150715 else if (ans->ar_pro != htons(ETHERTYPE_IP))
2943628Sss150715 cause = "protocol type not IP";
2953628Sss150715 else if (ans->ar_hln != physaddrlen)
2963628Sss150715 cause = "unexpected hardware address length";
2973628Sss150715 else if (ans->ar_pln != IPADDRL)
2983628Sss150715 cause = "unexpected protocol address length";
2993628Sss150715 if (cause != NULL) {
3003628Sss150715 (void) fprintf(stderr, "RARP packet received "
3013628Sss150715 "but discarded (%s)\n", cause);
3023628Sss150715 continue;
3033628Sss150715 }
3043628Sss150715 switch (ntohs(ans->ar_op)) {
3053628Sss150715 case REVARP_REQUEST:
3063628Sss150715 if (debug)
3073628Sss150715 (void) printf("Got a rarp request.\n");
3083628Sss150715 break;
3093628Sss150715
3103628Sss150715 case REVARP_REPLY:
3113628Sss150715 return (DLPI_SUCCESS);
3123628Sss150715
3133628Sss150715 default:
3143628Sss150715 (void) fprintf(stderr, "ifconfig: unknown "
3153628Sss150715 "RARP opcode 0x%x\n", ans->ar_op);
3163628Sss150715 break;
3173628Sss150715 }
3183628Sss150715 } else if (retval != DLPI_ETIMEDOUT) {
3193628Sss150715 Perrdlpi("doifrevarp: dlpi_recv failed",
3203628Sss150715 dlpi_linkname(dh), retval);
3213628Sss150715 return (retval);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate
3253628Sss150715 return (DLPI_ETIMEDOUT);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate void
dlpi_print_address(const char * linkname)3293628Sss150715 dlpi_print_address(const char *linkname)
3300Sstevel@tonic-gate {
3313628Sss150715 uint_t physaddrlen = DLPI_PHYSADDR_MAX;
3323628Sss150715 uchar_t physaddr[DLPI_PHYSADDR_MAX];
3333628Sss150715 char *str;
3343628Sss150715 int retv;
3353628Sss150715 dlpi_handle_t dh;
3363628Sss150715 dlpi_info_t dlinfo;
3370Sstevel@tonic-gate
3383628Sss150715 if (dlpi_open(linkname, &dh, 0) != DLPI_SUCCESS) {
3390Sstevel@tonic-gate /* Do not report an error */
3400Sstevel@tonic-gate return;
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate
3433628Sss150715 retv = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, physaddr, &physaddrlen);
3443628Sss150715 if (retv != DLPI_SUCCESS) {
3453628Sss150715 Perrdlpi("dlpi_get_physaddr failed", linkname, retv);
3463628Sss150715 dlpi_close(dh);
34713Syw138387 return;
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate
3503628Sss150715 retv = dlpi_info(dh, &dlinfo, 0);
3513628Sss150715 if (retv != DLPI_SUCCESS) {
3523628Sss150715 Perrdlpi("dlpi_info failed", linkname, retv);
3533628Sss150715 dlpi_close(dh);
3543628Sss150715 return;
3550Sstevel@tonic-gate }
3563628Sss150715 dlpi_close(dh);
3570Sstevel@tonic-gate
3583628Sss150715 str = _link_ntoa(physaddr, NULL, physaddrlen, IFT_OTHER);
3590Sstevel@tonic-gate
3606353Sdr146992 if (str != NULL && physaddrlen != 0) {
3613628Sss150715 switch (dlinfo.di_mactype) {
3620Sstevel@tonic-gate case DL_IB:
3630Sstevel@tonic-gate (void) printf("\tipib %s \n", str);
3640Sstevel@tonic-gate break;
3650Sstevel@tonic-gate default:
3660Sstevel@tonic-gate (void) printf("\tether %s \n", str);
3670Sstevel@tonic-gate break;
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate free(str);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate }
372