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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include "defs.h" 32 #include "ifconfig.h" 33 #include <sys/types.h> 34 #include <sys/dlpi.h> 35 #include <libdlpi.h> 36 #include <sys/sysmacros.h> 37 #include <deflt.h> 38 39 #define IPADDRL sizeof (struct in_addr) 40 #define RARPRETRIES 5 41 42 /* 43 * The following value (8) is determined to work reliably in switched 10/100MB 44 * ethernet environments. Use caution if you plan on decreasing it. 45 */ 46 #define RARPTIMEOUT 8 47 48 static char defaultfile[] = "/etc/inet/rarp"; 49 static char retries_var[] = "RARP_RETRIES="; 50 static int rarp_timeout = RARPTIMEOUT; 51 static int rarp_retries = RARPRETRIES; 52 53 static int rarp_write(int, struct arphdr *, uchar_t *, size_t, size_t); 54 static int rarp_open(char *, t_uscalar_t, size_t *, uchar_t **, 55 uchar_t **); 56 57 /* ARGSUSED */ 58 int 59 doifrevarp(char *ifname, struct sockaddr_in *laddr) 60 { 61 int if_fd; 62 struct pollfd pfd; 63 int s, flags, ret; 64 char *ctlbuf, *databuf, *cause; 65 struct strbuf ctl, data; 66 struct arphdr *req, *ans; 67 struct in_addr from; 68 struct in_addr answer; 69 union DL_primitives *dlp; 70 struct lifreq lifr; 71 struct timeval senttime; 72 struct timeval currenttime; 73 int waittime; 74 int tries_left; 75 size_t ifaddrlen, ifrarplen; 76 uchar_t *my_macaddr = NULL, *my_broadcast = NULL; 77 78 79 if (ifname[0] == '\0') { 80 (void) fprintf(stderr, "ifconfig: doifrevarp: name not set\n"); 81 exit(1); 82 } 83 84 if (debug) 85 (void) printf("doifrevarp interface %s\n", ifname); 86 87 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 88 Perror0_exit("socket"); 89 } 90 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 91 if (ioctl(s, SIOCGLIFFLAGS, (char *)&lifr) < 0) 92 Perror0_exit("SIOCGLIFFLAGS"); 93 94 /* don't try to revarp if we know it won't work */ 95 if ((lifr.lifr_flags & IFF_LOOPBACK) || 96 (lifr.lifr_flags & IFF_NOARP) || 97 (lifr.lifr_flags & IFF_POINTOPOINT)) 98 return (0); 99 100 /* open rarp interface */ 101 if_fd = rarp_open(ifname, ETHERTYPE_REVARP, &ifaddrlen, &my_macaddr, 102 &my_broadcast); 103 if (if_fd < 0) 104 return (0); 105 106 /* 107 * RARP looks at /etc/ethers and NIS, which only works 108 * with 6 byte addresses currently. 109 */ 110 if (ifaddrlen != ETHERADDRL) { 111 (void) close(if_fd); 112 free(my_macaddr); 113 free(my_broadcast); 114 return (0); 115 } 116 117 ifrarplen = sizeof (struct arphdr) + (2 * IPADDRL) + (2 * ifaddrlen); 118 119 /* look for adjustments to rarp_retries in the RARP defaults file */ 120 if (defopen(defaultfile) == 0) { 121 char *cp; 122 123 if (cp = defread(retries_var)) { 124 int ntries; 125 126 ntries = atoi(cp); 127 if (ntries > 0) 128 rarp_retries = ntries; 129 } 130 (void) defopen(NULL); /* close default file */ 131 } 132 133 /* allocate request and response buffers */ 134 if (((req = (struct arphdr *)malloc(ifrarplen)) == NULL) || 135 ((ans = (struct arphdr *)malloc(ifrarplen)) == NULL)) { 136 (void) close(if_fd); 137 free(req); 138 free(my_macaddr); 139 free(my_broadcast); 140 return (0); 141 } 142 143 /* create rarp request */ 144 (void) memset(req, 0, ifrarplen); 145 req->ar_hrd = htons(ARPHRD_ETHER); 146 req->ar_pro = htons(ETHERTYPE_IP); 147 req->ar_hln = ifaddrlen; 148 req->ar_pln = IPADDRL; 149 req->ar_op = htons(REVARP_REQUEST); 150 151 (void) memcpy((uchar_t *)req + sizeof (struct arphdr), my_macaddr, 152 ifaddrlen); 153 (void) memcpy((uchar_t *)req + sizeof (struct arphdr) + IPADDRL + 154 ifaddrlen, my_macaddr, ifaddrlen); 155 156 tries_left = rarp_retries; 157 rarp_retry: 158 /* send the request */ 159 if (rarp_write(if_fd, req, my_broadcast, ifaddrlen, ifrarplen) < 0) 160 goto fail; 161 162 gettimeofday(&senttime, NULL); 163 164 if (debug) 165 (void) printf("rarp sent\n"); 166 167 168 /* read the answers */ 169 if ((databuf = malloc(BUFSIZ)) == NULL) { 170 (void) fprintf(stderr, "ifconfig: malloc() failed\n"); 171 goto fail; 172 } 173 if ((ctlbuf = malloc(BUFSIZ)) == NULL) { 174 (void) fprintf(stderr, "ifconfig: malloc() failed\n"); 175 goto fail; 176 } 177 for (;;) { 178 ctl.len = 0; 179 ctl.maxlen = BUFSIZ; 180 ctl.buf = ctlbuf; 181 data.len = 0; 182 data.maxlen = BUFSIZ; 183 data.buf = databuf; 184 flags = 0; 185 186 /* 187 * Check to see when the packet was last sent. 188 * If we have not sent a packet in the last 189 * RARP_TIMEOUT seconds, we should send one now. 190 * Note that if some other host on the network is 191 * sending a broadcast packet, poll will return and we 192 * will find out that it does not match the reply we 193 * are waiting for and then go back to poll. If the 194 * frequency of such packets is > rarp_timeout, we don't 195 * want to just go back to poll. We should send out one 196 * more RARP request before blocking in poll. 197 */ 198 199 gettimeofday(¤ttime, NULL); 200 waittime = rarp_timeout - 201 (currenttime.tv_sec - senttime.tv_sec); 202 203 if (waittime <= 0) { 204 if (--tries_left > 0) { 205 if (debug) 206 (void) printf("rarp retry\n"); 207 goto rarp_retry; 208 } else { 209 if (debug) 210 (void) printf("rarp timeout\n"); 211 goto fail; 212 } 213 } 214 215 /* start RARP reply timeout */ 216 pfd.fd = if_fd; 217 pfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; 218 if ((ret = poll(&pfd, 1, waittime * 1000)) == 0) { 219 if (--tries_left > 0) { 220 if (debug) 221 (void) printf("rarp retry\n"); 222 goto rarp_retry; 223 } else { 224 if (debug) 225 (void) printf("rarp timeout\n"); 226 goto fail; 227 } 228 } else if (ret == -1) { 229 perror("ifconfig: RARP reply poll"); 230 goto fail; 231 } 232 233 /* poll returned > 0 for this fd so getmsg should not block */ 234 if ((ret = getmsg(if_fd, &ctl, &data, &flags)) < 0) { 235 perror("ifconfig: RARP reply getmsg"); 236 goto fail; 237 } 238 239 if (debug) { 240 (void) printf("rarp: ret[%d] ctl.len[%d] data.len[%d] " 241 "flags[%d]\n", ret, ctl.len, data.len, flags); 242 } 243 /* Validate DL_UNITDATA_IND. */ 244 /* LINTED: malloc returns a pointer aligned for any use */ 245 dlp = (union DL_primitives *)ctlbuf; 246 if (debug) { 247 (void) printf("rarp: dl_primitive[%lu]\n", 248 dlp->dl_primitive); 249 if (dlp->dl_primitive == DL_ERROR_ACK) { 250 (void) printf( 251 "rarp: err ak: dl_errno %lu errno %lu\n", 252 dlp->error_ack.dl_errno, 253 dlp->error_ack.dl_unix_errno); 254 } 255 if (dlp->dl_primitive == DL_UDERROR_IND) { 256 (void) printf("rarp: ud err: err[%lu] len[%lu] " 257 "off[%lu]\n", 258 dlp->uderror_ind.dl_errno, 259 dlp->uderror_ind.dl_dest_addr_length, 260 dlp->uderror_ind.dl_dest_addr_offset); 261 } 262 } 263 (void) memcpy(ans, databuf, ifrarplen); 264 cause = NULL; 265 if (ret & MORECTL) 266 cause = "MORECTL flag"; 267 else if (ret & MOREDATA) 268 cause = "MOREDATA flag"; 269 else if (ctl.len == 0) 270 cause = "missing control part of message"; 271 else if (ctl.len < 0) 272 cause = "short control part of message"; 273 else if (dlp->dl_primitive != DL_UNITDATA_IND) 274 cause = "not unitdata_ind"; 275 else if (ctl.len < DL_UNITDATA_IND_SIZE) 276 cause = "short unitdata_ind"; 277 278 else if (data.len < ifrarplen) 279 cause = "short arp"; 280 else if (ans->ar_hrd != htons(ARPHRD_ETHER)) 281 cause = "hrd"; 282 else if (ans->ar_pro != htons(ETHERTYPE_IP)) 283 cause = "pro"; 284 else if (ans->ar_hln != ifaddrlen) 285 cause = "hln"; 286 else if (ans->ar_pln != IPADDRL) 287 cause = "pln"; 288 if (cause) { 289 (void) fprintf(stderr, 290 "sanity check failed; cause: %s\n", cause); 291 continue; 292 } 293 294 switch (ntohs(ans->ar_op)) { 295 case ARPOP_REQUEST: 296 if (debug) 297 (void) printf("Got an arp request\n"); 298 break; 299 300 case ARPOP_REPLY: 301 if (debug) 302 (void) printf("Got an arp reply.\n"); 303 break; 304 305 case REVARP_REQUEST: 306 if (debug) 307 (void) printf("Got a rarp request.\n"); 308 break; 309 310 case REVARP_REPLY: 311 312 (void) memcpy(&answer, (uchar_t *)ans + 313 sizeof (struct arphdr) + (2 * ifaddrlen) + 314 IPADDRL, sizeof (answer)); 315 (void) memcpy(&from, (uchar_t *)ans + 316 sizeof (struct arphdr) + ifaddrlen, sizeof (from)); 317 if (debug) { 318 (void) printf("answer: %s", inet_ntoa(answer)); 319 (void) printf(" [from %s]\n", inet_ntoa(from)); 320 } 321 laddr->sin_addr = answer; 322 (void) close(if_fd); 323 free(req); 324 free(ans); 325 free(my_macaddr); 326 free(my_broadcast); 327 return (1); 328 329 default: 330 (void) fprintf(stderr, 331 "ifconfig: unknown opcode 0x%xd\n", ans->ar_op); 332 break; 333 } 334 } 335 /* NOTREACHED */ 336 fail: 337 (void) close(if_fd); 338 free(req); 339 free(ans); 340 free(my_macaddr); 341 free(my_broadcast); 342 return (0); 343 } 344 345 /* 346 * Open the datalink provider device and bind to the REVARP type. 347 * Return the resulting descriptor. 348 */ 349 static int 350 rarp_open(char *ifname, t_uscalar_t type, size_t *alen, uchar_t **myaddr, 351 uchar_t **mybaddr) 352 { 353 int fd, len; 354 char *str; 355 dl_info_ack_t dlinfo; 356 dlpi_if_attr_t dia; 357 int i; 358 359 if (debug) 360 (void) printf("rarp_open %s\n", ifname); 361 362 fd = dlpi_if_open(ifname, &dia, _B_FALSE); 363 if (fd < 0) { 364 (void) fprintf(stderr, "ifconfig: could not open device for " 365 "%s\n", ifname); 366 return (-1); 367 } 368 369 if (dlpi_info(fd, -1, &dlinfo, NULL, NULL, NULL, NULL, NULL, 370 NULL) < 0) { 371 (void) fprintf(stderr, "ifconfig: info req failed\n"); 372 goto failed; 373 } 374 375 if ((*mybaddr = malloc(dlinfo.dl_brdcst_addr_length)) == NULL) { 376 (void) fprintf(stderr, "rarp_open: malloc() failed\n"); 377 goto failed; 378 } 379 380 if (dlpi_info(fd, -1, &dlinfo, NULL, NULL, NULL, NULL, *mybaddr, 381 NULL) < 0) { 382 (void) fprintf(stderr, "ifconfig: info req failed\n"); 383 goto failed; 384 } 385 386 if (debug) { 387 (void) printf("broadcast addr: "); 388 for (i = 0; i < dlinfo.dl_brdcst_addr_length; i++) 389 (void) printf("%02x", (*mybaddr)[i]); 390 (void) printf("\n"); 391 } 392 393 len = *alen = dlinfo.dl_addr_length - abs(dlinfo.dl_sap_length); 394 395 if (debug) 396 (void) printf("rarp_open: addr length = %d\n", len); 397 398 if ((*myaddr = malloc(len)) == NULL) { 399 (void) fprintf(stderr, "rarp_open: malloc() failed\n"); 400 goto failed; 401 } 402 403 if (dlpi_bind(fd, -1, type, DL_CLDLS, _B_FALSE, NULL, NULL, 404 *myaddr, NULL) < 0) { 405 (void) fprintf(stderr, "rarp_open: dlpi_bind failed\n"); 406 goto failed; 407 } 408 409 if (debug) { 410 str = _link_ntoa(*myaddr, str, len, IFT_OTHER); 411 if (str != NULL) { 412 (void) printf("device %s mac address %s\n", 413 ifname, str); 414 free(str); 415 } 416 } 417 418 return (fd); 419 420 failed: 421 (void) dlpi_close(fd); 422 free(*mybaddr); 423 free(*myaddr); 424 return (-1); 425 } 426 427 static int 428 rarp_write(int fd, struct arphdr *ahdr, uchar_t *dhost, size_t maclen, 429 size_t rarplen) 430 { 431 struct strbuf ctl, data; 432 union DL_primitives *dlp; 433 char *ctlbuf; 434 int ret; 435 ushort_t etype = ETHERTYPE_REVARP; 436 437 /* 438 * Construct DL_UNITDATA_REQ. Allocate at least BUFSIZ bytes. 439 */ 440 ctl.len = DL_UNITDATA_REQ_SIZE + maclen + sizeof (ushort_t); 441 if ((ctl.buf = ctlbuf = malloc(ctl.len)) == NULL) { 442 (void) fprintf(stderr, "ifconfig: malloc() failed\n"); 443 return (-1); 444 } 445 /* LINTED: malloc returns a pointer aligned for any use */ 446 dlp = (union DL_primitives *)ctlbuf; 447 dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ; 448 dlp->unitdata_req.dl_dest_addr_length = maclen + sizeof (ushort_t); 449 dlp->unitdata_req.dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE; 450 dlp->unitdata_req.dl_priority.dl_min = 0; 451 dlp->unitdata_req.dl_priority.dl_max = 0; 452 453 /* 454 * XXX FIXME Assumes a specific DLPI address format. 455 */ 456 (void) memcpy(ctlbuf + DL_UNITDATA_REQ_SIZE, dhost, maclen); 457 (void) memcpy(ctlbuf + DL_UNITDATA_REQ_SIZE + maclen, &etype, 458 sizeof (etype)); 459 460 /* Send DL_UNITDATA_REQ. */ 461 data.len = rarplen; 462 data.buf = (char *)ahdr; 463 ret = putmsg(fd, &ctl, &data, 0); 464 free(ctlbuf); 465 return (ret); 466 } 467 468 int 469 dlpi_set_address(char *ifname, uchar_t *ea, int length) 470 { 471 int fd; 472 dlpi_if_attr_t dia; 473 474 fd = dlpi_if_open(ifname, &dia, _B_FALSE); 475 if (fd < 0) { 476 (void) fprintf(stderr, "ifconfig: could not open device for " 477 "%s\n", ifname); 478 return (-1); 479 } 480 481 if (dlpi_set_phys_addr(fd, -1, ea, length) < 0) { 482 (void) dlpi_close(fd); 483 return (-1); 484 } 485 486 (void) dlpi_close(fd); 487 return (0); 488 } 489 490 void 491 dlpi_print_address(char *ifname) 492 { 493 int fd, len; 494 uchar_t *laddr; 495 dl_info_ack_t dl_info; 496 char *str = NULL; 497 dlpi_if_attr_t dia; 498 499 fd = dlpi_if_open(ifname, &dia, _B_FALSE); 500 if (fd < 0) { 501 /* Do not report an error */ 502 return; 503 } 504 505 if (dlpi_info(fd, -1, &dl_info, NULL, NULL, NULL, NULL, NULL, 506 NULL) < 0) { 507 (void) fprintf(stderr, "ifconfig: info req failed\n"); 508 (void) dlpi_close(fd); 509 return; 510 } 511 512 len = dl_info.dl_addr_length - abs(dl_info.dl_sap_length); 513 if ((laddr = malloc(len)) == NULL) { 514 goto failed; 515 } 516 517 if (dlpi_phys_addr(fd, -1, DL_CURR_PHYS_ADDR, laddr, NULL) < 0) { 518 (void) fprintf(stderr, "ifconfig: phys_addr failed\n"); 519 goto failed; 520 } 521 522 (void) dlpi_close(fd); 523 str = _link_ntoa(laddr, str, len, IFT_OTHER); 524 if (str != NULL) { 525 switch (dl_info.dl_mac_type) { 526 case DL_IB: 527 (void) printf("\tipib %s \n", str); 528 break; 529 default: 530 (void) printf("\tether %s \n", str); 531 break; 532 } 533 free(str); 534 } 535 536 failed: 537 free(laddr); 538 (void) dlpi_close(fd); 539 } 540