1 /* $NetBSD: dlpi.c,v 1.1.1.3 2014/07/12 11:57:43 spz Exp $ */ 2 /* dlpi.c 3 4 Data Link Provider Interface (DLPI) network interface code. */ 5 6 /* 7 * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") 9 * Copyright (c) 1996-2003 by Internet Software Consortium 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 * 23 * Internet Systems Consortium, Inc. 24 * 950 Charter Street 25 * Redwood City, CA 94063 26 * <info@isc.org> 27 * https://www.isc.org/ 28 * 29 * This software was written for Internet Systems Consortium 30 * by Eric James Negaard, <lmdejn@lmd.ericsson.se>. To learn more about 31 * Internet Systems Consortium, see ``https://www.isc.org''. 32 * 33 * Joost Mulders has also done considerable work in debugging the DLPI API 34 * support on Solaris and getting this code to work properly on a variety 35 * of different Solaris platforms. 36 */ 37 38 #include <sys/cdefs.h> 39 __RCSID("$NetBSD: dlpi.c,v 1.1.1.3 2014/07/12 11:57:43 spz Exp $"); 40 41 /* 42 * Based largely in part to the existing NIT code in nit.c. 43 * 44 * This code has been developed and tested on sparc-based machines running 45 * SunOS 5.5.1, with le and hme network interfaces. It should be pretty 46 * generic, though. 47 */ 48 49 /* 50 * Implementation notes: 51 * 52 * I first tried to write this code to the "vanilla" DLPI 2.0 API. 53 * It worked on a Sun Ultra-1 with a hme interface, but didn't work 54 * on Sun SparcStation 5's with "le" interfaces (the packets sent out 55 * via dlpiunitdatareq contained an Ethernet type of 0x0000 instead 56 * of the expected 0x0800). 57 * 58 * Therefore I added the "DLPI_RAW" code which is a Sun extension to 59 * the DLPI standard. This code works on both of the above machines. 60 * This is configurable in the OS-dependent include file by defining 61 * USE_DLPI_RAW. 62 * 63 * It quickly became apparant that I should also use the "pfmod" 64 * STREAMS module to cut down on the amount of user level packet 65 * processing. I don't know how widely available "pfmod" is, so it's 66 * use is conditionally included. This is configurable in the 67 * OS-dependent include file by defining USE_DLPI_PFMOD. 68 * 69 * A major quirk on the Sun's at least, is that no packets seem to get 70 * sent out the interface until six seconds after the interface is 71 * first "attached" to [per system reboot] (it's actually from when 72 * the interface is attached, not when it is plumbed, so putting a 73 * sleep into the dhclient-script at PREINIT time doesn't help). I 74 * HAVE tried, without success to poll the fd to see when it is ready 75 * for writing. This doesn't help at all. If the sleeps are not done, 76 * the initial DHCPREQUEST or DHCPDISCOVER never gets sent out, so 77 * I've put them here, when register_send and register_receive are 78 * called (split up into two three-second sleeps between the notices, 79 * so that it doesn't seem like so long when you're watching :-). The 80 * amount of time to sleep is configurable in the OS-dependent include 81 * file by defining DLPI_FIRST_SEND_WAIT to be the number of seconds 82 * to sleep. 83 */ 84 85 /* 86 * The Open Group Technical Standard can be found here: 87 * http://www.opengroup.org/onlinepubs/009618899/index.htm 88 * 89 * The HP DLPI Programmer's Guide can be found here: 90 * http://docs.hp.com/en/B2355-90139/index.html 91 */ 92 93 #include "dhcpd.h" 94 95 #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) || \ 96 defined(USE_DLPI_HWADDR) 97 98 # include <sys/ioctl.h> 99 # include <sys/time.h> 100 # include <sys/dlpi.h> 101 # include <stropts.h> 102 # ifdef USE_DLPI_PFMOD 103 # include <sys/pfmod.h> 104 # endif 105 #include <poll.h> 106 #include <errno.h> 107 108 # include <netinet/in_systm.h> 109 # include "includes/netinet/ip.h" 110 # include "includes/netinet/udp.h" 111 # include "includes/netinet/if_ether.h" 112 113 # ifdef USE_DLPI_PFMOD 114 # ifdef USE_DLPI_RAW 115 # define DLPI_MODNAME "DLPI+RAW+PFMOD" 116 # else 117 # define DLPI_MODNAME "DLPI+PFMOD" 118 # endif 119 # else 120 # ifdef USE_DLPI_RAW 121 # define DLPI_MODNAME "DLPI+RAW" 122 # else 123 # define DLPI_MODNAME "DLPI" 124 # endif 125 # endif 126 127 # ifndef ABS 128 # define ABS(x) ((x) >= 0 ? (x) : 0-(x)) 129 # endif 130 131 #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW) 132 static int strioctl (int fd, int cmd, int timeout, int len, char *dp); 133 #endif 134 135 #define DLPI_MAXDLBUF 8192 /* Buffer size */ 136 #define DLPI_MAXDLADDR 1024 /* Max address size */ 137 #define DLPI_DEVDIR "/dev/" /* Device directory */ 138 139 static int dlpiopen(const char *ifname); 140 static int dlpiunit (char *ifname); 141 static int dlpiinforeq (int fd); 142 static int dlpiphysaddrreq (int fd, unsigned long addrtype); 143 static int dlpiattachreq (int fd, unsigned long ppa); 144 static int dlpibindreq (int fd, unsigned long sap, unsigned long max_conind, 145 unsigned long service_mode, unsigned long conn_mgmt, 146 unsigned long xidtest); 147 #if defined(UNUSED_DLPI_INTERFACE) 148 /* These functions are unused at present, but may be used at a later date. 149 * defined out to avoid compiler warnings about unused static functions. 150 */ 151 static int dlpidetachreq (int fd); 152 static int dlpiunbindreq (int fd); 153 #endif 154 static int dlpiokack (int fd, char *bufp); 155 static int dlpiinfoack (int fd, char *bufp); 156 static int dlpiphysaddrack (int fd, char *bufp); 157 static int dlpibindack (int fd, char *bufp); 158 #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE) 159 /* These functions are not used if we're only sourcing the get_hw_addr() 160 * function (for USE_SOCKETS). 161 */ 162 static int dlpiunitdatareq (int fd, unsigned char *addr, int addrlen, 163 unsigned long minpri, unsigned long maxpri, 164 unsigned char *data, int datalen); 165 static int dlpiunitdataind (int fd, 166 unsigned char *dstaddr, 167 unsigned long *dstaddrlen, 168 unsigned char *srcaddr, 169 unsigned long *srcaddrlen, 170 unsigned long *grpaddr, 171 unsigned char *data, 172 int datalen); 173 #endif /* !USE_DLPI_HWADDR: USE_DLPI_SEND || USE_DLPI_RECEIVE */ 174 static int expected (unsigned long prim, union DL_primitives *dlp, 175 int msgflags); 176 static int strgetmsg (int fd, struct strbuf *ctlp, struct strbuf *datap, 177 int *flagsp, char *caller); 178 179 /* Reinitializes the specified interface after an address change. This 180 is not required for packet-filter APIs. */ 181 182 #ifdef USE_DLPI_SEND 183 void if_reinitialize_send (info) 184 struct interface_info *info; 185 { 186 } 187 #endif 188 189 #ifdef USE_DLPI_RECEIVE 190 void if_reinitialize_receive (info) 191 struct interface_info *info; 192 { 193 } 194 #endif 195 196 /* Called by get_interface_list for each interface that's discovered. 197 Opens a packet filter for each interface and adds it to the select 198 mask. */ 199 200 int if_register_dlpi (info) 201 struct interface_info *info; 202 { 203 int sock; 204 int unit; 205 long buf [DLPI_MAXDLBUF]; 206 union DL_primitives *dlp; 207 208 dlp = (union DL_primitives *)buf; 209 210 /* Open a DLPI device */ 211 if ((sock = dlpiopen (info -> name)) < 0) { 212 log_fatal ("Can't open DLPI device for %s: %m", info -> name); 213 } 214 215 /* 216 * Submit a DL_INFO_REQ request, to find the dl_mac_type and 217 * dl_provider_style 218 */ 219 if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) { 220 log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name); 221 } else { 222 switch (dlp -> info_ack.dl_mac_type) { 223 case DL_CSMACD: /* IEEE 802.3 */ 224 case DL_ETHER: 225 info -> hw_address.hbuf [0] = HTYPE_ETHER; 226 break; 227 /* adding token ring 5/1999 - mayer@ping.at */ 228 case DL_TPR: 229 info -> hw_address.hbuf [0] = HTYPE_IEEE802; 230 break; 231 case DL_FDDI: 232 info -> hw_address.hbuf [0] = HTYPE_FDDI; 233 break; 234 default: 235 log_fatal("%s: unsupported DLPI MAC type %lu", info->name, 236 (unsigned long)dlp->info_ack.dl_mac_type); 237 break; 238 } 239 /* 240 * copy the sap length and broadcast address of this interface 241 * to interface_info. This fixes nothing but seemed nicer than to 242 * assume -2 and ffffff. 243 */ 244 info -> dlpi_sap_length = dlp -> info_ack.dl_sap_length; 245 info -> dlpi_broadcast_addr.hlen = 246 dlp -> info_ack.dl_brdcst_addr_length; 247 memcpy (info -> dlpi_broadcast_addr.hbuf, 248 (char *)dlp + dlp -> info_ack.dl_brdcst_addr_offset, 249 dlp -> info_ack.dl_brdcst_addr_length); 250 } 251 252 if (dlp -> info_ack.dl_provider_style == DL_STYLE2) { 253 /* 254 * Attach to the device. If this fails, the device 255 * does not exist. 256 */ 257 unit = dlpiunit (info -> name); 258 259 if (dlpiattachreq (sock, unit) < 0 260 || dlpiokack (sock, (char *)buf) < 0) { 261 log_fatal ("Can't attach DLPI device for %s: %m", info -> name); 262 } 263 } 264 265 /* 266 * Bind to the IP service access point (SAP), connectionless (CLDLS). 267 */ 268 if (dlpibindreq (sock, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0) < 0 269 || dlpibindack (sock, (char *)buf) < 0) { 270 log_fatal ("Can't bind DLPI device for %s: %m", info -> name); 271 } 272 273 /* 274 * Submit a DL_PHYS_ADDR_REQ request, to find 275 * the hardware address 276 */ 277 if (dlpiphysaddrreq (sock, DL_CURR_PHYS_ADDR) < 0 278 || dlpiphysaddrack (sock, (char *)buf) < 0) { 279 log_fatal ("Can't get DLPI hardware address for %s: %m", 280 info -> name); 281 } 282 283 info -> hw_address.hlen = dlp -> physaddr_ack.dl_addr_length + 1; 284 memcpy (&info -> hw_address.hbuf [1], 285 (char *)buf + dlp -> physaddr_ack.dl_addr_offset, 286 dlp -> physaddr_ack.dl_addr_length); 287 288 #ifdef USE_DLPI_RAW 289 if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) { 290 log_fatal ("Can't set DLPI RAW mode for %s: %m", 291 info -> name); 292 } 293 #endif 294 295 #ifdef USE_DLPI_PFMOD 296 if (ioctl (sock, I_PUSH, "pfmod") < 0) { 297 log_fatal ("Can't push packet filter onto DLPI for %s: %m", 298 info -> name); 299 } 300 #endif 301 302 return sock; 303 } 304 305 #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW) 306 static int 307 strioctl (fd, cmd, timeout, len, dp) 308 int fd; 309 int cmd; 310 int timeout; 311 int len; 312 char *dp; 313 { 314 struct strioctl sio; 315 int rslt; 316 317 sio.ic_cmd = cmd; 318 sio.ic_timout = timeout; 319 sio.ic_len = len; 320 sio.ic_dp = dp; 321 322 if ((rslt = ioctl (fd, I_STR, &sio)) < 0) { 323 return rslt; 324 } else { 325 return sio.ic_len; 326 } 327 } 328 #endif /* USE_DPI_PFMOD || USE_DLPI_RAW */ 329 330 #ifdef USE_DLPI_SEND 331 void if_register_send (info) 332 struct interface_info *info; 333 { 334 /* If we're using the DLPI API for sending and receiving, 335 we don't need to register this interface twice. */ 336 #ifndef USE_DLPI_RECEIVE 337 # ifdef USE_DLPI_PFMOD 338 struct packetfilt pf; 339 # endif 340 341 info -> wfdesc = if_register_dlpi (info); 342 343 # ifdef USE_DLPI_PFMOD 344 /* Set up an PFMOD filter that rejects everything... */ 345 pf.Pf_Priority = 0; 346 pf.Pf_FilterLen = 1; 347 pf.Pf_Filter [0] = ENF_PUSHZERO; 348 349 /* Install the filter */ 350 if (strioctl (info -> wfdesc, PFIOCSETF, INFTIM, 351 sizeof (pf), (char *)&pf) < 0) { 352 log_fatal ("Can't set PFMOD send filter on %s: %m", info -> name); 353 } 354 355 # endif /* USE_DLPI_PFMOD */ 356 #else /* !defined (USE_DLPI_RECEIVE) */ 357 /* 358 * If using DLPI for both send and receive, simply re-use 359 * the read file descriptor that was set up earlier. 360 */ 361 info -> wfdesc = info -> rfdesc; 362 #endif 363 364 if (!quiet_interface_discovery) 365 log_info ("Sending on DLPI/%s/%s%s%s", 366 info -> name, 367 print_hw_addr (info -> hw_address.hbuf [0], 368 info -> hw_address.hlen - 1, 369 &info -> hw_address.hbuf [1]), 370 (info -> shared_network ? "/" : ""), 371 (info -> shared_network ? 372 info -> shared_network -> name : "")); 373 374 #ifdef DLPI_FIRST_SEND_WAIT 375 /* See the implementation notes at the beginning of this file */ 376 # ifdef USE_DLPI_RECEIVE 377 sleep (DLPI_FIRST_SEND_WAIT - (DLPI_FIRST_SEND_WAIT / 2)); 378 # else 379 sleep (DLPI_FIRST_SEND_WAIT); 380 # endif 381 #endif 382 } 383 384 void if_deregister_send (info) 385 struct interface_info *info; 386 { 387 /* If we're using the DLPI API for sending and receiving, 388 we don't need to register this interface twice. */ 389 #ifndef USE_DLPI_RECEIVE 390 close (info -> wfdesc); 391 #endif 392 info -> wfdesc = -1; 393 394 if (!quiet_interface_discovery) 395 log_info ("Disabling output on DLPI/%s/%s%s%s", 396 info -> name, 397 print_hw_addr (info -> hw_address.hbuf [0], 398 info -> hw_address.hlen - 1, 399 &info -> hw_address.hbuf [1]), 400 (info -> shared_network ? "/" : ""), 401 (info -> shared_network ? 402 info -> shared_network -> name : "")); 403 } 404 #endif /* USE_DLPI_SEND */ 405 406 #ifdef USE_DLPI_RECEIVE 407 /* Packet filter program... 408 XXX Changes to the filter program may require changes to the constant 409 offsets used in if_register_send to patch the NIT program! XXX */ 410 411 void if_register_receive (info) 412 struct interface_info *info; 413 { 414 #ifdef USE_DLPI_PFMOD 415 struct packetfilt pf; 416 struct ip iphdr; 417 u_int16_t offset; 418 #endif 419 420 /* Open a DLPI device and hang it on this interface... */ 421 info -> rfdesc = if_register_dlpi (info); 422 423 #ifdef USE_DLPI_PFMOD 424 /* Set up the PFMOD filter program. */ 425 /* XXX Unlike the BPF filter program, this one won't work if the 426 XXX IP packet is fragmented or if there are options on the IP 427 XXX header. */ 428 pf.Pf_Priority = 0; 429 pf.Pf_FilterLen = 0; 430 431 #if defined (USE_DLPI_RAW) 432 # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */ 433 /* 434 * ethertype == ETHERTYPE_IP 435 */ 436 offset = 12; 437 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); 438 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; 439 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP); 440 # else 441 # define ETHER_H_PREFIX (0) 442 # endif /* USE_DLPI_RAW */ 443 /* 444 * The packets that will be received on this file descriptor 445 * will be IP packets (due to the SAP that was specified in 446 * the dlbind call). There will be no ethernet header. 447 * Therefore, setup the packet filter to check the protocol 448 * field for UDP, and the destination port number equal 449 * to the local port. All offsets are relative to the start 450 * of an IP packet. 451 */ 452 453 /* 454 * BOOTPS destination port 455 */ 456 offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_int16_t); 457 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); 458 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; 459 pf.Pf_Filter [pf.Pf_FilterLen++] = local_port; 460 461 /* 462 * protocol should be udp. this is a byte compare, test for 463 * endianess. 464 */ 465 offset = ETHER_H_PREFIX + ((u_int8_t *)&(iphdr.ip_p) - (u_int8_t *)&iphdr); 466 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); 467 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND; 468 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF); 469 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; 470 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP); 471 472 /* Install the filter... */ 473 if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM, 474 sizeof (pf), (char *)&pf) < 0) { 475 log_fatal ("Can't set PFMOD receive filter on %s: %m", info -> name); 476 } 477 #endif /* USE_DLPI_PFMOD */ 478 479 if (!quiet_interface_discovery) 480 log_info ("Listening on DLPI/%s/%s%s%s", 481 info -> name, 482 print_hw_addr (info -> hw_address.hbuf [0], 483 info -> hw_address.hlen - 1, 484 &info -> hw_address.hbuf [1]), 485 (info -> shared_network ? "/" : ""), 486 (info -> shared_network ? 487 info -> shared_network -> name : "")); 488 489 #ifdef DLPI_FIRST_SEND_WAIT 490 /* See the implementation notes at the beginning of this file */ 491 # ifdef USE_DLPI_SEND 492 sleep (DLPI_FIRST_SEND_WAIT / 2); 493 # else 494 sleep (DLPI_FIRST_SEND_WAIT); 495 # endif 496 #endif 497 } 498 499 void if_deregister_receive (info) 500 struct interface_info *info; 501 { 502 /* If we're using the DLPI API for sending and receiving, 503 we don't need to register this interface twice. */ 504 #ifndef USE_DLPI_SEND 505 close (info -> rfdesc); 506 #endif 507 info -> rfdesc = -1; 508 509 if (!quiet_interface_discovery) 510 log_info ("Disabling input on DLPI/%s/%s%s%s", 511 info -> name, 512 print_hw_addr (info -> hw_address.hbuf [0], 513 info -> hw_address.hlen - 1, 514 &info -> hw_address.hbuf [1]), 515 (info -> shared_network ? "/" : ""), 516 (info -> shared_network ? 517 info -> shared_network -> name : "")); 518 } 519 #endif /* USE_DLPI_RECEIVE */ 520 521 #ifdef USE_DLPI_SEND 522 ssize_t send_packet (interface, packet, raw, len, from, to, hto) 523 struct interface_info *interface; 524 struct packet *packet; 525 struct dhcp_packet *raw; 526 size_t len; 527 struct in_addr from; 528 struct sockaddr_in *to; 529 struct hardware *hto; 530 { 531 #ifdef USE_DLPI_RAW 532 double hh [32]; 533 int fudge; 534 #endif 535 double ih [1536 / sizeof (double)]; 536 unsigned char *dbuf = (unsigned char *)ih; 537 unsigned dbuflen; 538 unsigned char dstaddr [DLPI_MAXDLADDR]; 539 unsigned addrlen; 540 int result; 541 542 if (!strcmp (interface -> name, "fallback")) 543 return send_fallback (interface, packet, raw, 544 len, from, to, hto); 545 546 if (hto == NULL && interface->anycast_mac_addr.hlen) 547 hto = &interface->anycast_mac_addr; 548 549 dbuflen = 0; 550 551 /* Assemble the headers... */ 552 #ifdef USE_DLPI_RAW 553 assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto); 554 if (dbuflen > sizeof hh) 555 log_fatal ("send_packet: hh buffer too small.\n"); 556 fudge = dbuflen % 4; /* IP header must be word-aligned. */ 557 memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen); 558 dbuflen += fudge; 559 #endif 560 assemble_udp_ip_header (interface, dbuf, &dbuflen, from.s_addr, 561 to -> sin_addr.s_addr, to -> sin_port, 562 (unsigned char *)raw, len); 563 564 /* Copy the data into the buffer (yuk). */ 565 memcpy (dbuf + dbuflen, raw, len); 566 dbuflen += len; 567 568 #ifdef USE_DLPI_RAW 569 result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge); 570 #else 571 572 /* 573 * Setup the destination address (DLSAP) in dstaddr 574 * 575 * If sap_length < 0 we must deliver the DLSAP as phys+sap. 576 * If sap_length > 0 we must deliver the DLSAP as sap+phys. 577 * 578 * sap = Service Access Point == ETHERTYPE_IP 579 * sap + datalink address is called DLSAP in dlpi speak. 580 */ 581 { /* ENCODE DLSAP */ 582 unsigned char phys [DLPI_MAXDLADDR]; 583 unsigned char sap [4]; 584 int sap_len = interface -> dlpi_sap_length; 585 int phys_len = interface -> hw_address.hlen - 1; 586 587 /* sap = htons (ETHERTYPE_IP) kludge */ 588 memset (sap, 0, sizeof (sap)); 589 # if (BYTE_ORDER == LITTLE_ENDIAN) 590 sap [0] = 0x00; 591 sap [1] = 0x08; 592 # else 593 sap [0] = 0x08; 594 sap [1] = 0x00; 595 # endif 596 597 if (hto && hto -> hlen == interface -> hw_address.hlen) 598 memcpy ( phys, (char *) &hto -> hbuf [1], phys_len); 599 else 600 memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf, 601 interface -> dlpi_broadcast_addr.hlen); 602 603 if (sap_len < 0) { 604 memcpy ( dstaddr, phys, phys_len); 605 memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len)); 606 } 607 else { 608 memcpy ( dstaddr, (void *) sap, sap_len); 609 memcpy ( (char *) &dstaddr [sap_len], phys, phys_len); 610 } 611 addrlen = phys_len + ABS (sap_len); 612 } /* ENCODE DLSAP */ 613 614 result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen, 615 0, 0, dbuf, dbuflen); 616 #endif /* USE_DLPI_RAW */ 617 if (result < 0) 618 log_error ("send_packet: %m"); 619 return result; 620 } 621 #endif /* USE_DLPI_SEND */ 622 623 #ifdef USE_DLPI_RECEIVE 624 ssize_t receive_packet (interface, buf, len, from, hfrom) 625 struct interface_info *interface; 626 unsigned char *buf; 627 size_t len; 628 struct sockaddr_in *from; 629 struct hardware *hfrom; 630 { 631 unsigned char dbuf [1536]; 632 unsigned char srcaddr [DLPI_MAXDLADDR]; 633 unsigned long srcaddrlen; 634 int length = 0; 635 int offset = 0; 636 int bufix = 0; 637 unsigned paylen; 638 639 #ifdef USE_DLPI_RAW 640 length = read (interface -> rfdesc, dbuf, sizeof (dbuf)); 641 #else 642 length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL, 643 (unsigned long *)NULL, srcaddr, &srcaddrlen, 644 (unsigned long *)NULL, dbuf, sizeof (dbuf)); 645 #endif 646 647 if (length <= 0) { 648 log_error("receive_packet: %m"); 649 return length; 650 } 651 652 # if !defined (USE_DLPI_RAW) 653 /* 654 * Copy the sender's hw address into hfrom 655 * If sap_len < 0 the DLSAP is as phys+sap. 656 * If sap_len > 0 the DLSAP is as sap+phys. 657 * 658 * sap is discarded here. 659 */ 660 { /* DECODE DLSAP */ 661 int sap_len = interface -> dlpi_sap_length; 662 int phys_len = interface -> hw_address.hlen - 1; 663 664 if (hfrom && (srcaddrlen == ABS (sap_len) + phys_len )) { 665 hfrom -> hbuf [0] = interface -> hw_address.hbuf [0]; 666 hfrom -> hlen = interface -> hw_address.hlen; 667 668 if (sap_len < 0) { 669 memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len); 670 } 671 else { 672 memcpy((char *)&hfrom->hbuf[1], srcaddr + sap_len, phys_len); 673 } 674 } 675 else if (hfrom) { 676 memset (hfrom, '\0', sizeof *hfrom); 677 } 678 } /* DECODE_DLSAP */ 679 680 # endif /* !defined (USE_DLPI_RAW) */ 681 682 /* Decode the IP and UDP headers... */ 683 bufix = 0; 684 #ifdef USE_DLPI_RAW 685 /* Decode the physical header... */ 686 offset = decode_hw_header (interface, dbuf, bufix, hfrom); 687 688 /* If a physical layer checksum failed (dunno of any 689 physical layer that supports this, but WTH), skip this 690 packet. */ 691 if (offset < 0) { 692 return 0; 693 } 694 bufix += offset; 695 length -= offset; 696 #endif 697 offset = decode_udp_ip_header (interface, dbuf, bufix, 698 from, length, &paylen); 699 700 /* 701 * If the IP or UDP checksum was bad, skip the packet... 702 * 703 * Note: this happens all the time when writing packets via the 704 * fallback socket. The packet received by streams does not have 705 * the IP or UDP checksums filled in, as those are calculated by 706 * the hardware. 707 */ 708 if (offset < 0) { 709 return 0; 710 } 711 712 bufix += offset; 713 length -= offset; 714 715 if (length < paylen) 716 log_fatal("Internal inconsistency at %s:%d.", MDL); 717 718 /* Copy out the data in the packet... */ 719 memcpy(buf, &dbuf [bufix], paylen); 720 return paylen; 721 } 722 #endif 723 724 /* Common DLPI routines ... 725 * 726 * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se> 727 * 728 * Based largely in part to the example code contained in the document 729 * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written 730 * by Neal Nuckolls of SunSoft Internet Engineering. 731 * 732 * This code has been developed and tested on sparc-based machines running 733 * SunOS 5.5.1, with le and hme network interfaces. It should be pretty 734 * generic, though. 735 * 736 * The usual disclaimers apply. This code works for me. Don't blame me 737 * if it makes your machine or network go down in flames. That taken 738 * into consideration, use this code as you wish. If you make usefull 739 * modifications I'd appreciate hearing about it. 740 */ 741 742 #define DLPI_MAXWAIT 15 /* Max timeout */ 743 744 745 /* 746 * Parse an interface name and extract the unit number 747 */ 748 749 static int dlpiunit (ifname) 750 char *ifname; 751 { 752 char *cp; 753 int unit; 754 755 if (!ifname) { 756 return 0; 757 } 758 759 /* Advance to the end of the name */ 760 cp = ifname; 761 while (*cp) cp++; 762 /* Back up to the start of the first digit */ 763 while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--; 764 765 /* Convert the unit number */ 766 unit = 0; 767 while (*cp >= '0' && *cp <= '9') { 768 unit *= 10; 769 unit += (*cp++ - '0'); 770 } 771 772 return unit; 773 } 774 775 /* 776 * dlpiopen - open the DLPI device for a given interface name 777 */ 778 static int 779 dlpiopen(const char *ifname) { 780 char devname [50]; 781 char *dp; 782 const char *cp, *ep; 783 784 if (!ifname) { 785 return -1; 786 } 787 788 /* Open a DLPI device */ 789 if (*ifname == '/') { 790 dp = devname; 791 } else { 792 /* Prepend the device directory */ 793 memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR)); 794 dp = &devname [strlen (DLPI_DEVDIR)]; 795 } 796 797 /* Find the end of the interface name */ 798 ep = cp = ifname; 799 while (*ep) 800 ep++; 801 /* And back up to the first digit (unit number) */ 802 while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':') 803 ep--; 804 805 /* Copy everything up to the unit number */ 806 while (cp < ep) { 807 *dp++ = *cp++; 808 } 809 *dp = '\0'; 810 811 return open (devname, O_RDWR, 0); 812 } 813 814 /* 815 * dlpiinforeq - request information about the data link provider. 816 */ 817 818 static int dlpiinforeq (fd) 819 int fd; 820 { 821 dl_info_req_t info_req; 822 struct strbuf ctl; 823 int flags; 824 825 info_req.dl_primitive = DL_INFO_REQ; 826 827 ctl.maxlen = 0; 828 ctl.len = sizeof (info_req); 829 ctl.buf = (char *)&info_req; 830 831 flags = RS_HIPRI; 832 833 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags); 834 } 835 836 /* 837 * dlpiphysaddrreq - request the current physical address. 838 */ 839 static int dlpiphysaddrreq (fd, addrtype) 840 int fd; 841 unsigned long addrtype; 842 { 843 dl_phys_addr_req_t physaddr_req; 844 struct strbuf ctl; 845 int flags; 846 847 physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ; 848 physaddr_req.dl_addr_type = addrtype; 849 850 ctl.maxlen = 0; 851 ctl.len = sizeof (physaddr_req); 852 ctl.buf = (char *)&physaddr_req; 853 854 flags = RS_HIPRI; 855 856 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags); 857 } 858 859 /* 860 * dlpiattachreq - send a request to attach to a specific unit. 861 */ 862 static int dlpiattachreq (fd, ppa) 863 unsigned long ppa; 864 int fd; 865 { 866 dl_attach_req_t attach_req; 867 struct strbuf ctl; 868 int flags; 869 870 attach_req.dl_primitive = DL_ATTACH_REQ; 871 attach_req.dl_ppa = ppa; 872 873 ctl.maxlen = 0; 874 ctl.len = sizeof (attach_req); 875 ctl.buf = (char *)&attach_req; 876 877 flags = 0; 878 879 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); 880 } 881 882 /* 883 * dlpibindreq - send a request to bind to a specific SAP address. 884 */ 885 static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest) 886 unsigned long sap; 887 unsigned long max_conind; 888 unsigned long service_mode; 889 unsigned long conn_mgmt; 890 unsigned long xidtest; 891 int fd; 892 { 893 dl_bind_req_t bind_req; 894 struct strbuf ctl; 895 int flags; 896 897 bind_req.dl_primitive = DL_BIND_REQ; 898 bind_req.dl_sap = sap; 899 bind_req.dl_max_conind = max_conind; 900 bind_req.dl_service_mode = service_mode; 901 bind_req.dl_conn_mgmt = conn_mgmt; 902 bind_req.dl_xidtest_flg = xidtest; 903 904 ctl.maxlen = 0; 905 ctl.len = sizeof (bind_req); 906 ctl.buf = (char *)&bind_req; 907 908 flags = 0; 909 910 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); 911 } 912 913 #if defined(UNUSED_DLPI_INTERFACE) 914 /* 915 * dlpiunbindreq - send a request to unbind. This function is not actually 916 * used by ISC DHCP, but is included for completeness in case it is 917 * ever required for new work. 918 */ 919 static int dlpiunbindreq (fd) 920 int fd; 921 { 922 dl_unbind_req_t unbind_req; 923 struct strbuf ctl; 924 int flags; 925 926 unbind_req.dl_primitive = DL_UNBIND_REQ; 927 928 ctl.maxlen = 0; 929 ctl.len = sizeof (unbind_req); 930 ctl.buf = (char *)&unbind_req; 931 932 flags = 0; 933 934 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); 935 } 936 937 938 /* 939 * dlpidetachreq - send a request to detach. This function is not actually 940 * used by ISC DHCP, but is included for completeness in case it is 941 * ever required for new work. 942 */ 943 static int dlpidetachreq (fd) 944 int fd; 945 { 946 dl_detach_req_t detach_req; 947 struct strbuf ctl; 948 int flags; 949 950 detach_req.dl_primitive = DL_DETACH_REQ; 951 952 ctl.maxlen = 0; 953 ctl.len = sizeof (detach_req); 954 ctl.buf = (char *)&detach_req; 955 956 flags = 0; 957 958 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); 959 } 960 #endif /* UNUSED_DLPI_INTERFACE */ 961 962 963 /* 964 * dlpibindack - receive an ack to a dlbindreq. 965 */ 966 static int dlpibindack (fd, bufp) 967 char *bufp; 968 int fd; 969 { 970 union DL_primitives *dlp; 971 struct strbuf ctl; 972 int flags; 973 974 ctl.maxlen = DLPI_MAXDLBUF; 975 ctl.len = 0; 976 ctl.buf = bufp; 977 978 if (strgetmsg (fd, &ctl, 979 (struct strbuf*)NULL, &flags, "dlpibindack") < 0) { 980 return -1; 981 } 982 983 dlp = (union DL_primitives *)ctl.buf; 984 985 if (expected (DL_BIND_ACK, dlp, flags) == -1) { 986 return -1; 987 } 988 989 if (ctl.len < sizeof (dl_bind_ack_t)) { 990 /* Returned structure is too short */ 991 return -1; 992 } 993 994 return 0; 995 } 996 997 /* 998 * dlpiokack - general acknowledgement reception. 999 */ 1000 static int dlpiokack (fd, bufp) 1001 char *bufp; 1002 int fd; 1003 { 1004 union DL_primitives *dlp; 1005 struct strbuf ctl; 1006 int flags; 1007 1008 ctl.maxlen = DLPI_MAXDLBUF; 1009 ctl.len = 0; 1010 ctl.buf = bufp; 1011 1012 if (strgetmsg (fd, &ctl, 1013 (struct strbuf*)NULL, &flags, "dlpiokack") < 0) { 1014 return -1; 1015 } 1016 1017 dlp = (union DL_primitives *)ctl.buf; 1018 1019 if (expected (DL_OK_ACK, dlp, flags) == -1) { 1020 return -1; 1021 } 1022 1023 if (ctl.len < sizeof (dl_ok_ack_t)) { 1024 /* Returned structure is too short */ 1025 return -1; 1026 } 1027 1028 return 0; 1029 } 1030 1031 /* 1032 * dlpiinfoack - receive an ack to a dlinforeq. 1033 */ 1034 static int dlpiinfoack (fd, bufp) 1035 char *bufp; 1036 int fd; 1037 { 1038 union DL_primitives *dlp; 1039 struct strbuf ctl; 1040 int flags; 1041 1042 ctl.maxlen = DLPI_MAXDLBUF; 1043 ctl.len = 0; 1044 ctl.buf = bufp; 1045 1046 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags, 1047 "dlpiinfoack") < 0) { 1048 return -1; 1049 } 1050 1051 dlp = (union DL_primitives *) ctl.buf; 1052 1053 if (expected (DL_INFO_ACK, dlp, flags) == -1) { 1054 return -1; 1055 } 1056 1057 if (ctl.len < sizeof (dl_info_ack_t)) { 1058 /* Returned structure is too short */ 1059 return -1; 1060 } 1061 1062 return 0; 1063 } 1064 1065 /* 1066 * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq. 1067 */ 1068 int dlpiphysaddrack (fd, bufp) 1069 char *bufp; 1070 int fd; 1071 { 1072 union DL_primitives *dlp; 1073 struct strbuf ctl; 1074 int flags; 1075 1076 ctl.maxlen = DLPI_MAXDLBUF; 1077 ctl.len = 0; 1078 ctl.buf = bufp; 1079 1080 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags, 1081 "dlpiphysaddrack") < 0) { 1082 return -1; 1083 } 1084 1085 dlp = (union DL_primitives *)ctl.buf; 1086 1087 if (expected (DL_PHYS_ADDR_ACK, dlp, flags) == -1) { 1088 return -1; 1089 } 1090 1091 if (ctl.len < sizeof (dl_phys_addr_ack_t)) { 1092 /* Returned structure is too short */ 1093 return -1; 1094 } 1095 1096 return 0; 1097 } 1098 1099 #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE) 1100 int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen) 1101 int fd; 1102 unsigned char *addr; 1103 int addrlen; 1104 unsigned long minpri; 1105 unsigned long maxpri; 1106 unsigned char *dbuf; 1107 int dbuflen; 1108 { 1109 long buf [DLPI_MAXDLBUF]; 1110 union DL_primitives *dlp; 1111 struct strbuf ctl, data; 1112 1113 /* Set up the control information... */ 1114 dlp = (union DL_primitives *)buf; 1115 dlp -> unitdata_req.dl_primitive = DL_UNITDATA_REQ; 1116 dlp -> unitdata_req.dl_dest_addr_length = addrlen; 1117 dlp -> unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t); 1118 dlp -> unitdata_req.dl_priority.dl_min = minpri; 1119 dlp -> unitdata_req.dl_priority.dl_max = maxpri; 1120 1121 /* Append the destination address */ 1122 memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset, 1123 addr, addrlen); 1124 1125 ctl.maxlen = 0; 1126 ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen; 1127 ctl.buf = (char *)buf; 1128 1129 data.maxlen = 0; 1130 data.buf = (char *)dbuf; 1131 data.len = dbuflen; 1132 1133 /* Send the packet down the wire... */ 1134 return putmsg (fd, &ctl, &data, 0); 1135 } 1136 1137 static int dlpiunitdataind (fd, daddr, daddrlen, 1138 saddr, saddrlen, grpaddr, dbuf, dlen) 1139 int fd; 1140 unsigned char *daddr; 1141 unsigned long *daddrlen; 1142 unsigned char *saddr; 1143 unsigned long *saddrlen; 1144 unsigned long *grpaddr; 1145 unsigned char *dbuf; 1146 int dlen; 1147 { 1148 long buf [DLPI_MAXDLBUF]; 1149 union DL_primitives *dlp; 1150 struct strbuf ctl, data; 1151 int flags = 0; 1152 int result; 1153 1154 /* Set up the msg_buf structure... */ 1155 dlp = (union DL_primitives *)buf; 1156 dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND; 1157 1158 ctl.maxlen = DLPI_MAXDLBUF; 1159 ctl.len = 0; 1160 ctl.buf = (char *)buf; 1161 1162 data.maxlen = dlen; 1163 data.len = 0; 1164 data.buf = (char *)dbuf; 1165 1166 result = getmsg (fd, &ctl, &data, &flags); 1167 1168 if (result < 0) { 1169 log_debug("dlpiunitdataind: %m"); 1170 return -1; 1171 } 1172 1173 if (ctl.len < sizeof (dl_unitdata_ind_t) || 1174 dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) { 1175 return -1; 1176 } 1177 1178 if (data.len <= 0) { 1179 return data.len; 1180 } 1181 1182 /* Copy sender info */ 1183 if (saddr) { 1184 memcpy (saddr, 1185 (char *)buf + dlp -> unitdata_ind.dl_src_addr_offset, 1186 dlp -> unitdata_ind.dl_src_addr_length); 1187 } 1188 if (saddrlen) { 1189 *saddrlen = dlp -> unitdata_ind.dl_src_addr_length; 1190 } 1191 1192 /* Copy destination info */ 1193 if (daddr) { 1194 memcpy (daddr, 1195 (char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset, 1196 dlp -> unitdata_ind.dl_dest_addr_length); 1197 } 1198 if (daddrlen) { 1199 *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length; 1200 } 1201 1202 if (grpaddr) { 1203 *grpaddr = dlp -> unitdata_ind.dl_group_address; 1204 } 1205 1206 return data.len; 1207 } 1208 #endif /* !USE_DLPI_HWADDR: USE_DLPI_RECEIVE || USE_DLPI_SEND */ 1209 1210 /* 1211 * expected - see if we got what we wanted. 1212 */ 1213 static int expected (prim, dlp, msgflags) 1214 unsigned long prim; 1215 union DL_primitives *dlp; 1216 int msgflags; 1217 { 1218 if (msgflags != RS_HIPRI) { 1219 /* Message was not M_PCPROTO */ 1220 return -1; 1221 } 1222 1223 if (dlp->dl_primitive != prim) { 1224 /* Incorrect/unexpected return message */ 1225 return -1; 1226 } 1227 1228 return 0; 1229 } 1230 1231 /* 1232 * strgetmsg - get a message from a stream, with timeout. 1233 */ 1234 static int strgetmsg (fd, ctlp, datap, flagsp, caller) 1235 struct strbuf *ctlp, *datap; 1236 char *caller; 1237 int *flagsp; 1238 int fd; 1239 { 1240 int result; 1241 struct pollfd pfd; 1242 int count; 1243 time_t now; 1244 time_t starttime; 1245 int to_msec; 1246 1247 pfd.fd = fd; 1248 pfd.events = POLLPRI; /* We're only interested in knowing 1249 * when we can receive the next high 1250 * priority message. 1251 */ 1252 pfd.revents = 0; 1253 1254 now = time (&starttime); 1255 while (now <= starttime + DLPI_MAXWAIT) { 1256 to_msec = ((starttime + DLPI_MAXWAIT) - now) * 1000; 1257 count = poll (&pfd, 1, to_msec); 1258 1259 if (count == 0) { 1260 /* log_fatal ("strgetmsg: timeout"); */ 1261 return -1; 1262 } else if (count < 0) { 1263 if (errno == EAGAIN || errno == EINTR) { 1264 time (&now); 1265 continue; 1266 } else { 1267 /* log_fatal ("poll: %m"); */ 1268 return -1; 1269 } 1270 } else { 1271 break; 1272 } 1273 } 1274 1275 /* 1276 * Set flags argument and issue getmsg (). 1277 */ 1278 *flagsp = 0; 1279 if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) { 1280 return result; 1281 } 1282 1283 /* 1284 * Check for MOREDATA and/or MORECTL. 1285 */ 1286 if (result & (MORECTL|MOREDATA)) { 1287 return -1; 1288 } 1289 1290 /* 1291 * Check for at least sizeof (long) control data portion. 1292 */ 1293 if (ctlp -> len < sizeof (long)) { 1294 return -1; 1295 } 1296 1297 return 0; 1298 } 1299 1300 #if defined(USE_DLPI_SEND) 1301 int can_unicast_without_arp (ip) 1302 struct interface_info *ip; 1303 { 1304 return 1; 1305 } 1306 1307 int can_receive_unicast_unconfigured (ip) 1308 struct interface_info *ip; 1309 { 1310 return 1; 1311 } 1312 1313 int supports_multiple_interfaces (ip) 1314 struct interface_info *ip; 1315 { 1316 return 1; 1317 } 1318 1319 void maybe_setup_fallback () 1320 { 1321 isc_result_t status; 1322 struct interface_info *fbi = (struct interface_info *)0; 1323 if (setup_fallback (&fbi, MDL)) { 1324 if_register_fallback (fbi); 1325 status = omapi_register_io_object ((omapi_object_t *)fbi, 1326 if_readsocket, 0, 1327 fallback_discard, 0, 0); 1328 if (status != ISC_R_SUCCESS) 1329 log_fatal ("Can't register I/O handle for %s: %s", 1330 fbi -> name, isc_result_totext (status)); 1331 interface_dereference (&fbi, MDL); 1332 } 1333 } 1334 #endif /* USE_DLPI_SEND */ 1335 1336 void 1337 get_hw_addr(const char *name, struct hardware *hw) { 1338 int sock, unit; 1339 long buf[DLPI_MAXDLBUF]; 1340 union DL_primitives *dlp; 1341 1342 dlp = (union DL_primitives *)buf; 1343 1344 /* 1345 * Open a DLPI device. 1346 */ 1347 sock = dlpiopen(name); 1348 if (sock < 0) { 1349 log_fatal("Can't open DLPI device for %s: %m", name); 1350 } 1351 1352 /* 1353 * Submit a DL_INFO_REQ request, to find the dl_mac_type and 1354 * dl_provider_style 1355 */ 1356 if (dlpiinforeq(sock) < 0) { 1357 log_fatal("Can't request DLPI MAC type for %s: %m", name); 1358 } 1359 if (dlpiinfoack(sock, (char *)buf) < 0) { 1360 log_fatal("Can't get DLPI MAC type for %s: %m", name); 1361 } 1362 switch (dlp->info_ack.dl_mac_type) { 1363 case DL_CSMACD: /* IEEE 802.3 */ 1364 case DL_ETHER: 1365 hw->hbuf[0] = HTYPE_ETHER; 1366 break; 1367 case DL_TPR: 1368 hw->hbuf[0] = HTYPE_IEEE802; 1369 break; 1370 case DL_FDDI: 1371 hw->hbuf[0] = HTYPE_FDDI; 1372 break; 1373 default: 1374 log_fatal("%s: unsupported DLPI MAC type %lu", name, 1375 (unsigned long)dlp->info_ack.dl_mac_type); 1376 } 1377 1378 if (dlp->info_ack.dl_provider_style == DL_STYLE2) { 1379 /* 1380 * Attach to the device. If this fails, the device 1381 * does not exist. 1382 */ 1383 unit = dlpiunit((char *)name); 1384 1385 if (dlpiattachreq(sock, unit) < 0 || 1386 dlpiokack(sock, (char *)buf) < 0) { 1387 log_fatal("Can't attach DLPI device for %s: %m", 1388 name); 1389 } 1390 } 1391 1392 /* 1393 * Submit a DL_PHYS_ADDR_REQ request, to find 1394 * the hardware address. 1395 */ 1396 if (dlpiphysaddrreq(sock, DL_CURR_PHYS_ADDR) < 0) { 1397 log_fatal("Can't request DLPI hardware address for %s: %m", 1398 name); 1399 } 1400 if (dlpiphysaddrack(sock, (char *)buf) < 0) { 1401 log_fatal("Can't get DLPI hardware address for %s: %m", 1402 name); 1403 } 1404 if (dlp->physaddr_ack.dl_addr_length < sizeof(hw->hbuf)) { 1405 memcpy(hw->hbuf+1, 1406 (char *)buf + dlp->physaddr_ack.dl_addr_offset, 1407 dlp->physaddr_ack.dl_addr_length); 1408 hw->hlen = dlp->physaddr_ack.dl_addr_length + 1; 1409 } else { 1410 memcpy(hw->hbuf+1, 1411 (char *)buf + dlp->physaddr_ack.dl_addr_offset, 1412 sizeof(hw->hbuf)-1); 1413 hw->hlen = sizeof(hw->hbuf); 1414 } 1415 1416 close(sock); 1417 } 1418 #endif /* USE_DLPI_SEND || USE_DLPI_RECEIVE || USE_DLPI_HWADDR */ 1419