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 5*3628Sss150715 * Common Development and Distribution License (the "License"). 6*3628Sss150715 * 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*3628Sss150715 * Copyright 2007 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 #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include "defs.h" 310Sstevel@tonic-gate #include "ifconfig.h" 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <libdlpi.h> 340Sstevel@tonic-gate #include <sys/sysmacros.h> 35*3628Sss150715 #include <sys/time.h> 360Sstevel@tonic-gate #include <deflt.h> 370Sstevel@tonic-gate 380Sstevel@tonic-gate #define IPADDRL sizeof (struct in_addr) 390Sstevel@tonic-gate #define RARPRETRIES 5 40*3628Sss150715 #define MSEC2NSEC(msec) ((msec) * 1000000) 41*3628Sss150715 #define NSEC2MSEC(nsec) ((nsec) / 1000000) 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* 440Sstevel@tonic-gate * The following value (8) is determined to work reliably in switched 10/100MB 450Sstevel@tonic-gate * ethernet environments. Use caution if you plan on decreasing it. 460Sstevel@tonic-gate */ 470Sstevel@tonic-gate #define RARPTIMEOUT 8 480Sstevel@tonic-gate 490Sstevel@tonic-gate static char defaultfile[] = "/etc/inet/rarp"; 500Sstevel@tonic-gate static char retries_var[] = "RARP_RETRIES="; 510Sstevel@tonic-gate static int rarp_timeout = RARPTIMEOUT; 520Sstevel@tonic-gate static int rarp_retries = RARPRETRIES; 530Sstevel@tonic-gate 54*3628Sss150715 static dlpi_handle_t rarp_open(const char *, size_t *, uchar_t *, uchar_t *); 55*3628Sss150715 static int rarp_recv(dlpi_handle_t, struct arphdr *, size_t, size_t, int64_t); 560Sstevel@tonic-gate 570Sstevel@tonic-gate int 58*3628Sss150715 doifrevarp(const char *linkname, struct sockaddr_in *laddr) 590Sstevel@tonic-gate { 60*3628Sss150715 int s, retval; 610Sstevel@tonic-gate struct arphdr *req, *ans; 620Sstevel@tonic-gate struct in_addr from; 630Sstevel@tonic-gate struct in_addr answer; 640Sstevel@tonic-gate struct lifreq lifr; 650Sstevel@tonic-gate int tries_left; 66*3628Sss150715 size_t physaddrlen, ifrarplen; 67*3628Sss150715 uchar_t my_macaddr[DLPI_PHYSADDR_MAX]; 68*3628Sss150715 uchar_t my_broadcast[DLPI_PHYSADDR_MAX]; 69*3628Sss150715 dlpi_handle_t dh; 700Sstevel@tonic-gate 71*3628Sss150715 if (linkname[0] == '\0') { 720Sstevel@tonic-gate (void) fprintf(stderr, "ifconfig: doifrevarp: name not set\n"); 730Sstevel@tonic-gate exit(1); 740Sstevel@tonic-gate } 750Sstevel@tonic-gate 760Sstevel@tonic-gate if (debug) 77*3628Sss150715 (void) printf("doifrevarp interface %s\n", linkname); 780Sstevel@tonic-gate 79*3628Sss150715 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 800Sstevel@tonic-gate Perror0_exit("socket"); 81*3628Sss150715 82*3628Sss150715 (void) strlcpy(lifr.lifr_name, linkname, sizeof (lifr.lifr_name)); 83*3628Sss150715 if (ioctl(s, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 84*3628Sss150715 (void) close(s); 85*3628Sss150715 Perror0_exit("SIOCGLIFFLAGS"); 860Sstevel@tonic-gate } 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* don't try to revarp if we know it won't work */ 890Sstevel@tonic-gate if ((lifr.lifr_flags & IFF_LOOPBACK) || 900Sstevel@tonic-gate (lifr.lifr_flags & IFF_NOARP) || 91*3628Sss150715 (lifr.lifr_flags & IFF_POINTOPOINT)) { 92*3628Sss150715 (void) close(s); 930Sstevel@tonic-gate return (0); 94*3628Sss150715 } 950Sstevel@tonic-gate 960Sstevel@tonic-gate /* open rarp interface */ 97*3628Sss150715 dh = rarp_open(linkname, &physaddrlen, my_macaddr, my_broadcast); 98*3628Sss150715 if (dh == NULL) { 99*3628Sss150715 (void) close(s); 1000Sstevel@tonic-gate return (0); 101*3628Sss150715 } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /* 1040Sstevel@tonic-gate * RARP looks at /etc/ethers and NIS, which only works 1050Sstevel@tonic-gate * with 6 byte addresses currently. 1060Sstevel@tonic-gate */ 107*3628Sss150715 if (physaddrlen != ETHERADDRL) { 108*3628Sss150715 dlpi_close(dh); 109*3628Sss150715 (void) close(s); 1100Sstevel@tonic-gate return (0); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 113*3628Sss150715 ifrarplen = sizeof (struct arphdr) + (2 * IPADDRL) + (2 * physaddrlen); 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate /* look for adjustments to rarp_retries in the RARP defaults file */ 1160Sstevel@tonic-gate if (defopen(defaultfile) == 0) { 1170Sstevel@tonic-gate char *cp; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate if (cp = defread(retries_var)) { 1200Sstevel@tonic-gate int ntries; 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate ntries = atoi(cp); 1230Sstevel@tonic-gate if (ntries > 0) 1240Sstevel@tonic-gate rarp_retries = ntries; 1250Sstevel@tonic-gate } 1260Sstevel@tonic-gate (void) defopen(NULL); /* close default file */ 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate /* allocate request and response buffers */ 130*3628Sss150715 if (((req = malloc(ifrarplen)) == NULL) || 131*3628Sss150715 ((ans = malloc(ifrarplen)) == NULL)) { 132*3628Sss150715 dlpi_close(dh); 133*3628Sss150715 (void) close(s); 1340Sstevel@tonic-gate free(req); 1350Sstevel@tonic-gate return (0); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* create rarp request */ 1390Sstevel@tonic-gate (void) memset(req, 0, ifrarplen); 1400Sstevel@tonic-gate req->ar_hrd = htons(ARPHRD_ETHER); 1410Sstevel@tonic-gate req->ar_pro = htons(ETHERTYPE_IP); 142*3628Sss150715 req->ar_hln = physaddrlen; 1430Sstevel@tonic-gate req->ar_pln = IPADDRL; 1440Sstevel@tonic-gate req->ar_op = htons(REVARP_REQUEST); 1450Sstevel@tonic-gate 146*3628Sss150715 (void) memcpy(&req[1], my_macaddr, physaddrlen); 1470Sstevel@tonic-gate (void) memcpy((uchar_t *)req + sizeof (struct arphdr) + IPADDRL + 148*3628Sss150715 physaddrlen, my_macaddr, physaddrlen); 1490Sstevel@tonic-gate 150*3628Sss150715 for (tries_left = rarp_retries; tries_left > 0; --tries_left) { 151*3628Sss150715 /* send the request */ 152*3628Sss150715 retval = dlpi_send(dh, my_broadcast, physaddrlen, req, 153*3628Sss150715 ifrarplen, NULL); 154*3628Sss150715 if (retval != DLPI_SUCCESS) { 155*3628Sss150715 Perrdlpi("doifrevarp: cannot send rarp request", 156*3628Sss150715 linkname, retval); 157*3628Sss150715 break; 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 160*3628Sss150715 if (debug) 161*3628Sss150715 (void) printf("rarp sent\n"); 162*3628Sss150715 163*3628Sss150715 retval = rarp_recv(dh, ans, ifrarplen, physaddrlen, 164*3628Sss150715 rarp_timeout * MILLISEC); 165*3628Sss150715 166*3628Sss150715 if (retval != DLPI_ETIMEDOUT) 167*3628Sss150715 break; 1680Sstevel@tonic-gate 169*3628Sss150715 if (debug) 170*3628Sss150715 (void) printf("rarp retry\n"); 171*3628Sss150715 } 172*3628Sss150715 173*3628Sss150715 if (retval == DLPI_SUCCESS) { 174*3628Sss150715 (void) memcpy(&answer, (uchar_t *)ans + 175*3628Sss150715 sizeof (struct arphdr) + (2 * physaddrlen) + IPADDRL, 176*3628Sss150715 sizeof (answer)); 177*3628Sss150715 (void) memcpy(&from, (uchar_t *)ans + physaddrlen + 178*3628Sss150715 sizeof (struct arphdr), sizeof (from)); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate if (debug) { 181*3628Sss150715 (void) printf("answer: %s", inet_ntoa(answer)); 182*3628Sss150715 (void) printf(" [from %s]\n", inet_ntoa(from)); 1830Sstevel@tonic-gate } 184*3628Sss150715 laddr->sin_addr = answer; 185*3628Sss150715 } else if (debug) { 186*3628Sss150715 Perrdlpi("doifrevarp: could not receive rarp reply", 187*3628Sss150715 linkname, retval); 188*3628Sss150715 } 1890Sstevel@tonic-gate 190*3628Sss150715 dlpi_close(dh); 191*3628Sss150715 (void) close(s); 1920Sstevel@tonic-gate free(req); 1930Sstevel@tonic-gate free(ans); 194*3628Sss150715 return (retval == DLPI_SUCCESS); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate /* 1980Sstevel@tonic-gate * Open the datalink provider device and bind to the REVARP type. 199*3628Sss150715 * Return the resulting DLPI handle. 2000Sstevel@tonic-gate */ 201*3628Sss150715 static dlpi_handle_t 202*3628Sss150715 rarp_open(const char *linkname, size_t *alen, uchar_t *myaddr, uchar_t *mybaddr) 2030Sstevel@tonic-gate { 204*3628Sss150715 int retval; 205*3628Sss150715 char *physaddr, *bcastaddr; 206*3628Sss150715 dlpi_info_t dlinfo; 207*3628Sss150715 dlpi_handle_t dh; 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate if (debug) 210*3628Sss150715 (void) printf("rarp_open %s\n", linkname); 2110Sstevel@tonic-gate 212*3628Sss150715 if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) { 213*3628Sss150715 Perrdlpi("rarp_open: dlpi_open failed", linkname, retval); 214*3628Sss150715 return (NULL); 2150Sstevel@tonic-gate } 2160Sstevel@tonic-gate 217*3628Sss150715 if ((retval = dlpi_bind(dh, ETHERTYPE_REVARP, NULL)) != DLPI_SUCCESS) { 218*3628Sss150715 Perrdlpi("rarp_open: dlpi_bind failed", linkname, retval); 2190Sstevel@tonic-gate goto failed; 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate 222*3628Sss150715 if ((retval = dlpi_info(dh, &dlinfo, 0)) != DLPI_SUCCESS) { 223*3628Sss150715 Perrdlpi("rarp_open: dlpi_info failed", linkname, retval); 2240Sstevel@tonic-gate goto failed; 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate 227*3628Sss150715 if (dlinfo.di_bcastaddrlen == 0) { 228*3628Sss150715 (void) fprintf(stderr, "ifconfig: rarp_open: %s broadcast " 229*3628Sss150715 "not supported\n", linkname); 2300Sstevel@tonic-gate goto failed; 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate 233*3628Sss150715 /* we assume the following are equal and fill in 'alen' */ 234*3628Sss150715 assert(dlinfo.di_bcastaddrlen == dlinfo.di_physaddrlen); 235*3628Sss150715 236*3628Sss150715 (void) memcpy(mybaddr, dlinfo.di_bcastaddr, dlinfo.di_bcastaddrlen); 237*3628Sss150715 238*3628Sss150715 *alen = dlinfo.di_physaddrlen; 239*3628Sss150715 240*3628Sss150715 (void) memcpy(myaddr, dlinfo.di_physaddr, dlinfo.di_physaddrlen); 241*3628Sss150715 2420Sstevel@tonic-gate if (debug) { 243*3628Sss150715 bcastaddr = _link_ntoa(mybaddr, NULL, dlinfo.di_bcastaddrlen, 244*3628Sss150715 IFT_OTHER); 245*3628Sss150715 246*3628Sss150715 physaddr = _link_ntoa(myaddr, NULL, dlinfo.di_physaddrlen, 247*3628Sss150715 IFT_OTHER); 248*3628Sss150715 249*3628Sss150715 if (physaddr != NULL && bcastaddr != NULL) { 250*3628Sss150715 (void) printf("device %s: broadcast address %s, mac " 251*3628Sss150715 "address %s\n", linkname, bcastaddr, physaddr); 252*3628Sss150715 } 253*3628Sss150715 254*3628Sss150715 free(physaddr); 255*3628Sss150715 free(bcastaddr); 256*3628Sss150715 257*3628Sss150715 (void) printf("rarp_open: addr length = %d\n", 258*3628Sss150715 dlinfo.di_physaddrlen); 259*3628Sss150715 } 260*3628Sss150715 261*3628Sss150715 return (dh); 262*3628Sss150715 263*3628Sss150715 failed: 264*3628Sss150715 dlpi_close(dh); 265*3628Sss150715 return (NULL); 266*3628Sss150715 } 267*3628Sss150715 268*3628Sss150715 /* 269*3628Sss150715 * Read reply for RARP request. If a reply is received within waitms, 270*3628Sss150715 * validate the reply. If it is a correct RARP reply return DLPI_SUCCESS, 271*3628Sss150715 * otherwise return DLPI_ETIMEDOUT. If there is an error while reading retrun 272*3628Sss150715 * the error code. 273*3628Sss150715 */ 274*3628Sss150715 static int 275*3628Sss150715 rarp_recv(dlpi_handle_t dh, struct arphdr *ans, size_t msglen, 276*3628Sss150715 size_t physaddrlen, int64_t waitms) 277*3628Sss150715 { 278*3628Sss150715 int retval; 279*3628Sss150715 char *cause; 280*3628Sss150715 size_t anslen = msglen; 281*3628Sss150715 hrtime_t endtime = gethrtime() + MSEC2NSEC(waitms); 282*3628Sss150715 hrtime_t currtime; 283*3628Sss150715 284*3628Sss150715 while ((currtime = gethrtime()) < endtime) { 285*3628Sss150715 waitms = NSEC2MSEC(endtime - currtime); 286*3628Sss150715 retval = dlpi_recv(dh, NULL, NULL, ans, &anslen, waitms, NULL); 287*3628Sss150715 if (retval == DLPI_SUCCESS) { 288*3628Sss150715 cause = NULL; 289*3628Sss150715 290*3628Sss150715 if (anslen < msglen) 291*3628Sss150715 cause = "short packet"; 292*3628Sss150715 else if (ans->ar_hrd != htons(ARPHRD_ETHER)) 293*3628Sss150715 cause = "hardware type not Ethernet"; 294*3628Sss150715 else if (ans->ar_pro != htons(ETHERTYPE_IP)) 295*3628Sss150715 cause = "protocol type not IP"; 296*3628Sss150715 else if (ans->ar_hln != physaddrlen) 297*3628Sss150715 cause = "unexpected hardware address length"; 298*3628Sss150715 else if (ans->ar_pln != IPADDRL) 299*3628Sss150715 cause = "unexpected protocol address length"; 300*3628Sss150715 if (cause != NULL) { 301*3628Sss150715 (void) fprintf(stderr, "RARP packet received " 302*3628Sss150715 "but discarded (%s)\n", cause); 303*3628Sss150715 continue; 304*3628Sss150715 } 305*3628Sss150715 switch (ntohs(ans->ar_op)) { 306*3628Sss150715 case REVARP_REQUEST: 307*3628Sss150715 if (debug) 308*3628Sss150715 (void) printf("Got a rarp request.\n"); 309*3628Sss150715 break; 310*3628Sss150715 311*3628Sss150715 case REVARP_REPLY: 312*3628Sss150715 return (DLPI_SUCCESS); 313*3628Sss150715 314*3628Sss150715 default: 315*3628Sss150715 (void) fprintf(stderr, "ifconfig: unknown " 316*3628Sss150715 "RARP opcode 0x%x\n", ans->ar_op); 317*3628Sss150715 break; 318*3628Sss150715 } 319*3628Sss150715 } else if (retval != DLPI_ETIMEDOUT) { 320*3628Sss150715 Perrdlpi("doifrevarp: dlpi_recv failed", 321*3628Sss150715 dlpi_linkname(dh), retval); 322*3628Sss150715 return (retval); 3230Sstevel@tonic-gate } 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate 326*3628Sss150715 return (DLPI_ETIMEDOUT); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate int 330*3628Sss150715 dlpi_set_address(const char *linkname, uchar_t *physaddr, uint_t physaddrlen) 3310Sstevel@tonic-gate { 332*3628Sss150715 int retval; 333*3628Sss150715 dlpi_handle_t dh; 3340Sstevel@tonic-gate 335*3628Sss150715 if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) { 336*3628Sss150715 Perrdlpi("dlpi_open failed", linkname, retval); 3370Sstevel@tonic-gate return (-1); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 340*3628Sss150715 if ((retval = dlpi_set_physaddr(dh, DL_CURR_PHYS_ADDR, physaddr, 341*3628Sss150715 physaddrlen)) != DLPI_SUCCESS) { 342*3628Sss150715 Perrdlpi("dlpi_set_physaddr failed", linkname, retval); 343*3628Sss150715 dlpi_close(dh); 3440Sstevel@tonic-gate return (-1); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 347*3628Sss150715 dlpi_close(dh); 3480Sstevel@tonic-gate return (0); 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate void 352*3628Sss150715 dlpi_print_address(const char *linkname) 3530Sstevel@tonic-gate { 354*3628Sss150715 uint_t physaddrlen = DLPI_PHYSADDR_MAX; 355*3628Sss150715 uchar_t physaddr[DLPI_PHYSADDR_MAX]; 356*3628Sss150715 char *str; 357*3628Sss150715 int retv; 358*3628Sss150715 dlpi_handle_t dh; 359*3628Sss150715 dlpi_info_t dlinfo; 3600Sstevel@tonic-gate 361*3628Sss150715 if (dlpi_open(linkname, &dh, 0) != DLPI_SUCCESS) { 3620Sstevel@tonic-gate /* Do not report an error */ 3630Sstevel@tonic-gate return; 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 366*3628Sss150715 retv = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, physaddr, &physaddrlen); 367*3628Sss150715 if (retv != DLPI_SUCCESS) { 368*3628Sss150715 Perrdlpi("dlpi_get_physaddr failed", linkname, retv); 369*3628Sss150715 dlpi_close(dh); 37013Syw138387 return; 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 373*3628Sss150715 retv = dlpi_info(dh, &dlinfo, 0); 374*3628Sss150715 if (retv != DLPI_SUCCESS) { 375*3628Sss150715 Perrdlpi("dlpi_info failed", linkname, retv); 376*3628Sss150715 dlpi_close(dh); 377*3628Sss150715 return; 3780Sstevel@tonic-gate } 379*3628Sss150715 dlpi_close(dh); 3800Sstevel@tonic-gate 381*3628Sss150715 str = _link_ntoa(physaddr, NULL, physaddrlen, IFT_OTHER); 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate if (str != NULL) { 384*3628Sss150715 switch (dlinfo.di_mactype) { 3850Sstevel@tonic-gate case DL_IB: 3860Sstevel@tonic-gate (void) printf("\tipib %s \n", str); 3870Sstevel@tonic-gate break; 3880Sstevel@tonic-gate default: 3890Sstevel@tonic-gate (void) printf("\tether %s \n", str); 3900Sstevel@tonic-gate break; 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate free(str); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate } 395