Line data Source code
1 : /* $OpenBSD: if_ethersubr.c,v 1.253 2018/03/13 01:31:48 dlg Exp $ */
2 : /* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */
3 :
4 : /*
5 : * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * 3. Neither the name of the project nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : */
32 :
33 : /*
34 : * Copyright (c) 1982, 1989, 1993
35 : * The Regents of the University of California. All rights reserved.
36 : *
37 : * Redistribution and use in source and binary forms, with or without
38 : * modification, are permitted provided that the following conditions
39 : * are met:
40 : * 1. Redistributions of source code must retain the above copyright
41 : * notice, this list of conditions and the following disclaimer.
42 : * 2. Redistributions in binary form must reproduce the above copyright
43 : * notice, this list of conditions and the following disclaimer in the
44 : * documentation and/or other materials provided with the distribution.
45 : * 3. Neither the name of the University nor the names of its contributors
46 : * may be used to endorse or promote products derived from this software
47 : * without specific prior written permission.
48 : *
49 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 : * SUCH DAMAGE.
60 : *
61 : * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93
62 : */
63 :
64 : /*
65 : %%% portions-copyright-nrl-95
66 : Portions of this software are Copyright 1995-1998 by Randall Atkinson,
67 : Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
68 : Reserved. All rights under this copyright have been assigned to the US
69 : Naval Research Laboratory (NRL). The NRL Copyright Notice and License
70 : Agreement Version 1.1 (January 17, 1995) applies to these portions of the
71 : software.
72 : You should have received a copy of the license with this software. If you
73 : didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
74 : */
75 :
76 : #include "bpfilter.h"
77 :
78 : #include <sys/param.h>
79 : #include <sys/systm.h>
80 : #include <sys/kernel.h>
81 : #include <sys/malloc.h>
82 : #include <sys/mbuf.h>
83 : #include <sys/protosw.h>
84 : #include <sys/socket.h>
85 : #include <sys/ioctl.h>
86 : #include <sys/errno.h>
87 : #include <sys/syslog.h>
88 : #include <sys/timeout.h>
89 :
90 : #include <net/if.h>
91 : #include <net/netisr.h>
92 : #include <net/route.h>
93 : #include <net/if_llc.h>
94 : #include <net/if_dl.h>
95 : #include <net/if_media.h>
96 : #include <net/if_types.h>
97 :
98 : #include <netinet/in.h>
99 : #include <netinet/if_ether.h>
100 : #include <netinet/ip_ipsp.h>
101 :
102 : #if NBPFILTER > 0
103 : #include <net/bpf.h>
104 : #endif
105 :
106 : #include "pppoe.h"
107 : #if NPPPOE > 0
108 : #include <net/if_pppoe.h>
109 : #endif
110 :
111 : #ifdef INET6
112 : #include <netinet6/in6_var.h>
113 : #include <netinet6/nd6.h>
114 : #endif
115 :
116 : #ifdef PIPEX
117 : #include <net/pipex.h>
118 : #endif
119 :
120 : #ifdef MPLS
121 : #include <netmpls/mpls.h>
122 : #endif /* MPLS */
123 :
124 : u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] =
125 : { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
126 : u_int8_t etheranyaddr[ETHER_ADDR_LEN] =
127 : { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
128 : #define senderr(e) { error = (e); goto bad;}
129 :
130 : int
131 0 : ether_ioctl(struct ifnet *ifp, struct arpcom *arp, u_long cmd, caddr_t data)
132 : {
133 0 : struct ifreq *ifr = (struct ifreq *)data;
134 : int error = 0;
135 :
136 0 : switch (cmd) {
137 : case SIOCSIFADDR:
138 : break;
139 :
140 : case SIOCSIFMTU:
141 0 : if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu)
142 0 : error = EINVAL;
143 : else
144 0 : ifp->if_mtu = ifr->ifr_mtu;
145 : break;
146 :
147 : case SIOCADDMULTI:
148 : case SIOCDELMULTI:
149 0 : if (ifp->if_flags & IFF_MULTICAST) {
150 0 : error = (cmd == SIOCADDMULTI) ?
151 0 : ether_addmulti(ifr, arp) :
152 0 : ether_delmulti(ifr, arp);
153 0 : } else
154 : error = ENOTTY;
155 : break;
156 :
157 : default:
158 : error = ENOTTY;
159 0 : }
160 :
161 0 : return (error);
162 : }
163 :
164 :
165 : void
166 0 : ether_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt)
167 : {
168 0 : switch (rt_key(rt)->sa_family) {
169 : case AF_INET:
170 0 : arp_rtrequest(ifp, req, rt);
171 0 : break;
172 : #ifdef INET6
173 : case AF_INET6:
174 0 : nd6_rtrequest(ifp, req, rt);
175 0 : break;
176 : #endif
177 : default:
178 : break;
179 : }
180 0 : }
181 : /*
182 : * Ethernet output routine.
183 : * Encapsulate a packet of type family for the local net.
184 : * Assumes that ifp is actually pointer to arpcom structure.
185 : */
186 : int
187 0 : ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
188 : struct rtentry *rt)
189 : {
190 : u_int16_t etype;
191 0 : u_char edst[ETHER_ADDR_LEN];
192 : u_char *esrc;
193 : struct mbuf *mcopy = NULL;
194 : struct ether_header *eh;
195 0 : struct arpcom *ac = (struct arpcom *)ifp;
196 0 : sa_family_t af = dst->sa_family;
197 : int error = 0;
198 :
199 0 : KASSERT(rt != NULL || ISSET(m->m_flags, M_MCAST|M_BCAST) ||
200 : af == AF_UNSPEC || af == pseudo_AF_HDRCMPLT);
201 :
202 : #ifdef DIAGNOSTIC
203 0 : if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) {
204 0 : printf("%s: trying to send packet on wrong domain. "
205 0 : "if %d vs. mbuf %d\n", ifp->if_xname,
206 0 : ifp->if_rdomain, rtable_l2(m->m_pkthdr.ph_rtableid));
207 0 : }
208 : #endif
209 :
210 0 : esrc = ac->ac_enaddr;
211 :
212 0 : if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
213 0 : senderr(ENETDOWN);
214 :
215 0 : switch (af) {
216 : case AF_INET:
217 0 : error = arpresolve(ifp, rt, m, dst, edst);
218 0 : if (error)
219 0 : return (error == EAGAIN ? 0 : error);
220 : /* If broadcasting on a simplex interface, loopback a copy */
221 0 : if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
222 0 : !m->m_pkthdr.pf.routed)
223 0 : mcopy = m_copym(m, 0, M_COPYALL, M_NOWAIT);
224 : etype = htons(ETHERTYPE_IP);
225 0 : break;
226 : #ifdef INET6
227 : case AF_INET6:
228 0 : error = nd6_resolve(ifp, rt, m, dst, edst);
229 0 : if (error)
230 0 : return (error == EAGAIN ? 0 : error);
231 : etype = htons(ETHERTYPE_IPV6);
232 0 : break;
233 : #endif
234 : #ifdef MPLS
235 : case AF_MPLS:
236 0 : if (rt)
237 0 : dst = rt_key(rt);
238 : else
239 0 : senderr(EHOSTUNREACH);
240 :
241 0 : if (!ISSET(ifp->if_xflags, IFXF_MPLS))
242 0 : senderr(ENETUNREACH);
243 :
244 0 : switch (dst->sa_family) {
245 : case AF_LINK:
246 0 : if (satosdl(dst)->sdl_alen < sizeof(edst))
247 0 : senderr(EHOSTUNREACH);
248 0 : memcpy(edst, LLADDR(satosdl(dst)),
249 : sizeof(edst));
250 0 : break;
251 : #ifdef INET6
252 : case AF_INET6:
253 0 : error = nd6_resolve(ifp, rt, m, dst, edst);
254 0 : if (error)
255 0 : return (error == EAGAIN ? 0 : error);
256 : break;
257 : #endif
258 : case AF_INET:
259 : case AF_MPLS:
260 0 : error = arpresolve(ifp, rt, m, dst, edst);
261 0 : if (error)
262 0 : return (error == EAGAIN ? 0 : error);
263 : break;
264 : default:
265 0 : senderr(EHOSTUNREACH);
266 : }
267 : /* XXX handling for simplex devices in case of M/BCAST ?? */
268 0 : if (m->m_flags & (M_BCAST | M_MCAST))
269 0 : etype = htons(ETHERTYPE_MPLS_MCAST);
270 : else
271 : etype = htons(ETHERTYPE_MPLS);
272 : break;
273 : #endif /* MPLS */
274 : case pseudo_AF_HDRCMPLT:
275 0 : eh = (struct ether_header *)dst->sa_data;
276 0 : esrc = eh->ether_shost;
277 : /* FALLTHROUGH */
278 :
279 : case AF_UNSPEC:
280 0 : eh = (struct ether_header *)dst->sa_data;
281 0 : memcpy(edst, eh->ether_dhost, sizeof(edst));
282 : /* AF_UNSPEC doesn't swap the byte order of the ether_type. */
283 0 : etype = eh->ether_type;
284 0 : break;
285 :
286 : default:
287 0 : printf("%s: can't handle af%d\n", ifp->if_xname,
288 0 : dst->sa_family);
289 0 : senderr(EAFNOSUPPORT);
290 : }
291 :
292 : /* XXX Should we feed-back an unencrypted IPsec packet ? */
293 0 : if (mcopy)
294 0 : if_input_local(ifp, mcopy, dst->sa_family);
295 :
296 0 : M_PREPEND(m, sizeof(struct ether_header) + ETHER_ALIGN, M_DONTWAIT);
297 0 : if (m == NULL)
298 0 : return (ENOBUFS);
299 0 : m_adj(m, ETHER_ALIGN);
300 0 : eh = mtod(m, struct ether_header *);
301 0 : eh->ether_type = etype;
302 0 : memcpy(eh->ether_dhost, edst, sizeof(eh->ether_dhost));
303 0 : memcpy(eh->ether_shost, esrc, sizeof(eh->ether_shost));
304 :
305 0 : return (if_enqueue(ifp, m));
306 : bad:
307 0 : m_freem(m);
308 0 : return (error);
309 0 : }
310 :
311 : /*
312 : * Process a received Ethernet packet;
313 : * the packet is in the mbuf chain m without
314 : * the ether header, which is provided separately.
315 : */
316 : int
317 0 : ether_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
318 : {
319 : struct ether_header *eh;
320 : void (*input)(struct ifnet *, struct mbuf *);
321 : u_int16_t etype;
322 : struct arpcom *ac;
323 :
324 : /* Drop short frames */
325 0 : if (m->m_len < ETHER_HDR_LEN)
326 : goto dropanyway;
327 :
328 0 : ac = (struct arpcom *)ifp;
329 0 : eh = mtod(m, struct ether_header *);
330 :
331 : /* Is the packet for us? */
332 0 : if (memcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN) != 0) {
333 :
334 : /* If not, it must be multicast or broadcast to go further */
335 0 : if (!ETHER_IS_MULTICAST(eh->ether_dhost))
336 : goto dropanyway;
337 :
338 : /*
339 : * If this is not a simplex interface, drop the packet
340 : * if it came from us.
341 : */
342 0 : if ((ifp->if_flags & IFF_SIMPLEX) == 0) {
343 0 : if (memcmp(ac->ac_enaddr, eh->ether_shost,
344 0 : ETHER_ADDR_LEN) == 0)
345 : goto dropanyway;
346 : }
347 :
348 0 : if (memcmp(etherbroadcastaddr, eh->ether_dhost,
349 0 : ETHER_ADDR_LEN) == 0)
350 0 : m->m_flags |= M_BCAST;
351 : else
352 0 : m->m_flags |= M_MCAST;
353 0 : ifp->if_imcasts++;
354 0 : }
355 :
356 : /*
357 : * HW vlan tagged packets that were not collected by vlan(4) must
358 : * be dropped now.
359 : */
360 0 : if (m->m_flags & M_VLANTAG)
361 : goto dropanyway;
362 :
363 0 : etype = ntohs(eh->ether_type);
364 :
365 0 : switch (etype) {
366 : case ETHERTYPE_IP:
367 : input = ipv4_input;
368 0 : break;
369 :
370 : case ETHERTYPE_ARP:
371 0 : if (ifp->if_flags & IFF_NOARP)
372 : goto dropanyway;
373 : input = arpinput;
374 0 : break;
375 :
376 : case ETHERTYPE_REVARP:
377 0 : if (ifp->if_flags & IFF_NOARP)
378 : goto dropanyway;
379 : input = revarpinput;
380 0 : break;
381 :
382 : #ifdef INET6
383 : /*
384 : * Schedule IPv6 software interrupt for incoming IPv6 packet.
385 : */
386 : case ETHERTYPE_IPV6:
387 : input = ipv6_input;
388 0 : break;
389 : #endif /* INET6 */
390 : #if NPPPOE > 0 || defined(PIPEX)
391 : case ETHERTYPE_PPPOEDISC:
392 : case ETHERTYPE_PPPOE:
393 0 : if (m->m_flags & (M_MCAST | M_BCAST))
394 : goto dropanyway;
395 : #ifdef PIPEX
396 0 : if (pipex_enable) {
397 : struct pipex_session *session;
398 :
399 0 : if ((session = pipex_pppoe_lookup_session(m)) != NULL) {
400 0 : pipex_pppoe_input(m, session);
401 0 : return (1);
402 : }
403 0 : }
404 : #endif
405 0 : if (etype == ETHERTYPE_PPPOEDISC)
406 0 : niq_enqueue(&pppoediscinq, m);
407 : else
408 0 : niq_enqueue(&pppoeinq, m);
409 0 : return (1);
410 : #endif
411 : #ifdef MPLS
412 : case ETHERTYPE_MPLS:
413 : case ETHERTYPE_MPLS_MCAST:
414 : input = mpls_input;
415 0 : break;
416 : #endif
417 : default:
418 : goto dropanyway;
419 : }
420 :
421 0 : m_adj(m, sizeof(*eh));
422 0 : (*input)(ifp, m);
423 0 : return (1);
424 : dropanyway:
425 0 : m_freem(m);
426 0 : return (1);
427 0 : }
428 :
429 : /*
430 : * Convert Ethernet address to printable (loggable) representation.
431 : */
432 : static char digits[] = "0123456789abcdef";
433 : char *
434 0 : ether_sprintf(u_char *ap)
435 : {
436 : int i;
437 : static char etherbuf[ETHER_ADDR_LEN * 3];
438 : char *cp = etherbuf;
439 :
440 0 : for (i = 0; i < ETHER_ADDR_LEN; i++) {
441 0 : *cp++ = digits[*ap >> 4];
442 0 : *cp++ = digits[*ap++ & 0xf];
443 0 : *cp++ = ':';
444 : }
445 0 : *--cp = 0;
446 0 : return (etherbuf);
447 : }
448 :
449 : /*
450 : * Generate a (hopefully) acceptable MAC address, if asked.
451 : */
452 : void
453 0 : ether_fakeaddr(struct ifnet *ifp)
454 : {
455 : static int unit;
456 0 : int rng = arc4random();
457 :
458 : /* Non-multicast; locally administered address */
459 0 : ((struct arpcom *)ifp)->ac_enaddr[0] = 0xfe;
460 0 : ((struct arpcom *)ifp)->ac_enaddr[1] = 0xe1;
461 0 : ((struct arpcom *)ifp)->ac_enaddr[2] = 0xba;
462 0 : ((struct arpcom *)ifp)->ac_enaddr[3] = 0xd0 | (unit++ & 0xf);
463 0 : ((struct arpcom *)ifp)->ac_enaddr[4] = rng;
464 0 : ((struct arpcom *)ifp)->ac_enaddr[5] = rng >> 8;
465 0 : }
466 :
467 : /*
468 : * Perform common duties while attaching to interface list
469 : */
470 : void
471 0 : ether_ifattach(struct ifnet *ifp)
472 : {
473 0 : struct arpcom *ac = (struct arpcom *)ifp;
474 :
475 : /*
476 : * Any interface which provides a MAC address which is obviously
477 : * invalid gets whacked, so that users will notice.
478 : */
479 0 : if (ETHER_IS_MULTICAST(((struct arpcom *)ifp)->ac_enaddr))
480 0 : ether_fakeaddr(ifp);
481 :
482 0 : ifp->if_type = IFT_ETHER;
483 0 : ifp->if_addrlen = ETHER_ADDR_LEN;
484 0 : ifp->if_hdrlen = ETHER_HDR_LEN;
485 0 : ifp->if_mtu = ETHERMTU;
486 0 : ifp->if_output = ether_output;
487 0 : ifp->if_rtrequest = ether_rtrequest;
488 :
489 0 : if_ih_insert(ifp, ether_input, NULL);
490 :
491 0 : if (ifp->if_hardmtu == 0)
492 0 : ifp->if_hardmtu = ETHERMTU;
493 :
494 0 : if_alloc_sadl(ifp);
495 0 : memcpy(LLADDR(ifp->if_sadl), ac->ac_enaddr, ifp->if_addrlen);
496 0 : LIST_INIT(&ac->ac_multiaddrs);
497 : #if NBPFILTER > 0
498 0 : bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN);
499 : #endif
500 0 : }
501 :
502 : void
503 0 : ether_ifdetach(struct ifnet *ifp)
504 : {
505 0 : struct arpcom *ac = (struct arpcom *)ifp;
506 : struct ether_multi *enm;
507 :
508 : /* Undo pseudo-driver changes. */
509 0 : if_deactivate(ifp);
510 :
511 0 : if_ih_remove(ifp, ether_input, NULL);
512 :
513 0 : KASSERT(SRPL_EMPTY_LOCKED(&ifp->if_inputs));
514 :
515 0 : for (enm = LIST_FIRST(&ac->ac_multiaddrs);
516 0 : enm != NULL;
517 0 : enm = LIST_FIRST(&ac->ac_multiaddrs)) {
518 0 : LIST_REMOVE(enm, enm_list);
519 0 : free(enm, M_IFMADDR, sizeof *enm);
520 : }
521 0 : }
522 :
523 : #if 0
524 : /*
525 : * This is for reference. We have table-driven versions of the
526 : * crc32 generators, which are faster than the double-loop.
527 : */
528 : u_int32_t __pure
529 : ether_crc32_le_update(u_int_32_t crc, const u_int8_t *buf, size_t len)
530 : {
531 : u_int32_t c, carry;
532 : size_t i, j;
533 :
534 : for (i = 0; i < len; i++) {
535 : c = buf[i];
536 : for (j = 0; j < 8; j++) {
537 : carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01);
538 : crc >>= 1;
539 : c >>= 1;
540 : if (carry)
541 : crc = (crc ^ ETHER_CRC_POLY_LE);
542 : }
543 : }
544 :
545 : return (crc);
546 : }
547 :
548 : u_int32_t __pure
549 : ether_crc32_be_update(u_int_32_t crc, const u_int8_t *buf, size_t len)
550 : {
551 : u_int32_t c, carry;
552 : size_t i, j;
553 :
554 : for (i = 0; i < len; i++) {
555 : c = buf[i];
556 : for (j = 0; j < 8; j++) {
557 : carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01);
558 : crc <<= 1;
559 : c >>= 1;
560 : if (carry)
561 : crc = (crc ^ ETHER_CRC_POLY_BE) | carry;
562 : }
563 : }
564 :
565 : return (crc);
566 : }
567 : #else
568 : u_int32_t __pure
569 0 : ether_crc32_le_update(u_int32_t crc, const u_int8_t *buf, size_t len)
570 : {
571 : static const u_int32_t crctab[] = {
572 : 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
573 : 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
574 : 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
575 : 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
576 : };
577 : size_t i;
578 :
579 0 : for (i = 0; i < len; i++) {
580 0 : crc ^= buf[i];
581 0 : crc = (crc >> 4) ^ crctab[crc & 0xf];
582 0 : crc = (crc >> 4) ^ crctab[crc & 0xf];
583 : }
584 :
585 0 : return (crc);
586 : }
587 :
588 : u_int32_t __pure
589 0 : ether_crc32_be_update(u_int32_t crc, const u_int8_t *buf, size_t len)
590 : {
591 : static const u_int8_t rev[] = {
592 : 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
593 : 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
594 : };
595 : static const u_int32_t crctab[] = {
596 : 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
597 : 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
598 : 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
599 : 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd
600 : };
601 : size_t i;
602 : u_int8_t data;
603 :
604 0 : for (i = 0; i < len; i++) {
605 0 : data = buf[i];
606 0 : crc = (crc << 4) ^ crctab[(crc >> 28) ^ rev[data & 0xf]];
607 0 : crc = (crc << 4) ^ crctab[(crc >> 28) ^ rev[data >> 4]];
608 : }
609 :
610 0 : return (crc);
611 : }
612 : #endif
613 :
614 : u_int32_t
615 0 : ether_crc32_le(const u_int8_t *buf, size_t len)
616 : {
617 0 : return ether_crc32_le_update(0xffffffff, buf, len);
618 : }
619 :
620 : u_int32_t
621 0 : ether_crc32_be(const u_int8_t *buf, size_t len)
622 : {
623 0 : return ether_crc32_be_update(0xffffffff, buf, len);
624 : }
625 :
626 : u_char ether_ipmulticast_min[ETHER_ADDR_LEN] =
627 : { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
628 : u_char ether_ipmulticast_max[ETHER_ADDR_LEN] =
629 : { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
630 :
631 : #ifdef INET6
632 : u_char ether_ip6multicast_min[ETHER_ADDR_LEN] =
633 : { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 };
634 : u_char ether_ip6multicast_max[ETHER_ADDR_LEN] =
635 : { 0x33, 0x33, 0xff, 0xff, 0xff, 0xff };
636 : #endif
637 :
638 : /*
639 : * Convert a sockaddr into an Ethernet address or range of Ethernet
640 : * addresses.
641 : */
642 : int
643 0 : ether_multiaddr(struct sockaddr *sa, u_int8_t addrlo[ETHER_ADDR_LEN],
644 : u_int8_t addrhi[ETHER_ADDR_LEN])
645 : {
646 : struct sockaddr_in *sin;
647 : #ifdef INET6
648 : struct sockaddr_in6 *sin6;
649 : #endif /* INET6 */
650 :
651 0 : switch (sa->sa_family) {
652 :
653 : case AF_UNSPEC:
654 0 : memcpy(addrlo, sa->sa_data, ETHER_ADDR_LEN);
655 0 : memcpy(addrhi, addrlo, ETHER_ADDR_LEN);
656 0 : break;
657 :
658 : case AF_INET:
659 0 : sin = satosin(sa);
660 0 : if (sin->sin_addr.s_addr == INADDR_ANY) {
661 : /*
662 : * An IP address of INADDR_ANY means listen to
663 : * or stop listening to all of the Ethernet
664 : * multicast addresses used for IP.
665 : * (This is for the sake of IP multicast routers.)
666 : */
667 0 : memcpy(addrlo, ether_ipmulticast_min, ETHER_ADDR_LEN);
668 0 : memcpy(addrhi, ether_ipmulticast_max, ETHER_ADDR_LEN);
669 0 : } else {
670 0 : ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
671 0 : memcpy(addrhi, addrlo, ETHER_ADDR_LEN);
672 : }
673 : break;
674 : #ifdef INET6
675 : case AF_INET6:
676 0 : sin6 = satosin6(sa);
677 0 : if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
678 : /*
679 : * An IP6 address of 0 means listen to or stop
680 : * listening to all of the Ethernet multicast
681 : * address used for IP6.
682 : *
683 : * (This might not be healthy, given IPv6's reliance on
684 : * multicast for things like neighbor discovery.
685 : * Perhaps initializing all-nodes, solicited nodes, and
686 : * possibly all-routers for this interface afterwards
687 : * is not a bad idea.)
688 : */
689 :
690 0 : memcpy(addrlo, ether_ip6multicast_min, ETHER_ADDR_LEN);
691 0 : memcpy(addrhi, ether_ip6multicast_max, ETHER_ADDR_LEN);
692 0 : } else {
693 0 : ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, addrlo);
694 0 : memcpy(addrhi, addrlo, ETHER_ADDR_LEN);
695 : }
696 : break;
697 : #endif
698 :
699 : default:
700 0 : return (EAFNOSUPPORT);
701 : }
702 0 : return (0);
703 0 : }
704 :
705 : /*
706 : * Add an Ethernet multicast address or range of addresses to the list for a
707 : * given interface.
708 : */
709 : int
710 0 : ether_addmulti(struct ifreq *ifr, struct arpcom *ac)
711 : {
712 : struct ether_multi *enm;
713 0 : u_char addrlo[ETHER_ADDR_LEN];
714 0 : u_char addrhi[ETHER_ADDR_LEN];
715 0 : int s = splnet(), error;
716 :
717 0 : error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
718 0 : if (error != 0) {
719 0 : splx(s);
720 0 : return (error);
721 : }
722 :
723 : /*
724 : * Verify that we have valid Ethernet multicast addresses.
725 : */
726 0 : if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
727 0 : splx(s);
728 0 : return (EINVAL);
729 : }
730 : /*
731 : * See if the address range is already in the list.
732 : */
733 0 : ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
734 0 : if (enm != NULL) {
735 : /*
736 : * Found it; just increment the reference count.
737 : */
738 0 : ++enm->enm_refcount;
739 0 : splx(s);
740 0 : return (0);
741 : }
742 : /*
743 : * New address or range; malloc a new multicast record
744 : * and link it into the interface's multicast list.
745 : */
746 0 : enm = malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
747 0 : if (enm == NULL) {
748 0 : splx(s);
749 0 : return (ENOBUFS);
750 : }
751 0 : memcpy(enm->enm_addrlo, addrlo, ETHER_ADDR_LEN);
752 0 : memcpy(enm->enm_addrhi, addrhi, ETHER_ADDR_LEN);
753 0 : enm->enm_refcount = 1;
754 0 : LIST_INSERT_HEAD(&ac->ac_multiaddrs, enm, enm_list);
755 0 : ac->ac_multicnt++;
756 0 : if (memcmp(addrlo, addrhi, ETHER_ADDR_LEN) != 0)
757 0 : ac->ac_multirangecnt++;
758 0 : splx(s);
759 : /*
760 : * Return ENETRESET to inform the driver that the list has changed
761 : * and its reception filter should be adjusted accordingly.
762 : */
763 0 : return (ENETRESET);
764 0 : }
765 :
766 : /*
767 : * Delete a multicast address record.
768 : */
769 : int
770 0 : ether_delmulti(struct ifreq *ifr, struct arpcom *ac)
771 : {
772 : struct ether_multi *enm;
773 0 : u_char addrlo[ETHER_ADDR_LEN];
774 0 : u_char addrhi[ETHER_ADDR_LEN];
775 0 : int s = splnet(), error;
776 :
777 0 : error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
778 0 : if (error != 0) {
779 0 : splx(s);
780 0 : return (error);
781 : }
782 :
783 : /*
784 : * Look up the address in our list.
785 : */
786 0 : ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
787 0 : if (enm == NULL) {
788 0 : splx(s);
789 0 : return (ENXIO);
790 : }
791 0 : if (--enm->enm_refcount != 0) {
792 : /*
793 : * Still some claims to this record.
794 : */
795 0 : splx(s);
796 0 : return (0);
797 : }
798 : /*
799 : * No remaining claims to this record; unlink and free it.
800 : */
801 0 : LIST_REMOVE(enm, enm_list);
802 0 : free(enm, M_IFMADDR, sizeof *enm);
803 0 : ac->ac_multicnt--;
804 0 : if (memcmp(addrlo, addrhi, ETHER_ADDR_LEN) != 0)
805 0 : ac->ac_multirangecnt--;
806 0 : splx(s);
807 : /*
808 : * Return ENETRESET to inform the driver that the list has changed
809 : * and its reception filter should be adjusted accordingly.
810 : */
811 0 : return (ENETRESET);
812 0 : }
|