1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 28 #include "defs.h" 29 #include "ifconfig.h" 30 #include <sys/types.h> 31 #include <libdlpi.h> 32 #include <sys/sysmacros.h> 33 #include <sys/time.h> 34 #include <deflt.h> 35 36 #define IPADDRL sizeof (struct in_addr) 37 #define RARPRETRIES 5 38 #define MSEC2NSEC(msec) ((msec) * 1000000) 39 #define NSEC2MSEC(nsec) ((nsec) / 1000000) 40 41 /* 42 * The following value (8) is determined to work reliably in switched 10/100MB 43 * ethernet environments. Use caution if you plan on decreasing it. 44 */ 45 #define RARPTIMEOUT 8 46 47 static char defaultfile[] = "/etc/inet/rarp"; 48 static char retries_var[] = "RARP_RETRIES="; 49 static int rarp_timeout = RARPTIMEOUT; 50 static int rarp_retries = RARPRETRIES; 51 52 static dlpi_handle_t rarp_open(const char *, size_t *, uchar_t *, uchar_t *); 53 static int rarp_recv(dlpi_handle_t, struct arphdr *, size_t, size_t, int64_t); 54 55 int 56 doifrevarp(const char *linkname, struct sockaddr_in *laddr) 57 { 58 int s, retval; 59 struct arphdr *req, *ans; 60 struct in_addr from; 61 struct in_addr answer; 62 struct lifreq lifr; 63 int tries_left; 64 size_t physaddrlen, ifrarplen; 65 uchar_t my_macaddr[DLPI_PHYSADDR_MAX]; 66 uchar_t my_broadcast[DLPI_PHYSADDR_MAX]; 67 dlpi_handle_t dh; 68 69 if (linkname[0] == '\0') { 70 (void) fprintf(stderr, "ifconfig: doifrevarp: name not set\n"); 71 exit(1); 72 } 73 74 if (debug) 75 (void) printf("doifrevarp interface %s\n", linkname); 76 77 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 78 Perror0_exit("socket"); 79 80 (void) strlcpy(lifr.lifr_name, linkname, sizeof (lifr.lifr_name)); 81 if (ioctl(s, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 82 (void) close(s); 83 Perror0_exit("SIOCGLIFFLAGS"); 84 } 85 86 /* don't try to revarp if we know it won't work */ 87 if ((lifr.lifr_flags & IFF_LOOPBACK) || 88 (lifr.lifr_flags & IFF_NOARP) || 89 (lifr.lifr_flags & IFF_IPMP) || 90 (lifr.lifr_flags & IFF_POINTOPOINT)) { 91 (void) close(s); 92 return (0); 93 } 94 95 /* open rarp interface */ 96 dh = rarp_open(linkname, &physaddrlen, my_macaddr, my_broadcast); 97 if (dh == NULL) { 98 (void) close(s); 99 return (0); 100 } 101 102 /* 103 * RARP looks at /etc/ethers and NIS, which only works 104 * with 6 byte addresses currently. 105 */ 106 if (physaddrlen != ETHERADDRL) { 107 dlpi_close(dh); 108 (void) close(s); 109 return (0); 110 } 111 112 ifrarplen = sizeof (struct arphdr) + (2 * IPADDRL) + (2 * physaddrlen); 113 114 /* look for adjustments to rarp_retries in the RARP defaults file */ 115 if (defopen(defaultfile) == 0) { 116 char *cp; 117 118 if (cp = defread(retries_var)) { 119 int ntries; 120 121 ntries = atoi(cp); 122 if (ntries > 0) 123 rarp_retries = ntries; 124 } 125 (void) defopen(NULL); /* close default file */ 126 } 127 128 /* allocate request and response buffers */ 129 if (((req = malloc(ifrarplen)) == NULL) || 130 ((ans = malloc(ifrarplen)) == NULL)) { 131 dlpi_close(dh); 132 (void) close(s); 133 free(req); 134 return (0); 135 } 136 137 /* create rarp request */ 138 (void) memset(req, 0, ifrarplen); 139 req->ar_hrd = htons(ARPHRD_ETHER); 140 req->ar_pro = htons(ETHERTYPE_IP); 141 req->ar_hln = physaddrlen; 142 req->ar_pln = IPADDRL; 143 req->ar_op = htons(REVARP_REQUEST); 144 145 (void) memcpy(&req[1], my_macaddr, physaddrlen); 146 (void) memcpy((uchar_t *)req + sizeof (struct arphdr) + IPADDRL + 147 physaddrlen, my_macaddr, physaddrlen); 148 149 for (tries_left = rarp_retries; tries_left > 0; --tries_left) { 150 /* send the request */ 151 retval = dlpi_send(dh, my_broadcast, physaddrlen, req, 152 ifrarplen, NULL); 153 if (retval != DLPI_SUCCESS) { 154 Perrdlpi("doifrevarp: cannot send rarp request", 155 linkname, retval); 156 break; 157 } 158 159 if (debug) 160 (void) printf("rarp sent\n"); 161 162 retval = rarp_recv(dh, ans, ifrarplen, physaddrlen, 163 rarp_timeout * MILLISEC); 164 165 if (retval != DLPI_ETIMEDOUT) 166 break; 167 168 if (debug) 169 (void) printf("rarp retry\n"); 170 } 171 172 if (retval == DLPI_SUCCESS) { 173 (void) memcpy(&answer, (uchar_t *)ans + 174 sizeof (struct arphdr) + (2 * physaddrlen) + IPADDRL, 175 sizeof (answer)); 176 (void) memcpy(&from, (uchar_t *)ans + physaddrlen + 177 sizeof (struct arphdr), sizeof (from)); 178 179 if (debug) { 180 (void) printf("answer: %s", inet_ntoa(answer)); 181 (void) printf(" [from %s]\n", inet_ntoa(from)); 182 } 183 laddr->sin_addr = answer; 184 } else if (debug) { 185 Perrdlpi("doifrevarp: could not receive rarp reply", 186 linkname, retval); 187 } 188 189 dlpi_close(dh); 190 (void) close(s); 191 free(req); 192 free(ans); 193 return (retval == DLPI_SUCCESS); 194 } 195 196 /* 197 * Open the datalink provider device and bind to the REVARP type. 198 * Return the resulting DLPI handle. 199 */ 200 static dlpi_handle_t 201 rarp_open(const char *linkname, size_t *alen, uchar_t *myaddr, uchar_t *mybaddr) 202 { 203 int retval; 204 char *physaddr, *bcastaddr; 205 dlpi_info_t dlinfo; 206 dlpi_handle_t dh; 207 208 if (debug) 209 (void) printf("rarp_open %s\n", linkname); 210 211 if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) { 212 Perrdlpi("rarp_open: dlpi_open failed", linkname, retval); 213 return (NULL); 214 } 215 216 if ((retval = dlpi_bind(dh, ETHERTYPE_REVARP, NULL)) != DLPI_SUCCESS) { 217 Perrdlpi("rarp_open: dlpi_bind failed", linkname, retval); 218 goto failed; 219 } 220 221 if ((retval = dlpi_info(dh, &dlinfo, 0)) != DLPI_SUCCESS) { 222 Perrdlpi("rarp_open: dlpi_info failed", linkname, retval); 223 goto failed; 224 } 225 226 if (dlinfo.di_bcastaddrlen == 0) { 227 (void) fprintf(stderr, "ifconfig: rarp_open: %s broadcast " 228 "not supported\n", linkname); 229 goto failed; 230 } 231 232 /* we assume the following are equal and fill in 'alen' */ 233 assert(dlinfo.di_bcastaddrlen == dlinfo.di_physaddrlen); 234 235 (void) memcpy(mybaddr, dlinfo.di_bcastaddr, dlinfo.di_bcastaddrlen); 236 237 *alen = dlinfo.di_physaddrlen; 238 239 (void) memcpy(myaddr, dlinfo.di_physaddr, dlinfo.di_physaddrlen); 240 241 if (debug) { 242 bcastaddr = _link_ntoa(mybaddr, NULL, dlinfo.di_bcastaddrlen, 243 IFT_OTHER); 244 245 physaddr = _link_ntoa(myaddr, NULL, dlinfo.di_physaddrlen, 246 IFT_OTHER); 247 248 if (physaddr != NULL && bcastaddr != NULL) { 249 (void) printf("device %s: broadcast address %s, mac " 250 "address %s\n", linkname, bcastaddr, physaddr); 251 } 252 253 free(physaddr); 254 free(bcastaddr); 255 256 (void) printf("rarp_open: addr length = %d\n", 257 dlinfo.di_physaddrlen); 258 } 259 260 return (dh); 261 262 failed: 263 dlpi_close(dh); 264 return (NULL); 265 } 266 267 /* 268 * Read reply for RARP request. If a reply is received within waitms, 269 * validate the reply. If it is a correct RARP reply return DLPI_SUCCESS, 270 * otherwise return DLPI_ETIMEDOUT. If there is an error while reading retrun 271 * the error code. 272 */ 273 static int 274 rarp_recv(dlpi_handle_t dh, struct arphdr *ans, size_t msglen, 275 size_t physaddrlen, int64_t waitms) 276 { 277 int retval; 278 char *cause; 279 size_t anslen = msglen; 280 hrtime_t endtime = gethrtime() + MSEC2NSEC(waitms); 281 hrtime_t currtime; 282 283 while ((currtime = gethrtime()) < endtime) { 284 waitms = NSEC2MSEC(endtime - currtime); 285 retval = dlpi_recv(dh, NULL, NULL, ans, &anslen, waitms, NULL); 286 if (retval == DLPI_SUCCESS) { 287 cause = NULL; 288 289 if (anslen < msglen) 290 cause = "short packet"; 291 else if (ans->ar_hrd != htons(ARPHRD_ETHER)) 292 cause = "hardware type not Ethernet"; 293 else if (ans->ar_pro != htons(ETHERTYPE_IP)) 294 cause = "protocol type not IP"; 295 else if (ans->ar_hln != physaddrlen) 296 cause = "unexpected hardware address length"; 297 else if (ans->ar_pln != IPADDRL) 298 cause = "unexpected protocol address length"; 299 if (cause != NULL) { 300 (void) fprintf(stderr, "RARP packet received " 301 "but discarded (%s)\n", cause); 302 continue; 303 } 304 switch (ntohs(ans->ar_op)) { 305 case REVARP_REQUEST: 306 if (debug) 307 (void) printf("Got a rarp request.\n"); 308 break; 309 310 case REVARP_REPLY: 311 return (DLPI_SUCCESS); 312 313 default: 314 (void) fprintf(stderr, "ifconfig: unknown " 315 "RARP opcode 0x%x\n", ans->ar_op); 316 break; 317 } 318 } else if (retval != DLPI_ETIMEDOUT) { 319 Perrdlpi("doifrevarp: dlpi_recv failed", 320 dlpi_linkname(dh), retval); 321 return (retval); 322 } 323 } 324 325 return (DLPI_ETIMEDOUT); 326 } 327 328 void 329 dlpi_print_address(const char *linkname) 330 { 331 uint_t physaddrlen = DLPI_PHYSADDR_MAX; 332 uchar_t physaddr[DLPI_PHYSADDR_MAX]; 333 char *str; 334 int retv; 335 dlpi_handle_t dh; 336 dlpi_info_t dlinfo; 337 338 if (dlpi_open(linkname, &dh, 0) != DLPI_SUCCESS) { 339 /* Do not report an error */ 340 return; 341 } 342 343 retv = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, physaddr, &physaddrlen); 344 if (retv != DLPI_SUCCESS) { 345 Perrdlpi("dlpi_get_physaddr failed", linkname, retv); 346 dlpi_close(dh); 347 return; 348 } 349 350 retv = dlpi_info(dh, &dlinfo, 0); 351 if (retv != DLPI_SUCCESS) { 352 Perrdlpi("dlpi_info failed", linkname, retv); 353 dlpi_close(dh); 354 return; 355 } 356 dlpi_close(dh); 357 358 str = _link_ntoa(physaddr, NULL, physaddrlen, IFT_OTHER); 359 360 if (str != NULL && physaddrlen != 0) { 361 switch (dlinfo.di_mactype) { 362 case DL_IB: 363 (void) printf("\tipib %s \n", str); 364 break; 365 default: 366 (void) printf("\tether %s \n", str); 367 break; 368 } 369 free(str); 370 } 371 } 372