]> git.ipfire.org Git - thirdparty/dhcp.git/blame - common/lpf.c
[#189] Whitespace fixes in opened files
[thirdparty/dhcp.git] / common / lpf.c
CommitLineData
31c08e37
TL
1/* lpf.c
2
3 Linux packet filter code, contributed by Brian Murrel at Interlinx
4 Support Services in Vancouver, B.C. */
5
6/*
7512d88b 7 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
98311e4b 8 * Copyright (c) 1996-2003 by Internet Software Consortium
31c08e37 9 *
7512d88b
TM
10 * This Source Code Form is subject to the terms of the Mozilla Public
11 * License, v. 2.0. If a copy of the MPL was not distributed with this
12 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
31c08e37 13 *
98311e4b
DH
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31c08e37 21 *
98311e4b 22 * Internet Systems Consortium, Inc.
429a56d7
TM
23 * PO Box 360
24 * Newmarket, NH 03857 USA
98311e4b 25 * <info@isc.org>
2c85ac9b 26 * https://www.isc.org/
31c08e37
TL
27 */
28
31c08e37
TL
29#include "dhcpd.h"
30#if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
31c08e37 31#include <sys/uio.h>
fe5b0fdd 32#include <errno.h>
31c08e37 33
2dddca22
TL
34#include <asm/types.h>
35#include <linux/filter.h>
36#include <linux/if_ether.h>
7ff6ae5a 37#include <linux/if_packet.h>
31c08e37
TL
38#include <netinet/in_systm.h>
39#include "includes/netinet/ip.h"
40#include "includes/netinet/udp.h"
41#include "includes/netinet/if_ether.h"
32e651c4
SR
42#endif
43
44#if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
45#include <sys/ioctl.h>
7ff6ae5a 46#include <sys/socket.h>
98bd7ca0 47#include <net/if.h>
32e651c4 48#endif
31c08e37 49
32e651c4 50#if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
31c08e37
TL
51/* Reinitializes the specified interface after an address change. This
52 is not required for packet-filter APIs. */
53
54#ifdef USE_LPF_SEND
55void if_reinitialize_send (info)
56 struct interface_info *info;
57{
58}
59#endif
60
61#ifdef USE_LPF_RECEIVE
62void if_reinitialize_receive (info)
63 struct interface_info *info;
64{
65}
66#endif
67
68/* Called by get_interface_list for each interface that's discovered.
69 Opens a packet filter for each interface and adds it to the select
70 mask. */
71
72int if_register_lpf (info)
73 struct interface_info *info;
74{
75 int sock;
7ff6ae5a
TM
76 union {
77 struct sockaddr_ll ll;
78 struct sockaddr common;
79 } sa;
80 struct ifreq ifr;
31c08e37
TL
81
82 /* Make an LPF socket. */
7ff6ae5a 83 if ((sock = socket(PF_PACKET, SOCK_RAW,
6ceb9118 84 htons((short)ETH_P_ALL))) < 0) {
2dddca22
TL
85 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
86 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
6ceb9118
TL
87 errno == EAFNOSUPPORT || errno == EINVAL) {
88 log_error ("socket: %m - make sure");
89 log_error ("CONFIG_PACKET (Packet socket) %s",
90 "and CONFIG_FILTER");
91 log_error ("(Socket Filtering) are enabled %s",
92 "in your kernel");
93 log_fatal ("configuration!");
94 }
0536c3ef 95 log_fatal ("Open a socket for LPF: %m");
2dddca22 96 }
31c08e37 97
7ff6ae5a
TM
98 memset (&ifr, 0, sizeof ifr);
99 strncpy (ifr.ifr_name, (const char *)info -> ifp, sizeof ifr.ifr_name);
100 ifr.ifr_name[IFNAMSIZ-1] = '\0';
101 if (ioctl (sock, SIOCGIFINDEX, &ifr))
102 log_fatal ("Failed to get interface index: %m");
103
31c08e37
TL
104 /* Bind to the interface name */
105 memset (&sa, 0, sizeof sa);
7ff6ae5a
TM
106 sa.ll.sll_family = AF_PACKET;
107 sa.ll.sll_ifindex = ifr.ifr_ifindex;
108 if (bind (sock, &sa.common, sizeof sa)) {
2dddca22
TL
109 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
110 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
6ceb9118
TL
111 errno == EAFNOSUPPORT || errno == EINVAL) {
112 log_error ("socket: %m - make sure");
113 log_error ("CONFIG_PACKET (Packet socket) %s",
114 "and CONFIG_FILTER");
115 log_error ("(Socket Filtering) are enabled %s",
116 "in your kernel");
117 log_fatal ("configuration!");
118 }
0536c3ef 119 log_fatal ("Bind socket to interface: %m");
36e2c224 120
2dddca22 121 }
31c08e37 122
4ba58919
DH
123 get_hw_addr(info->name, &info->hw_address);
124
31c08e37
TL
125 return sock;
126}
127#endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
128
129#ifdef USE_LPF_SEND
130void if_register_send (info)
131 struct interface_info *info;
132{
133 /* If we're using the lpf API for sending and receiving,
134 we don't need to register this interface twice. */
135#ifndef USE_LPF_RECEIVE
bdcaf7b9 136 info -> wfdesc = if_register_lpf (info);
31c08e37
TL
137#else
138 info -> wfdesc = info -> rfdesc;
139#endif
140 if (!quiet_interface_discovery)
74f45f96 141 log_info ("Sending on LPF/%s/%s%s%s",
31c08e37 142 info -> name,
d4feef65
TL
143 print_hw_addr (info -> hw_address.hbuf [0],
144 info -> hw_address.hlen - 1,
145 &info -> hw_address.hbuf [1]),
74f45f96 146 (info -> shared_network ? "/" : ""),
31c08e37 147 (info -> shared_network ?
74f45f96 148 info -> shared_network -> name : ""));
31c08e37 149}
bdcaf7b9
TL
150
151void if_deregister_send (info)
152 struct interface_info *info;
153{
154 /* don't need to close twice if we are using lpf for sending and
155 receiving */
156#ifndef USE_LPF_RECEIVE
157 /* for LPF this is simple, packet filters are removed when sockets
158 are closed */
159 close (info -> wfdesc);
160#endif
7203e8ee 161 info -> wfdesc = -1;
bdcaf7b9 162 if (!quiet_interface_discovery)
7203e8ee 163 log_info ("Disabling output on LPF/%s/%s%s%s",
bdcaf7b9
TL
164 info -> name,
165 print_hw_addr (info -> hw_address.hbuf [0],
166 info -> hw_address.hlen - 1,
167 &info -> hw_address.hbuf [1]),
168 (info -> shared_network ? "/" : ""),
169 (info -> shared_network ?
170 info -> shared_network -> name : ""));
171}
31c08e37
TL
172#endif /* USE_LPF_SEND */
173
174#ifdef USE_LPF_RECEIVE
175/* Defined in bpf.c. We can't extern these in dhcpd.h without pulling
176 in bpf includes... */
2dddca22 177extern struct sock_filter dhcp_bpf_filter [];
31c08e37 178extern int dhcp_bpf_filter_len;
e31656de 179
563f0b8a
FD
180#if defined(RELAY_PORT)
181extern struct sock_filter dhcp_bpf_relay_filter [];
182extern int dhcp_bpf_relay_filter_len;
183#endif
184
e31656de 185#if defined (HAVE_TR_SUPPORT)
7d29d66d
TL
186extern struct sock_filter dhcp_bpf_tr_filter [];
187extern int dhcp_bpf_tr_filter_len;
e31656de
TL
188static void lpf_tr_filter_setup (struct interface_info *);
189#endif
31c08e37 190
c4906ac0 191static void lpf_gen_filter_setup (struct interface_info *);
c4906ac0 192
31c08e37
TL
193void if_register_receive (info)
194 struct interface_info *info;
195{
196 /* Open a LPF device and hang it on this interface... */
197 info -> rfdesc = if_register_lpf (info);
198
7ff6ae5a
TM
199#ifdef PACKET_AUXDATA
200 {
201 int val = 1;
202
203 if (setsockopt(info->rfdesc, SOL_PACKET, PACKET_AUXDATA,
204 &val, sizeof(val)) < 0) {
205 if (errno != ENOPROTOOPT) {
206 log_fatal ("Failed to set auxiliary packet data: %m");
207 }
208 }
209 }
210#endif
211
212
e31656de 213#if defined (HAVE_TR_SUPPORT)
254f9d79 214 if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
7d29d66d
TL
215 lpf_tr_filter_setup (info);
216 else
e31656de 217#endif
7d29d66d
TL
218 lpf_gen_filter_setup (info);
219
220 if (!quiet_interface_discovery)
b733ed10
TL
221 log_info ("Listening on LPF/%s/%s%s%s",
222 info -> name,
d4feef65
TL
223 print_hw_addr (info -> hw_address.hbuf [0],
224 info -> hw_address.hlen - 1,
225 &info -> hw_address.hbuf [1]),
b733ed10
TL
226 (info -> shared_network ? "/" : ""),
227 (info -> shared_network ?
228 info -> shared_network -> name : ""));
7d29d66d
TL
229}
230
bdcaf7b9
TL
231void if_deregister_receive (info)
232 struct interface_info *info;
233{
234 /* for LPF this is simple, packet filters are removed when sockets
235 are closed */
236 close (info -> rfdesc);
7203e8ee 237 info -> rfdesc = -1;
bdcaf7b9 238 if (!quiet_interface_discovery)
7203e8ee 239 log_info ("Disabling input on LPF/%s/%s%s%s",
bdcaf7b9
TL
240 info -> name,
241 print_hw_addr (info -> hw_address.hbuf [0],
242 info -> hw_address.hlen - 1,
243 &info -> hw_address.hbuf [1]),
244 (info -> shared_network ? "/" : ""),
245 (info -> shared_network ?
246 info -> shared_network -> name : ""));
247}
248
7d29d66d
TL
249static void lpf_gen_filter_setup (info)
250 struct interface_info *info;
251{
252 struct sock_fprog p;
253
4619c0a2
DH
254 memset(&p, 0, sizeof(p));
255
31c08e37
TL
256 /* Set up the bpf filter program structure. This is defined in
257 bpf.c */
2dddca22
TL
258 p.len = dhcp_bpf_filter_len;
259 p.filter = dhcp_bpf_filter;
31c08e37
TL
260
261 /* Patch the server port into the LPF program...
262 XXX changes to filter program may require changes
263 to the insn number(s) used below! XXX */
563f0b8a
FD
264#if defined(RELAY_PORT)
265 if (relay_port) {
266 /*
267 * If user defined relay UDP port, we need to filter
268 * also on the user UDP port.
269 */
270 p.len = dhcp_bpf_relay_filter_len;
271 p.filter = dhcp_bpf_relay_filter;
272
273 dhcp_bpf_relay_filter [10].k = ntohs (relay_port);
274 }
275#endif
276 dhcp_bpf_filter [8].k = ntohs (local_port);
31c08e37
TL
277
278 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
2dddca22
TL
279 sizeof p) < 0) {
280 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
281 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
6ceb9118
TL
282 errno == EAFNOSUPPORT) {
283 log_error ("socket: %m - make sure");
284 log_error ("CONFIG_PACKET (Packet socket) %s",
285 "and CONFIG_FILTER");
286 log_error ("(Socket Filtering) are enabled %s",
287 "in your kernel");
288 log_fatal ("configuration!");
289 }
fd6f298f 290 log_fatal ("Can't install packet filter program: %m");
7d29d66d
TL
291 }
292}
293
e31656de 294#if defined (HAVE_TR_SUPPORT)
7d29d66d
TL
295static void lpf_tr_filter_setup (info)
296 struct interface_info *info;
297{
298 struct sock_fprog p;
299
819186b7
DH
300 memset(&p, 0, sizeof(p));
301
7d29d66d
TL
302 /* Set up the bpf filter program structure. This is defined in
303 bpf.c */
304 p.len = dhcp_bpf_tr_filter_len;
305 p.filter = dhcp_bpf_tr_filter;
306
307 /* Patch the server port into the LPF program...
308 XXX changes to filter program may require changes
309 XXX to the insn number(s) used below!
f6b8f48d 310 XXX Token ring filter is null - when/if we have a filter
7d29d66d
TL
311 XXX that's not, we'll need this code.
312 XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
313
314 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
315 sizeof p) < 0) {
316 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
317 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
6ceb9118
TL
318 errno == EAFNOSUPPORT) {
319 log_error ("socket: %m - make sure");
320 log_error ("CONFIG_PACKET (Packet socket) %s",
321 "and CONFIG_FILTER");
322 log_error ("(Socket Filtering) are enabled %s",
323 "in your kernel");
324 log_fatal ("configuration!");
325 }
fd6f298f 326 log_fatal ("Can't install packet filter program: %m");
2dddca22 327 }
31c08e37 328}
e31656de 329#endif /* HAVE_TR_SUPPORT */
31c08e37
TL
330#endif /* USE_LPF_RECEIVE */
331
332#ifdef USE_LPF_SEND
333ssize_t send_packet (interface, packet, raw, len, from, to, hto)
334 struct interface_info *interface;
335 struct packet *packet;
336 struct dhcp_packet *raw;
337 size_t len;
338 struct in_addr from;
339 struct sockaddr_in *to;
340 struct hardware *hto;
341{
6ceb9118
TL
342 unsigned hbufp = 0, ibufp = 0;
343 double hh [16];
344 double ih [1536 / sizeof (double)];
345 unsigned char *buf = (unsigned char *)ih;
74f45f96 346 int result;
6ceb9118 347 int fudge;
31c08e37
TL
348
349 if (!strcmp (interface -> name, "fallback"))
350 return send_fallback (interface, packet, raw,
351 len, from, to, hto);
352
0829d595
DH
353 if (hto == NULL && interface->anycast_mac_addr.hlen)
354 hto = &interface->anycast_mac_addr;
355
31c08e37 356 /* Assemble the headers... */
6ceb9118
TL
357 assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto);
358 fudge = hbufp % 4; /* IP header must be word-aligned. */
359 memcpy (buf + fudge, (unsigned char *)hh, hbufp);
360 ibufp = hbufp + fudge;
361 assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
31c08e37
TL
362 to -> sin_addr.s_addr, to -> sin_port,
363 (unsigned char *)raw, len);
6ceb9118 364 memcpy (buf + ibufp, raw, len);
7ff6ae5a 365 result = write(interface->wfdesc, buf + fudge, ibufp + len - fudge);
74f45f96 366 if (result < 0)
c5b0f529 367 log_error ("send_packet: %m");
74f45f96 368 return result;
31c08e37
TL
369}
370#endif /* USE_LPF_SEND */
371
372#ifdef USE_LPF_RECEIVE
373ssize_t receive_packet (interface, buf, len, from, hfrom)
374 struct interface_info *interface;
375 unsigned char *buf;
376 size_t len;
377 struct sockaddr_in *from;
378 struct hardware *hfrom;
379{
31c08e37
TL
380 int length = 0;
381 int offset = 0;
7ff6ae5a 382 int csum_ready = 1;
05dcd093 383 unsigned char ibuf [1536];
6ceb9118 384 unsigned bufix = 0;
83c0372e 385 unsigned paylen;
7ff6ae5a
TM
386 struct iovec iov = {
387 .iov_base = ibuf,
388 .iov_len = sizeof ibuf,
389 };
1c0b7d66
SR
390#ifdef PACKET_AUXDATA
391 /*
392 * We only need cmsgbuf if we are getting the aux data and we
393 * only get the auxdata if it is actually defined
394 */
395 unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
7ff6ae5a
TM
396 struct msghdr msg = {
397 .msg_iov = &iov,
398 .msg_iovlen = 1,
399 .msg_control = cmsgbuf,
400 .msg_controllen = sizeof(cmsgbuf),
401 };
1c0b7d66
SR
402#else
403 struct msghdr msg = {
404 .msg_iov = &iov,
405 .msg_iovlen = 1,
406 .msg_control = NULL,
407 .msg_controllen = 0,
408 };
409#endif /* PACKET_AUXDATA */
7ff6ae5a
TM
410
411 length = recvmsg (interface->rfdesc, &msg, 0);
31c08e37
TL
412 if (length <= 0)
413 return length;
414
7ff6ae5a
TM
415#ifdef PACKET_AUXDATA
416 {
acbecb2e
TM
417 /* Use auxiliary packet data to:
418 *
419 * a. Weed out extraneous VLAN-tagged packets - If the NIC driver is
420 * handling VLAN encapsulation (i.e. stripping/adding VLAN tags),
421 * then an inbound VLAN packet will be seen twice: Once by
422 * the parent interface (e.g. eth0) with a VLAN tag != 0; and once
423 * by the vlan interface (e.g. eth0.n) with a VLAN tag of 0 (i.e none).
424 * We want to discard the packet sent to the parent and thus respond
425 * only over the vlan interface. (Drivers for Intel PRO/1000 series
426 * NICs perform VLAN encapsulation, while drivers for PCnet series
427 * do not, for example. The linux kernel makes stripped vlan info
428 * visible to user space via CMSG/auxdata, this appears to not be
75d02fcf
TM
429 * true for BSD OSs.). NOTE: this is only supported on linux flavors
430 * which define the tpacket_auxdata.tp_vlan_tci.
acbecb2e
TM
431 *
432 * b. Determine if checksum is valid for use. It may not be if
433 * checksum offloading is enabled on the interface. */
7ff6ae5a
TM
434 struct cmsghdr *cmsg;
435
436 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
437 if (cmsg->cmsg_level == SOL_PACKET &&
438 cmsg->cmsg_type == PACKET_AUXDATA) {
439 struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
75d02fcf 440#ifdef VLAN_TCI_PRESENT
f10cbbfa
TM
441 /* Discard packets with stripped vlan id */
442 /* VLAN ID is only bottom 12-bits of TCI */
443 if (aux->tp_vlan_tci & 0x0fff)
acbecb2e 444 return 0;
75d02fcf 445#endif
acbecb2e 446
7ff6ae5a
TM
447 csum_ready = ((aux->tp_status & TP_STATUS_CSUMNOTREADY)
448 ? 0 : 1);
449 }
450 }
451
452 }
1c0b7d66 453#endif /* PACKET_AUXDATA */
7ff6ae5a 454
2dddca22 455 bufix = 0;
31c08e37
TL
456 /* Decode the physical header... */
457 offset = decode_hw_header (interface, ibuf, bufix, hfrom);
458
459 /* If a physical layer checksum failed (dunno of any
460 physical layer that supports this, but WTH), skip this
461 packet. */
462 if (offset < 0) {
463 return 0;
464 }
465
466 bufix += offset;
467 length -= offset;
468
469 /* Decode the IP and UDP headers... */
6ceb9118 470 offset = decode_udp_ip_header (interface, ibuf, bufix, from,
7ff6ae5a 471 (unsigned)length, &paylen, csum_ready);
31c08e37
TL
472
473 /* If the IP or UDP checksum was bad, skip the packet... */
474 if (offset < 0)
475 return 0;
476
477 bufix += offset;
478 length -= offset;
479
83c0372e
EH
480 if (length < paylen)
481 log_fatal("Internal inconsistency at %s:%d.", MDL);
482
31c08e37 483 /* Copy out the data in the packet... */
83c0372e
EH
484 memcpy(buf, &ibuf[bufix], paylen);
485 return paylen;
31c08e37
TL
486}
487
21d21e91
TL
488int can_unicast_without_arp (ip)
489 struct interface_info *ip;
31c08e37
TL
490{
491 return 1;
492}
493
21d21e91
TL
494int can_receive_unicast_unconfigured (ip)
495 struct interface_info *ip;
b547818b
TL
496{
497 return 1;
498}
499
5cefe5e5
TL
500int supports_multiple_interfaces (ip)
501 struct interface_info *ip;
502{
503 return 1;
504}
505
31c08e37
TL
506void maybe_setup_fallback ()
507{
acc21512 508 isc_result_t status;
20916cae
TL
509 struct interface_info *fbi = (struct interface_info *)0;
510 if (setup_fallback (&fbi, MDL)) {
31c08e37 511 if_register_fallback (fbi);
e92653f1 512 status = omapi_register_io_object ((omapi_object_t *)fbi,
acc21512
TL
513 if_readsocket, 0,
514 fallback_discard, 0, 0);
515 if (status != ISC_R_SUCCESS)
98bd7ca0 516 log_fatal ("Can't register I/O handle for \"%s\": %s",
acc21512 517 fbi -> name, isc_result_totext (status));
68e1f67a 518 interface_dereference (&fbi, MDL);
31c08e37
TL
519 }
520}
32e651c4 521#endif
98bd7ca0 522
32e651c4 523#if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
98bd7ca0
DH
524void
525get_hw_addr(const char *name, struct hardware *hw) {
526 int sock;
527 struct ifreq tmp;
528 struct sockaddr *sa;
529
530 if (strlen(name) >= sizeof(tmp.ifr_name)) {
531 log_fatal("Device name too long: \"%s\"", name);
532 }
533
534 sock = socket(AF_INET, SOCK_DGRAM, 0);
535 if (sock < 0) {
536 log_fatal("Can't create socket for \"%s\": %m", name);
537 }
538
539 memset(&tmp, 0, sizeof(tmp));
540 strcpy(tmp.ifr_name, name);
541 if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
f6b8f48d 542 log_fatal("Error getting hardware address for \"%s\": %m",
98bd7ca0
DH
543 name);
544 }
545
546 sa = &tmp.ifr_hwaddr;
547 switch (sa->sa_family) {
548 case ARPHRD_ETHER:
549 hw->hlen = 7;
550 hw->hbuf[0] = HTYPE_ETHER;
551 memcpy(&hw->hbuf[1], sa->sa_data, 6);
552 break;
553 case ARPHRD_IEEE802:
99fe695e 554#ifdef ARPHRD_IEEE802_TR
98bd7ca0 555 case ARPHRD_IEEE802_TR:
99fe695e 556#endif /* ARPHRD_IEEE802_TR */
98bd7ca0
DH
557 hw->hlen = 7;
558 hw->hbuf[0] = HTYPE_IEEE802;
559 memcpy(&hw->hbuf[1], sa->sa_data, 6);
560 break;
561 case ARPHRD_FDDI:
0f750c4f 562 hw->hlen = 7;
98bd7ca0 563 hw->hbuf[0] = HTYPE_FDDI;
0f750c4f 564 memcpy(&hw->hbuf[1], sa->sa_data, 6);
98bd7ca0
DH
565 break;
566 default:
567 log_fatal("Unsupported device type %ld for \"%s\"",
28868515 568 (long int)sa->sa_family, name);
98bd7ca0
DH
569 }
570
571 close(sock);
572}
31c08e37 573#endif