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