| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_ethersubr.c,v 1.242.6.4 2018/03/08 14:37:58 martin Exp $ */ | | 1 | /* $NetBSD: if_ethersubr.c,v 1.242.6.5 2018/03/13 15:40:25 martin Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | | 4 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -51,27 +51,27 @@ | | | @@ -51,27 +51,27 @@ |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
58 | * SUCH DAMAGE. | | 58 | * SUCH DAMAGE. |
59 | * | | 59 | * |
60 | * @(#)if_ethersubr.c 8.2 (Berkeley) 4/4/96 | | 60 | * @(#)if_ethersubr.c 8.2 (Berkeley) 4/4/96 |
61 | */ | | 61 | */ |
62 | | | 62 | |
63 | #include <sys/cdefs.h> | | 63 | #include <sys/cdefs.h> |
64 | __KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.242.6.4 2018/03/08 14:37:58 martin Exp $"); | | 64 | __KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.242.6.5 2018/03/13 15:40:25 martin Exp $"); |
65 | | | 65 | |
66 | #ifdef _KERNEL_OPT | | 66 | #ifdef _KERNEL_OPT |
67 | #include "opt_inet.h" | | 67 | #include "opt_inet.h" |
68 | #include "opt_atalk.h" | | 68 | #include "opt_atalk.h" |
69 | #include "opt_mbuftrace.h" | | 69 | #include "opt_mbuftrace.h" |
70 | #include "opt_mpls.h" | | 70 | #include "opt_mpls.h" |
71 | #include "opt_gateway.h" | | 71 | #include "opt_gateway.h" |
72 | #include "opt_pppoe.h" | | 72 | #include "opt_pppoe.h" |
73 | #include "opt_net_mpsafe.h" | | 73 | #include "opt_net_mpsafe.h" |
74 | #endif | | 74 | #endif |
75 | | | 75 | |
76 | #include "vlan.h" | | 76 | #include "vlan.h" |
77 | #include "pppoe.h" | | 77 | #include "pppoe.h" |
| @@ -182,27 +182,27 @@ static int ether_output(struct ifnet *, | | | @@ -182,27 +182,27 @@ static int ether_output(struct ifnet *, |
182 | | | 182 | |
183 | /* | | 183 | /* |
184 | * Ethernet output routine. | | 184 | * Ethernet output routine. |
185 | * Encapsulate a packet of type family for the local net. | | 185 | * Encapsulate a packet of type family for the local net. |
186 | * Assumes that ifp is actually pointer to ethercom structure. | | 186 | * Assumes that ifp is actually pointer to ethercom structure. |
187 | */ | | 187 | */ |
188 | static int | | 188 | static int |
189 | ether_output(struct ifnet * const ifp0, struct mbuf * const m0, | | 189 | ether_output(struct ifnet * const ifp0, struct mbuf * const m0, |
190 | const struct sockaddr * const dst, | | 190 | const struct sockaddr * const dst, |
191 | const struct rtentry *rt) | | 191 | const struct rtentry *rt) |
192 | { | | 192 | { |
193 | uint16_t etype = 0; | | 193 | uint16_t etype = 0; |
194 | int error = 0, hdrcmplt = 0; | | 194 | int error = 0, hdrcmplt = 0; |
195 | uint8_t esrc[6], edst[6]; | | 195 | uint8_t esrc[6], edst[6]; |
196 | struct mbuf *m = m0; | | 196 | struct mbuf *m = m0; |
197 | struct mbuf *mcopy = NULL; | | 197 | struct mbuf *mcopy = NULL; |
198 | struct ether_header *eh; | | 198 | struct ether_header *eh; |
199 | struct ifnet *ifp = ifp0; | | 199 | struct ifnet *ifp = ifp0; |
200 | #ifdef INET | | 200 | #ifdef INET |
201 | struct arphdr *ah; | | 201 | struct arphdr *ah; |
202 | #endif /* INET */ | | 202 | #endif /* INET */ |
203 | #ifdef NETATALK | | 203 | #ifdef NETATALK |
204 | struct at_ifaddr *aa; | | 204 | struct at_ifaddr *aa; |
205 | #endif /* NETATALK */ | | 205 | #endif /* NETATALK */ |
206 | | | 206 | |
207 | #ifdef MBUFTRACE | | 207 | #ifdef MBUFTRACE |
208 | m_claimm(m, ifp->if_mowner); | | 208 | m_claimm(m, ifp->if_mowner); |
| @@ -291,27 +291,27 @@ ether_output(struct ifnet * const ifp0, | | | @@ -291,27 +291,27 @@ ether_output(struct ifnet * const ifp0, |
291 | else if (m->m_flags & M_MCAST) { | | 291 | else if (m->m_flags & M_MCAST) { |
292 | ETHER_MAP_IPV6_MULTICAST(&satocsin6(dst)->sin6_addr, | | 292 | ETHER_MAP_IPV6_MULTICAST(&satocsin6(dst)->sin6_addr, |
293 | edst); | | 293 | edst); |
294 | } else { | | 294 | } else { |
295 | error = nd6_resolve(ifp, rt, m, dst, edst, | | 295 | error = nd6_resolve(ifp, rt, m, dst, edst, |
296 | sizeof(edst)); | | 296 | sizeof(edst)); |
297 | if (error != 0) | | 297 | if (error != 0) |
298 | return error == EWOULDBLOCK ? 0 : error; | | 298 | return error == EWOULDBLOCK ? 0 : error; |
299 | } | | 299 | } |
300 | etype = htons(ETHERTYPE_IPV6); | | 300 | etype = htons(ETHERTYPE_IPV6); |
301 | break; | | 301 | break; |
302 | #endif | | 302 | #endif |
303 | #ifdef NETATALK | | 303 | #ifdef NETATALK |
304 | case AF_APPLETALK: { | | 304 | case AF_APPLETALK: { |
305 | struct ifaddr *ifa; | | 305 | struct ifaddr *ifa; |
306 | int s; | | 306 | int s; |
307 | | | 307 | |
308 | KERNEL_LOCK(1, NULL); | | 308 | KERNEL_LOCK(1, NULL); |
309 | if (!aarpresolve(ifp, m, (const struct sockaddr_at *)dst, edst)) { | | 309 | if (!aarpresolve(ifp, m, (const struct sockaddr_at *)dst, edst)) { |
310 | #ifdef NETATALKDEBUG | | 310 | #ifdef NETATALKDEBUG |
311 | printf("aarpresolv failed\n"); | | 311 | printf("aarpresolv failed\n"); |
312 | #endif /* NETATALKDEBUG */ | | 312 | #endif /* NETATALKDEBUG */ |
313 | KERNEL_UNLOCK_ONE(NULL); | | 313 | KERNEL_UNLOCK_ONE(NULL); |
314 | return (0); | | 314 | return (0); |
315 | } | | 315 | } |
316 | /* | | 316 | /* |
317 | * ifaddr is the first thing in at_ifaddr | | 317 | * ifaddr is the first thing in at_ifaddr |
| @@ -337,37 +337,37 @@ ether_output(struct ifnet * const ifp0, | | | @@ -337,37 +337,37 @@ ether_output(struct ifnet * const ifp0, |
337 | M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); | | 337 | M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); |
338 | llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; | | 338 | llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; |
339 | llc.llc_control = LLC_UI; | | 339 | llc.llc_control = LLC_UI; |
340 | memcpy(llc.llc_snap_org_code, at_org_code, | | 340 | memcpy(llc.llc_snap_org_code, at_org_code, |
341 | sizeof(llc.llc_snap_org_code)); | | 341 | sizeof(llc.llc_snap_org_code)); |
342 | llc.llc_snap_ether_type = htons(ETHERTYPE_ATALK); | | 342 | llc.llc_snap_ether_type = htons(ETHERTYPE_ATALK); |
343 | memcpy(mtod(m, void *), &llc, sizeof(struct llc)); | | 343 | memcpy(mtod(m, void *), &llc, sizeof(struct llc)); |
344 | } else { | | 344 | } else { |
345 | etype = htons(ETHERTYPE_ATALK); | | 345 | etype = htons(ETHERTYPE_ATALK); |
346 | } | | 346 | } |
347 | pserialize_read_exit(s); | | 347 | pserialize_read_exit(s); |
348 | KERNEL_UNLOCK_ONE(NULL); | | 348 | KERNEL_UNLOCK_ONE(NULL); |
349 | break; | | 349 | break; |
350 | } | | 350 | } |
351 | #endif /* NETATALK */ | | 351 | #endif /* NETATALK */ |
352 | case pseudo_AF_HDRCMPLT: | | 352 | case pseudo_AF_HDRCMPLT: |
353 | hdrcmplt = 1; | | 353 | hdrcmplt = 1; |
354 | memcpy(esrc, | | 354 | memcpy(esrc, |
355 | ((const struct ether_header *)dst->sa_data)->ether_shost, | | 355 | ((const struct ether_header *)dst->sa_data)->ether_shost, |
356 | sizeof(esrc)); | | 356 | sizeof(esrc)); |
357 | /* FALLTHROUGH */ | | 357 | /* FALLTHROUGH */ |
358 | | | 358 | |
359 | case AF_UNSPEC: | | 359 | case AF_UNSPEC: |
360 | memcpy(edst, | | 360 | memcpy(edst, |
361 | ((const struct ether_header *)dst->sa_data)->ether_dhost, | | 361 | ((const struct ether_header *)dst->sa_data)->ether_dhost, |
362 | sizeof(edst)); | | 362 | sizeof(edst)); |
363 | /* AF_UNSPEC doesn't swap the byte order of the ether_type. */ | | 363 | /* AF_UNSPEC doesn't swap the byte order of the ether_type. */ |
364 | etype = ((const struct ether_header *)dst->sa_data)->ether_type; | | 364 | etype = ((const struct ether_header *)dst->sa_data)->ether_type; |
365 | break; | | 365 | break; |
366 | | | 366 | |
367 | default: | | 367 | default: |
368 | printf("%s: can't handle af%d\n", ifp->if_xname, | | 368 | printf("%s: can't handle af%d\n", ifp->if_xname, |
369 | dst->sa_family); | | 369 | dst->sa_family); |
370 | senderr(EAFNOSUPPORT); | | 370 | senderr(EAFNOSUPPORT); |
371 | } | | 371 | } |
372 | | | 372 | |
373 | #ifdef MPLS | | 373 | #ifdef MPLS |
| @@ -391,27 +391,27 @@ ether_output(struct ifnet * const ifp0, | | | @@ -391,27 +391,27 @@ ether_output(struct ifnet * const ifp0, |
391 | */ | | 391 | */ |
392 | if (etype == 0) | | 392 | if (etype == 0) |
393 | etype = htons(m->m_pkthdr.len); | | 393 | etype = htons(m->m_pkthdr.len); |
394 | /* | | 394 | /* |
395 | * Add local net header. If no space in first mbuf, | | 395 | * Add local net header. If no space in first mbuf, |
396 | * allocate another. | | 396 | * allocate another. |
397 | */ | | 397 | */ |
398 | M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); | | 398 | M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); |
399 | if (m == 0) | | 399 | if (m == 0) |
400 | senderr(ENOBUFS); | | 400 | senderr(ENOBUFS); |
401 | eh = mtod(m, struct ether_header *); | | 401 | eh = mtod(m, struct ether_header *); |
402 | /* Note: etype is already in network byte order. */ | | 402 | /* Note: etype is already in network byte order. */ |
403 | (void)memcpy(&eh->ether_type, &etype, sizeof(eh->ether_type)); | | 403 | (void)memcpy(&eh->ether_type, &etype, sizeof(eh->ether_type)); |
404 | memcpy(eh->ether_dhost, edst, sizeof(edst)); | | 404 | memcpy(eh->ether_dhost, edst, sizeof(edst)); |
405 | if (hdrcmplt) | | 405 | if (hdrcmplt) |
406 | memcpy(eh->ether_shost, esrc, sizeof(eh->ether_shost)); | | 406 | memcpy(eh->ether_shost, esrc, sizeof(eh->ether_shost)); |
407 | else | | 407 | else |
408 | memcpy(eh->ether_shost, CLLADDR(ifp->if_sadl), | | 408 | memcpy(eh->ether_shost, CLLADDR(ifp->if_sadl), |
409 | sizeof(eh->ether_shost)); | | 409 | sizeof(eh->ether_shost)); |
410 | | | 410 | |
411 | #if NCARP > 0 | | 411 | #if NCARP > 0 |
412 | if (ifp0 != ifp && ifp0->if_type == IFT_CARP) { | | 412 | if (ifp0 != ifp && ifp0->if_type == IFT_CARP) { |
413 | memcpy(eh->ether_shost, CLLADDR(ifp0->if_sadl), | | 413 | memcpy(eh->ether_shost, CLLADDR(ifp0->if_sadl), |
414 | sizeof(eh->ether_shost)); | | 414 | sizeof(eh->ether_shost)); |
415 | } | | 415 | } |
416 | #endif /* NCARP > 0 */ | | 416 | #endif /* NCARP > 0 */ |
417 | | | 417 | |
| @@ -528,27 +528,27 @@ altq_etherclassify(struct ifaltq *ifq, s | | | @@ -528,27 +528,27 @@ altq_etherclassify(struct ifaltq *ifq, s |
528 | hdr = mtod(m, void *); | | 528 | hdr = mtod(m, void *); |
529 | | | 529 | |
530 | if (ALTQ_NEEDS_CLASSIFY(ifq)) | | 530 | if (ALTQ_NEEDS_CLASSIFY(ifq)) |
531 | m->m_pkthdr.pattr_class = | | 531 | m->m_pkthdr.pattr_class = |
532 | (*ifq->altq_classify)(ifq->altq_clfier, m, af); | | 532 | (*ifq->altq_classify)(ifq->altq_clfier, m, af); |
533 | m->m_pkthdr.pattr_af = af; | | 533 | m->m_pkthdr.pattr_af = af; |
534 | m->m_pkthdr.pattr_hdr = hdr; | | 534 | m->m_pkthdr.pattr_hdr = hdr; |
535 | | | 535 | |
536 | m->m_data -= hlen; | | 536 | m->m_data -= hlen; |
537 | m->m_len += hlen; | | 537 | m->m_len += hlen; |
538 | | | 538 | |
539 | return; | | 539 | return; |
540 | | | 540 | |
541 | bad: | | 541 | bad: |
542 | m->m_pkthdr.pattr_class = NULL; | | 542 | m->m_pkthdr.pattr_class = NULL; |
543 | m->m_pkthdr.pattr_hdr = NULL; | | 543 | m->m_pkthdr.pattr_hdr = NULL; |
544 | m->m_pkthdr.pattr_af = AF_UNSPEC; | | 544 | m->m_pkthdr.pattr_af = AF_UNSPEC; |
545 | } | | 545 | } |
546 | #endif /* ALTQ */ | | 546 | #endif /* ALTQ */ |
547 | | | 547 | |
548 | /* | | 548 | /* |
549 | * Process a received Ethernet packet; | | 549 | * Process a received Ethernet packet; |
550 | * the packet is in the mbuf chain m with | | 550 | * the packet is in the mbuf chain m with |
551 | * the ether header. | | 551 | * the ether header. |
552 | */ | | 552 | */ |
553 | void | | 553 | void |
554 | ether_input(struct ifnet *ifp, struct mbuf *m) | | 554 | ether_input(struct ifnet *ifp, struct mbuf *m) |
| @@ -569,27 +569,27 @@ ether_input(struct ifnet *ifp, struct mb | | | @@ -569,27 +569,27 @@ ether_input(struct ifnet *ifp, struct mb |
569 | | | 569 | |
570 | if ((ifp->if_flags & IFF_UP) == 0) { | | 570 | if ((ifp->if_flags & IFF_UP) == 0) { |
571 | m_freem(m); | | 571 | m_freem(m); |
572 | return; | | 572 | return; |
573 | } | | 573 | } |
574 | | | 574 | |
575 | #ifdef MBUFTRACE | | 575 | #ifdef MBUFTRACE |
576 | m_claimm(m, &ec->ec_rx_mowner); | | 576 | m_claimm(m, &ec->ec_rx_mowner); |
577 | #endif | | 577 | #endif |
578 | eh = mtod(m, struct ether_header *); | | 578 | eh = mtod(m, struct ether_header *); |
579 | etype = ntohs(eh->ether_type); | | 579 | etype = ntohs(eh->ether_type); |
580 | ehlen = sizeof(*eh); | | 580 | ehlen = sizeof(*eh); |
581 | | | 581 | |
582 | if(__predict_false(earlypkts < 100 || !rnd_initial_entropy)) { | | 582 | if (__predict_false(earlypkts < 100 || !rnd_initial_entropy)) { |
583 | rnd_add_data(NULL, eh, ehlen, 0); | | 583 | rnd_add_data(NULL, eh, ehlen, 0); |
584 | earlypkts++; | | 584 | earlypkts++; |
585 | } | | 585 | } |
586 | | | 586 | |
587 | /* | | 587 | /* |
588 | * Determine if the packet is within its size limits. | | 588 | * Determine if the packet is within its size limits. |
589 | */ | | 589 | */ |
590 | if (etype != ETHERTYPE_MPLS && m->m_pkthdr.len > | | 590 | if (etype != ETHERTYPE_MPLS && m->m_pkthdr.len > |
591 | ETHER_MAX_FRAME(ifp, etype, m->m_flags & M_HASFCS)) { | | 591 | ETHER_MAX_FRAME(ifp, etype, m->m_flags & M_HASFCS)) { |
592 | mutex_enter(&bigpktpps_lock); | | 592 | mutex_enter(&bigpktpps_lock); |
593 | if (ppsratecheck(&bigpktppslim_last, &bigpktpps_count, | | 593 | if (ppsratecheck(&bigpktppslim_last, &bigpktpps_count, |
594 | bigpktppslim)) { | | 594 | bigpktppslim)) { |
595 | printf("%s: discarding oversize frame (len=%d)\n", | | 595 | printf("%s: discarding oversize frame (len=%d)\n", |
| @@ -630,26 +630,27 @@ ether_input(struct ifnet *ifp, struct mb | | | @@ -630,26 +630,27 @@ ether_input(struct ifnet *ifp, struct mb |
630 | | | 630 | |
631 | #if NCARP > 0 | | 631 | #if NCARP > 0 |
632 | if (__predict_false(ifp->if_carp && ifp->if_type != IFT_CARP)) { | | 632 | if (__predict_false(ifp->if_carp && ifp->if_type != IFT_CARP)) { |
633 | /* | | 633 | /* |
634 | * clear M_PROMISC, in case the packets comes from a | | 634 | * clear M_PROMISC, in case the packets comes from a |
635 | * vlan | | 635 | * vlan |
636 | */ | | 636 | */ |
637 | m->m_flags &= ~M_PROMISC; | | 637 | m->m_flags &= ~M_PROMISC; |
638 | if (carp_input(m, (uint8_t *)&eh->ether_shost, | | 638 | if (carp_input(m, (uint8_t *)&eh->ether_shost, |
639 | (uint8_t *)&eh->ether_dhost, eh->ether_type) == 0) | | 639 | (uint8_t *)&eh->ether_dhost, eh->ether_type) == 0) |
640 | return; | | 640 | return; |
641 | } | | 641 | } |
642 | #endif /* NCARP > 0 */ | | 642 | #endif /* NCARP > 0 */ |
| | | 643 | |
643 | if ((m->m_flags & (M_BCAST | M_MCAST | M_PROMISC)) == 0 && | | 644 | if ((m->m_flags & (M_BCAST | M_MCAST | M_PROMISC)) == 0 && |
644 | (ifp->if_flags & IFF_PROMISC) != 0 && | | 645 | (ifp->if_flags & IFF_PROMISC) != 0 && |
645 | memcmp(CLLADDR(ifp->if_sadl), eh->ether_dhost, | | 646 | memcmp(CLLADDR(ifp->if_sadl), eh->ether_dhost, |
646 | ETHER_ADDR_LEN) != 0) { | | 647 | ETHER_ADDR_LEN) != 0) { |
647 | m->m_flags |= M_PROMISC; | | 648 | m->m_flags |= M_PROMISC; |
648 | } | | 649 | } |
649 | | | 650 | |
650 | if ((m->m_flags & M_PROMISC) == 0) { | | 651 | if ((m->m_flags & M_PROMISC) == 0) { |
651 | if (pfil_run_hooks(ifp->if_pfil, &m, ifp, PFIL_IN) != 0) | | 652 | if (pfil_run_hooks(ifp->if_pfil, &m, ifp, PFIL_IN) != 0) |
652 | return; | | 653 | return; |
653 | if (m == NULL) | | 654 | if (m == NULL) |
654 | return; | | 655 | return; |
655 | | | 656 | |
| @@ -685,27 +686,27 @@ ether_input(struct ifnet *ifp, struct mb | | | @@ -685,27 +686,27 @@ ether_input(struct ifnet *ifp, struct mb |
685 | return; | | 686 | return; |
686 | } | | 687 | } |
687 | | | 688 | |
688 | /* | | 689 | /* |
689 | * Handle protocols that expect to have the Ethernet header | | 690 | * Handle protocols that expect to have the Ethernet header |
690 | * (and possibly FCS) intact. | | 691 | * (and possibly FCS) intact. |
691 | */ | | 692 | */ |
692 | switch (etype) { | | 693 | switch (etype) { |
693 | case ETHERTYPE_VLAN: { | | 694 | case ETHERTYPE_VLAN: { |
694 | struct ether_vlan_header *evl = (void *)eh; | | 695 | struct ether_vlan_header *evl = (void *)eh; |
695 | /* | | 696 | /* |
696 | * If there is a tag of 0, then the VLAN header was probably | | 697 | * If there is a tag of 0, then the VLAN header was probably |
697 | * just being used to store the priority. Extract the ether | | 698 | * just being used to store the priority. Extract the ether |
698 | * type, and if IP or IPV6, let them deal with it. | | 699 | * type, and if IP or IPV6, let them deal with it. |
699 | */ | | 700 | */ |
700 | if (m->m_len <= sizeof(*evl) | | 701 | if (m->m_len <= sizeof(*evl) |
701 | && EVL_VLANOFTAG(evl->evl_tag) == 0) { | | 702 | && EVL_VLANOFTAG(evl->evl_tag) == 0) { |
702 | etype = ntohs(evl->evl_proto); | | 703 | etype = ntohs(evl->evl_proto); |
703 | ehlen = sizeof(*evl); | | 704 | ehlen = sizeof(*evl); |
704 | if ((m->m_flags & M_PROMISC) == 0 | | 705 | if ((m->m_flags & M_PROMISC) == 0 |
705 | && (etype == ETHERTYPE_IP | | 706 | && (etype == ETHERTYPE_IP |
706 | || etype == ETHERTYPE_IPV6)) | | 707 | || etype == ETHERTYPE_IPV6)) |
707 | break; | | 708 | break; |
708 | } | | 709 | } |
709 | #if NVLAN > 0 | | 710 | #if NVLAN > 0 |
710 | /* | | 711 | /* |
711 | * vlan_input() will either recursively call ether_input() | | 712 | * vlan_input() will either recursively call ether_input() |
| @@ -794,27 +795,27 @@ ether_input(struct ifnet *ifp, struct mb | | | @@ -794,27 +795,27 @@ ether_input(struct ifnet *ifp, struct mb |
794 | inq = &arpintrq; | | 795 | inq = &arpintrq; |
795 | break; | | 796 | break; |
796 | | | 797 | |
797 | case ETHERTYPE_REVARP: | | 798 | case ETHERTYPE_REVARP: |
798 | revarpinput(m); /* XXX queue? */ | | 799 | revarpinput(m); /* XXX queue? */ |
799 | return; | | 800 | return; |
800 | #endif | | 801 | #endif |
801 | #ifdef INET6 | | 802 | #ifdef INET6 |
802 | case ETHERTYPE_IPV6: | | 803 | case ETHERTYPE_IPV6: |
803 | if (__predict_false(!in6_present)) { | | 804 | if (__predict_false(!in6_present)) { |
804 | m_freem(m); | | 805 | m_freem(m); |
805 | return; | | 806 | return; |
806 | } | | 807 | } |
807 | #ifdef GATEWAY | | 808 | #ifdef GATEWAY |
808 | if (ip6flow_fastforward(&m)) | | 809 | if (ip6flow_fastforward(&m)) |
809 | return; | | 810 | return; |
810 | #endif | | 811 | #endif |
811 | pktq = ip6_pktq; | | 812 | pktq = ip6_pktq; |
812 | break; | | 813 | break; |
813 | #endif | | 814 | #endif |
814 | #ifdef NETATALK | | 815 | #ifdef NETATALK |
815 | case ETHERTYPE_ATALK: | | 816 | case ETHERTYPE_ATALK: |
816 | isr = NETISR_ATALK; | | 817 | isr = NETISR_ATALK; |
817 | inq = &atintrq1; | | 818 | inq = &atintrq1; |
818 | break; | | 819 | break; |
819 | case ETHERTYPE_AARP: | | 820 | case ETHERTYPE_AARP: |
820 | /* probably this should be done with a NETISR as well */ | | 821 | /* probably this should be done with a NETISR as well */ |
| @@ -868,30 +869,30 @@ ether_input(struct ifnet *ifp, struct mb | | | @@ -868,30 +869,30 @@ ether_input(struct ifnet *ifp, struct mb |
868 | return; | | 869 | return; |
869 | } | | 870 | } |
870 | | | 871 | |
871 | default: | | 872 | default: |
872 | goto dropanyway; | | 873 | goto dropanyway; |
873 | } | | 874 | } |
874 | break; | | 875 | break; |
875 | #endif | | 876 | #endif |
876 | dropanyway: | | 877 | dropanyway: |
877 | default: | | 878 | default: |
878 | m_freem(m); | | 879 | m_freem(m); |
879 | return; | | 880 | return; |
880 | } | | 881 | } |
881 | #else /* ISO || LLC || NETATALK*/ | | 882 | #else /* LLC || NETATALK */ |
882 | m_freem(m); | | 883 | m_freem(m); |
883 | return; | | 884 | return; |
884 | #endif /* ISO || LLC || NETATALK*/ | | 885 | #endif /* LLC || NETATALK */ |
885 | } | | 886 | } |
886 | | | 887 | |
887 | if (__predict_true(pktq)) { | | 888 | if (__predict_true(pktq)) { |
888 | #ifdef NET_MPSAFE | | 889 | #ifdef NET_MPSAFE |
889 | const u_int h = curcpu()->ci_index; | | 890 | const u_int h = curcpu()->ci_index; |
890 | #else | | 891 | #else |
891 | const uint32_t h = pktq_rps_hash(m); | | 892 | const uint32_t h = pktq_rps_hash(m); |
892 | #endif | | 893 | #endif |
893 | if (__predict_false(!pktq_enqueue(pktq, m, h))) { | | 894 | if (__predict_false(!pktq_enqueue(pktq, m, h))) { |
894 | m_freem(m); | | 895 | m_freem(m); |
895 | } | | 896 | } |
896 | return; | | 897 | return; |
897 | } | | 898 | } |
| @@ -987,43 +988,41 @@ ether_ifdetach(struct ifnet *ifp) | | | @@ -987,43 +988,41 @@ ether_ifdetach(struct ifnet *ifp) |
987 | /* | | 988 | /* |
988 | * Prevent further calls to ioctl (for example turning off | | 989 | * Prevent further calls to ioctl (for example turning off |
989 | * promiscuous mode from the bridge code), which eventually can | | 990 | * promiscuous mode from the bridge code), which eventually can |
990 | * call if_init() which can cause panics because the interface | | 991 | * call if_init() which can cause panics because the interface |
991 | * is in the process of being detached. Return device not configured | | 992 | * is in the process of being detached. Return device not configured |
992 | * instead. | | 993 | * instead. |
993 | */ | | 994 | */ |
994 | ifp->if_ioctl = (int (*)(struct ifnet *, u_long, void *))enxio; | | 995 | ifp->if_ioctl = (int (*)(struct ifnet *, u_long, void *))enxio; |
995 | | | 996 | |
996 | #if NBRIDGE > 0 | | 997 | #if NBRIDGE > 0 |
997 | if (ifp->if_bridge) | | 998 | if (ifp->if_bridge) |
998 | bridge_ifdetach(ifp); | | 999 | bridge_ifdetach(ifp); |
999 | #endif | | 1000 | #endif |
1000 | | | | |
1001 | bpf_detach(ifp); | | 1001 | bpf_detach(ifp); |
1002 | | | | |
1003 | #if NVLAN > 0 | | 1002 | #if NVLAN > 0 |
1004 | if (ec->ec_nvlans) | | 1003 | if (ec->ec_nvlans) |
1005 | vlan_ifdetach(ifp); | | 1004 | vlan_ifdetach(ifp); |
1006 | #endif | | 1005 | #endif |
1007 | | | 1006 | |
1008 | ETHER_LOCK(ec); | | 1007 | ETHER_LOCK(ec); |
1009 | while ((enm = LIST_FIRST(&ec->ec_multiaddrs)) != NULL) { | | 1008 | while ((enm = LIST_FIRST(&ec->ec_multiaddrs)) != NULL) { |
1010 | LIST_REMOVE(enm, enm_list); | | 1009 | LIST_REMOVE(enm, enm_list); |
1011 | kmem_intr_free(enm, sizeof(*enm)); | | 1010 | kmem_free(enm, sizeof(*enm)); |
1012 | ec->ec_multicnt--; | | 1011 | ec->ec_multicnt--; |
1013 | } | | 1012 | } |
1014 | ETHER_UNLOCK(ec); | | 1013 | ETHER_UNLOCK(ec); |
1015 | | | 1014 | |
1016 | mutex_destroy(ec->ec_lock); | | 1015 | mutex_obj_free(ec->ec_lock); |
1017 | | | 1016 | |
1018 | ifp->if_mowner = NULL; | | 1017 | ifp->if_mowner = NULL; |
1019 | MOWNER_DETACH(&ec->ec_rx_mowner); | | 1018 | MOWNER_DETACH(&ec->ec_rx_mowner); |
1020 | MOWNER_DETACH(&ec->ec_tx_mowner); | | 1019 | MOWNER_DETACH(&ec->ec_tx_mowner); |
1021 | } | | 1020 | } |
1022 | | | 1021 | |
1023 | #if 0 | | 1022 | #if 0 |
1024 | /* | | 1023 | /* |
1025 | * This is for reference. We have a table-driven version | | 1024 | * This is for reference. We have a table-driven version |
1026 | * of the little-endian crc32 generator, which is faster | | 1025 | * of the little-endian crc32 generator, which is faster |
1027 | * than the double-loop. | | 1026 | * than the double-loop. |
1028 | */ | | 1027 | */ |
1029 | uint32_t | | 1028 | uint32_t |
| @@ -1103,57 +1102,59 @@ const uint8_t ether_ipmulticast_max[ETHE | | | @@ -1103,57 +1102,59 @@ const uint8_t ether_ipmulticast_max[ETHE |
1103 | #ifdef INET6 | | 1102 | #ifdef INET6 |
1104 | const uint8_t ether_ip6multicast_min[ETHER_ADDR_LEN] = | | 1103 | const uint8_t ether_ip6multicast_min[ETHER_ADDR_LEN] = |
1105 | { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; | | 1104 | { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; |
1106 | const uint8_t ether_ip6multicast_max[ETHER_ADDR_LEN] = | | 1105 | const uint8_t ether_ip6multicast_max[ETHER_ADDR_LEN] = |
1107 | { 0x33, 0x33, 0xff, 0xff, 0xff, 0xff }; | | 1106 | { 0x33, 0x33, 0xff, 0xff, 0xff, 0xff }; |
1108 | #endif | | 1107 | #endif |
1109 | | | 1108 | |
1110 | /* | | 1109 | /* |
1111 | * ether_aton implementation, not using a static buffer. | | 1110 | * ether_aton implementation, not using a static buffer. |
1112 | */ | | 1111 | */ |
1113 | int | | 1112 | int |
1114 | ether_aton_r(u_char *dest, size_t len, const char *str) | | 1113 | ether_aton_r(u_char *dest, size_t len, const char *str) |
1115 | { | | 1114 | { |
1116 | const u_char *cp = (const void *)str; | | 1115 | const u_char *cp = (const void *)str; |
1117 | u_char *ep; | | 1116 | u_char *ep; |
1118 | | | 1117 | |
1119 | #define atox(c) (((c) <= '9') ? ((c) - '0') : ((toupper(c) - 'A') + 10)) | | 1118 | #define atox(c) (((c) <= '9') ? ((c) - '0') : ((toupper(c) - 'A') + 10)) |
1120 | | | 1119 | |
1121 | if (len < ETHER_ADDR_LEN) | | 1120 | if (len < ETHER_ADDR_LEN) |
1122 | return ENOSPC; | | 1121 | return ENOSPC; |
1123 | | | 1122 | |
1124 | ep = dest + ETHER_ADDR_LEN; | | 1123 | ep = dest + ETHER_ADDR_LEN; |
1125 | | | 1124 | |
1126 | while (*cp) { | | 1125 | while (*cp) { |
1127 | if (!isxdigit(*cp)) | | 1126 | if (!isxdigit(*cp)) |
1128 | return EINVAL; | | 1127 | return EINVAL; |
| | | 1128 | |
1129 | *dest = atox(*cp); | | 1129 | *dest = atox(*cp); |
1130 | cp++; | | 1130 | cp++; |
1131 | if (isxdigit(*cp)) { | | 1131 | if (isxdigit(*cp)) { |
1132 | *dest = (*dest << 4) | atox(*cp); | | 1132 | *dest = (*dest << 4) | atox(*cp); |
1133 | dest++; | | | |
1134 | cp++; | | 1133 | cp++; |
1135 | } else | | 1134 | } |
1136 | dest++; | | 1135 | dest++; |
| | | 1136 | |
1137 | if (dest == ep) | | 1137 | if (dest == ep) |
1138 | return *cp == '\0' ? 0 : ENAMETOOLONG; | | 1138 | return (*cp == '\0') ? 0 : ENAMETOOLONG; |
| | | 1139 | |
1139 | switch (*cp) { | | 1140 | switch (*cp) { |
1140 | case ':': | | 1141 | case ':': |
1141 | case '-': | | 1142 | case '-': |
1142 | case '.': | | 1143 | case '.': |
1143 | cp++; | | 1144 | cp++; |
1144 | break; | | 1145 | break; |
1145 | } | | 1146 | } |
1146 | } | | 1147 | } |
1147 | return ENOBUFS; | | 1148 | return ENOBUFS; |
1148 | } | | 1149 | } |
1149 | | | 1150 | |
1150 | /* | | 1151 | /* |
1151 | * Convert a sockaddr into an Ethernet address or range of Ethernet | | 1152 | * Convert a sockaddr into an Ethernet address or range of Ethernet |
1152 | * addresses. | | 1153 | * addresses. |
1153 | */ | | 1154 | */ |
1154 | int | | 1155 | int |
1155 | ether_multiaddr(const struct sockaddr *sa, uint8_t addrlo[ETHER_ADDR_LEN], | | 1156 | ether_multiaddr(const struct sockaddr *sa, uint8_t addrlo[ETHER_ADDR_LEN], |
1156 | uint8_t addrhi[ETHER_ADDR_LEN]) | | 1157 | uint8_t addrhi[ETHER_ADDR_LEN]) |
1157 | { | | 1158 | { |
1158 | #ifdef INET | | 1159 | #ifdef INET |
1159 | const struct sockaddr_in *sin; | | 1160 | const struct sockaddr_in *sin; |
| @@ -1171,28 +1172,27 @@ ether_multiaddr(const struct sockaddr *s | | | @@ -1171,28 +1172,27 @@ ether_multiaddr(const struct sockaddr *s |
1171 | | | 1172 | |
1172 | #ifdef INET | | 1173 | #ifdef INET |
1173 | case AF_INET: | | 1174 | case AF_INET: |
1174 | sin = satocsin(sa); | | 1175 | sin = satocsin(sa); |
1175 | if (sin->sin_addr.s_addr == INADDR_ANY) { | | 1176 | if (sin->sin_addr.s_addr == INADDR_ANY) { |
1176 | /* | | 1177 | /* |
1177 | * An IP address of INADDR_ANY means listen to | | 1178 | * An IP address of INADDR_ANY means listen to |
1178 | * or stop listening to all of the Ethernet | | 1179 | * or stop listening to all of the Ethernet |
1179 | * multicast addresses used for IP. | | 1180 | * multicast addresses used for IP. |
1180 | * (This is for the sake of IP multicast routers.) | | 1181 | * (This is for the sake of IP multicast routers.) |
1181 | */ | | 1182 | */ |
1182 | memcpy(addrlo, ether_ipmulticast_min, ETHER_ADDR_LEN); | | 1183 | memcpy(addrlo, ether_ipmulticast_min, ETHER_ADDR_LEN); |
1183 | memcpy(addrhi, ether_ipmulticast_max, ETHER_ADDR_LEN); | | 1184 | memcpy(addrhi, ether_ipmulticast_max, ETHER_ADDR_LEN); |
1184 | } | | 1185 | } else { |
1185 | else { | | | |
1186 | ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); | | 1186 | ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); |
1187 | memcpy(addrhi, addrlo, ETHER_ADDR_LEN); | | 1187 | memcpy(addrhi, addrlo, ETHER_ADDR_LEN); |
1188 | } | | 1188 | } |
1189 | break; | | 1189 | break; |
1190 | #endif | | 1190 | #endif |
1191 | #ifdef INET6 | | 1191 | #ifdef INET6 |
1192 | case AF_INET6: | | 1192 | case AF_INET6: |
1193 | sin6 = satocsin6(sa); | | 1193 | sin6 = satocsin6(sa); |
1194 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { | | 1194 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
1195 | /* | | 1195 | /* |
1196 | * An IP6 address of 0 means listen to or stop | | 1196 | * An IP6 address of 0 means listen to or stop |
1197 | * listening to all of the Ethernet multicast | | 1197 | * listening to all of the Ethernet multicast |
1198 | * address used for IP6. | | 1198 | * address used for IP6. |
| @@ -1216,120 +1216,123 @@ ether_multiaddr(const struct sockaddr *s | | | @@ -1216,120 +1216,123 @@ ether_multiaddr(const struct sockaddr *s |
1216 | /* | | 1216 | /* |
1217 | * Add an Ethernet multicast address or range of addresses to the list for a | | 1217 | * Add an Ethernet multicast address or range of addresses to the list for a |
1218 | * given interface. | | 1218 | * given interface. |
1219 | */ | | 1219 | */ |
1220 | int | | 1220 | int |
1221 | ether_addmulti(const struct sockaddr *sa, struct ethercom *ec) | | 1221 | ether_addmulti(const struct sockaddr *sa, struct ethercom *ec) |
1222 | { | | 1222 | { |
1223 | struct ether_multi *enm, *_enm; | | 1223 | struct ether_multi *enm, *_enm; |
1224 | u_char addrlo[ETHER_ADDR_LEN]; | | 1224 | u_char addrlo[ETHER_ADDR_LEN]; |
1225 | u_char addrhi[ETHER_ADDR_LEN]; | | 1225 | u_char addrhi[ETHER_ADDR_LEN]; |
1226 | int error = 0; | | 1226 | int error = 0; |
1227 | | | 1227 | |
1228 | /* Allocate out of lock */ | | 1228 | /* Allocate out of lock */ |
1229 | /* XXX still can be called in softint */ | | 1229 | enm = kmem_alloc(sizeof(*enm), KM_SLEEP); |
1230 | enm = kmem_intr_alloc(sizeof(*enm), KM_SLEEP); | | | |
1231 | if (enm == NULL) | | | |
1232 | return ENOBUFS; | | | |
1233 | | | 1230 | |
1234 | ETHER_LOCK(ec); | | 1231 | ETHER_LOCK(ec); |
1235 | error = ether_multiaddr(sa, addrlo, addrhi); | | 1232 | error = ether_multiaddr(sa, addrlo, addrhi); |
1236 | if (error != 0) | | 1233 | if (error != 0) |
1237 | goto out; | | 1234 | goto out; |
1238 | | | 1235 | |
1239 | /* | | 1236 | /* |
1240 | * Verify that we have valid Ethernet multicast addresses. | | 1237 | * Verify that we have valid Ethernet multicast addresses. |
1241 | */ | | 1238 | */ |
1242 | if (!ETHER_IS_MULTICAST(addrlo) || !ETHER_IS_MULTICAST(addrhi)) { | | 1239 | if (!ETHER_IS_MULTICAST(addrlo) || !ETHER_IS_MULTICAST(addrhi)) { |
1243 | error = EINVAL; | | 1240 | error = EINVAL; |
1244 | goto out; | | 1241 | goto out; |
1245 | } | | 1242 | } |
| | | 1243 | |
1246 | /* | | 1244 | /* |
1247 | * See if the address range is already in the list. | | 1245 | * See if the address range is already in the list. |
1248 | */ | | 1246 | */ |
1249 | ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, _enm); | | 1247 | ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, _enm); |
1250 | if (_enm != NULL) { | | 1248 | if (_enm != NULL) { |
1251 | /* | | 1249 | /* |
1252 | * Found it; just increment the reference count. | | 1250 | * Found it; just increment the reference count. |
1253 | */ | | 1251 | */ |
1254 | ++_enm->enm_refcount; | | 1252 | ++_enm->enm_refcount; |
1255 | error = 0; | | 1253 | error = 0; |
1256 | goto out; | | 1254 | goto out; |
1257 | } | | 1255 | } |
| | | 1256 | |
1258 | /* | | 1257 | /* |
1259 | * Link a new multicast record into the interface's multicast list. | | 1258 | * Link a new multicast record into the interface's multicast list. |
1260 | */ | | 1259 | */ |
1261 | memcpy(enm->enm_addrlo, addrlo, 6); | | 1260 | memcpy(enm->enm_addrlo, addrlo, ETHER_ADDR_LEN); |
1262 | memcpy(enm->enm_addrhi, addrhi, 6); | | 1261 | memcpy(enm->enm_addrhi, addrhi, ETHER_ADDR_LEN); |
1263 | enm->enm_refcount = 1; | | 1262 | enm->enm_refcount = 1; |
1264 | LIST_INSERT_HEAD(&ec->ec_multiaddrs, enm, enm_list); | | 1263 | LIST_INSERT_HEAD(&ec->ec_multiaddrs, enm, enm_list); |
1265 | ec->ec_multicnt++; | | 1264 | ec->ec_multicnt++; |
| | | 1265 | |
1266 | /* | | 1266 | /* |
1267 | * Return ENETRESET to inform the driver that the list has changed | | 1267 | * Return ENETRESET to inform the driver that the list has changed |
1268 | * and its reception filter should be adjusted accordingly. | | 1268 | * and its reception filter should be adjusted accordingly. |
1269 | */ | | 1269 | */ |
1270 | error = ENETRESET; | | 1270 | error = ENETRESET; |
1271 | enm = NULL; | | 1271 | enm = NULL; |
| | | 1272 | |
1272 | out: | | 1273 | out: |
1273 | ETHER_UNLOCK(ec); | | 1274 | ETHER_UNLOCK(ec); |
1274 | if (enm != NULL) | | 1275 | if (enm != NULL) |
1275 | kmem_intr_free(enm, sizeof(*enm)); | | 1276 | kmem_free(enm, sizeof(*enm)); |
1276 | return error; | | 1277 | return error; |
1277 | } | | 1278 | } |
1278 | | | 1279 | |
1279 | /* | | 1280 | /* |
1280 | * Delete a multicast address record. | | 1281 | * Delete a multicast address record. |
1281 | */ | | 1282 | */ |
1282 | int | | 1283 | int |
1283 | ether_delmulti(const struct sockaddr *sa, struct ethercom *ec) | | 1284 | ether_delmulti(const struct sockaddr *sa, struct ethercom *ec) |
1284 | { | | 1285 | { |
1285 | struct ether_multi *enm; | | 1286 | struct ether_multi *enm; |
1286 | u_char addrlo[ETHER_ADDR_LEN]; | | 1287 | u_char addrlo[ETHER_ADDR_LEN]; |
1287 | u_char addrhi[ETHER_ADDR_LEN]; | | 1288 | u_char addrhi[ETHER_ADDR_LEN]; |
1288 | int error; | | 1289 | int error; |
1289 | | | 1290 | |
1290 | ETHER_LOCK(ec); | | 1291 | ETHER_LOCK(ec); |
1291 | error = ether_multiaddr(sa, addrlo, addrhi); | | 1292 | error = ether_multiaddr(sa, addrlo, addrhi); |
1292 | if (error != 0) | | 1293 | if (error != 0) |
1293 | goto error; | | 1294 | goto error; |
1294 | | | 1295 | |
1295 | /* | | 1296 | /* |
1296 | * Look ur the address in our list. | | 1297 | * Look up the address in our list. |
1297 | */ | | 1298 | */ |
1298 | ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, enm); | | 1299 | ETHER_LOOKUP_MULTI(addrlo, addrhi, ec, enm); |
1299 | if (enm == NULL) { | | 1300 | if (enm == NULL) { |
1300 | error = ENXIO; | | 1301 | error = ENXIO; |
1301 | goto error; | | 1302 | goto error; |
1302 | } | | 1303 | } |
1303 | if (--enm->enm_refcount != 0) { | | 1304 | if (--enm->enm_refcount != 0) { |
1304 | /* | | 1305 | /* |
1305 | * Still some claims to this record. | | 1306 | * Still some claims to this record. |
1306 | */ | | 1307 | */ |
1307 | error = 0; | | 1308 | error = 0; |
1308 | goto error; | | 1309 | goto error; |
1309 | } | | 1310 | } |
| | | 1311 | |
1310 | /* | | 1312 | /* |
1311 | * No remaining claims to this record; unlink and free it. | | 1313 | * No remaining claims to this record; unlink and free it. |
1312 | */ | | 1314 | */ |
1313 | LIST_REMOVE(enm, enm_list); | | 1315 | LIST_REMOVE(enm, enm_list); |
1314 | ec->ec_multicnt--; | | 1316 | ec->ec_multicnt--; |
1315 | ETHER_UNLOCK(ec); | | 1317 | ETHER_UNLOCK(ec); |
| | | 1318 | kmem_free(enm, sizeof(*enm)); |
1316 | | | 1319 | |
1317 | kmem_intr_free(enm, sizeof(*enm)); | | | |
1318 | /* | | 1320 | /* |
1319 | * Return ENETRESET to inform the driver that the list has changed | | 1321 | * Return ENETRESET to inform the driver that the list has changed |
1320 | * and its reception filter should be adjusted accordingly. | | 1322 | * and its reception filter should be adjusted accordingly. |
1321 | */ | | 1323 | */ |
1322 | return ENETRESET; | | 1324 | return ENETRESET; |
| | | 1325 | |
1323 | error: | | 1326 | error: |
1324 | ETHER_UNLOCK(ec); | | 1327 | ETHER_UNLOCK(ec); |
1325 | return error; | | 1328 | return error; |
1326 | } | | 1329 | } |
1327 | | | 1330 | |
1328 | void | | 1331 | void |
1329 | ether_set_ifflags_cb(struct ethercom *ec, ether_cb_t cb) | | 1332 | ether_set_ifflags_cb(struct ethercom *ec, ether_cb_t cb) |
1330 | { | | 1333 | { |
1331 | ec->ec_ifflags_cb = cb; | | 1334 | ec->ec_ifflags_cb = cb; |
1332 | } | | 1335 | } |
1333 | | | 1336 | |
1334 | /* | | 1337 | /* |
1335 | * Common ioctls for Ethernet interfaces. Note, we must be | | 1338 | * Common ioctls for Ethernet interfaces. Note, we must be |
| @@ -1350,27 +1353,27 @@ ether_ioctl(struct ifnet *ifp, u_long cm | | | @@ -1350,27 +1353,27 @@ ether_ioctl(struct ifnet *ifp, u_long cm |
1350 | case SIOCINITIFADDR: | | 1353 | case SIOCINITIFADDR: |
1351 | { | | 1354 | { |
1352 | struct ifaddr *ifa = (struct ifaddr *)data; | | 1355 | struct ifaddr *ifa = (struct ifaddr *)data; |
1353 | if (ifa->ifa_addr->sa_family != AF_LINK | | 1356 | if (ifa->ifa_addr->sa_family != AF_LINK |
1354 | && (ifp->if_flags & (IFF_UP | IFF_RUNNING)) != | | 1357 | && (ifp->if_flags & (IFF_UP | IFF_RUNNING)) != |
1355 | (IFF_UP | IFF_RUNNING)) { | | 1358 | (IFF_UP | IFF_RUNNING)) { |
1356 | ifp->if_flags |= IFF_UP; | | 1359 | ifp->if_flags |= IFF_UP; |
1357 | if ((error = (*ifp->if_init)(ifp)) != 0) | | 1360 | if ((error = (*ifp->if_init)(ifp)) != 0) |
1358 | return error; | | 1361 | return error; |
1359 | } | | 1362 | } |
1360 | #ifdef INET | | 1363 | #ifdef INET |
1361 | if (ifa->ifa_addr->sa_family == AF_INET) | | 1364 | if (ifa->ifa_addr->sa_family == AF_INET) |
1362 | arp_ifinit(ifp, ifa); | | 1365 | arp_ifinit(ifp, ifa); |
1363 | #endif /* INET */ | | 1366 | #endif |
1364 | return 0; | | 1367 | return 0; |
1365 | } | | 1368 | } |
1366 | | | 1369 | |
1367 | case SIOCSIFMTU: | | 1370 | case SIOCSIFMTU: |
1368 | { | | 1371 | { |
1369 | int maxmtu; | | 1372 | int maxmtu; |
1370 | | | 1373 | |
1371 | if (ec->ec_capabilities & ETHERCAP_JUMBO_MTU) | | 1374 | if (ec->ec_capabilities & ETHERCAP_JUMBO_MTU) |
1372 | maxmtu = ETHERMTU_JUMBO; | | 1375 | maxmtu = ETHERMTU_JUMBO; |
1373 | else | | 1376 | else |
1374 | maxmtu = ETHERMTU; | | 1377 | maxmtu = ETHERMTU; |
1375 | | | 1378 | |
1376 | if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > maxmtu) | | 1379 | if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > maxmtu) |
| @@ -1492,27 +1495,27 @@ ether_disable_vlan_mtu(struct ifnet *ifp | | | @@ -1492,27 +1495,27 @@ ether_disable_vlan_mtu(struct ifnet *ifp |
1492 | | | 1495 | |
1493 | /* We still have VLAN's, defer for later */ | | 1496 | /* We still have VLAN's, defer for later */ |
1494 | if (ec->ec_nvlans != 0) | | 1497 | if (ec->ec_nvlans != 0) |
1495 | return 0; | | 1498 | return 0; |
1496 | | | 1499 | |
1497 | /* Parent does not support VLAB's, nothing to do. */ | | 1500 | /* Parent does not support VLAB's, nothing to do. */ |
1498 | if ((ec->ec_capenable & ETHERCAP_VLAN_MTU) == 0) | | 1501 | if ((ec->ec_capenable & ETHERCAP_VLAN_MTU) == 0) |
1499 | return -1; | | 1502 | return -1; |
1500 | | | 1503 | |
1501 | /* | | 1504 | /* |
1502 | * Disable Tx/Rx of VLAN-sized frames. | | 1505 | * Disable Tx/Rx of VLAN-sized frames. |
1503 | */ | | 1506 | */ |
1504 | ec->ec_capenable &= ~ETHERCAP_VLAN_MTU; | | 1507 | ec->ec_capenable &= ~ETHERCAP_VLAN_MTU; |
1505 | | | 1508 | |
1506 | /* Interface is down, defer for later */ | | 1509 | /* Interface is down, defer for later */ |
1507 | if ((ifp->if_flags & IFF_UP) == 0) | | 1510 | if ((ifp->if_flags & IFF_UP) == 0) |
1508 | return 0; | | 1511 | return 0; |
1509 | | | 1512 | |
1510 | if ((error = if_flags_set(ifp, ifp->if_flags)) == 0) | | 1513 | if ((error = if_flags_set(ifp, ifp->if_flags)) == 0) |
1511 | return 0; | | 1514 | return 0; |
1512 | | | 1515 | |
1513 | ec->ec_capenable |= ETHERCAP_VLAN_MTU; | | 1516 | ec->ec_capenable |= ETHERCAP_VLAN_MTU; |
1514 | return error; | | 1517 | return error; |
1515 | } | | 1518 | } |
1516 | | | 1519 | |
1517 | static int | | 1520 | static int |
1518 | ether_multicast_sysctl(SYSCTLFN_ARGS) | | 1521 | ether_multicast_sysctl(SYSCTLFN_ARGS) |
| @@ -1542,36 +1545,43 @@ ether_multicast_sysctl(SYSCTLFN_ARGS) | | | @@ -1542,36 +1545,43 @@ ether_multicast_sysctl(SYSCTLFN_ARGS) |
1542 | *oldlenp = 0; | | 1545 | *oldlenp = 0; |
1543 | goto out; | | 1546 | goto out; |
1544 | } | | 1547 | } |
1545 | ec = (struct ethercom *)ifp; | | 1548 | ec = (struct ethercom *)ifp; |
1546 | | | 1549 | |
1547 | if (oldp == NULL) { | | 1550 | if (oldp == NULL) { |
1548 | if_put(ifp, &psref); | | 1551 | if_put(ifp, &psref); |
1549 | *oldlenp = ec->ec_multicnt * sizeof(*addrs); | | 1552 | *oldlenp = ec->ec_multicnt * sizeof(*addrs); |
1550 | goto out; | | 1553 | goto out; |
1551 | } | | 1554 | } |
1552 | | | 1555 | |
1553 | /* | | 1556 | /* |
1554 | * ec->ec_lock is a spin mutex so we cannot call sysctl_copyout, which | | 1557 | * ec->ec_lock is a spin mutex so we cannot call sysctl_copyout, which |
1555 | * is sleepable, with holding it. Copy data to a local buffer first | | 1558 | * is sleepable, while holding it. Copy data to a local buffer first |
1556 | * with holding it and then call sysctl_copyout without holding it. | | 1559 | * with the lock taken and then call sysctl_copyout without holding it. |
1557 | */ | | 1560 | */ |
1558 | retry: | | 1561 | retry: |
1559 | multicnt = ec->ec_multicnt; | | 1562 | multicnt = ec->ec_multicnt; |
1560 | addrs = kmem_alloc(sizeof(*addrs) * multicnt, KM_SLEEP); | | 1563 | |
| | | 1564 | if (multicnt == 0) { |
| | | 1565 | if_put(ifp, &psref); |
| | | 1566 | *oldlenp = 0; |
| | | 1567 | goto out; |
| | | 1568 | } |
| | | 1569 | |
| | | 1570 | addrs = kmem_zalloc(sizeof(*addrs) * multicnt, KM_SLEEP); |
1561 | | | 1571 | |
1562 | ETHER_LOCK(ec); | | 1572 | ETHER_LOCK(ec); |
1563 | if (multicnt < ec->ec_multicnt) { | | 1573 | if (multicnt != ec->ec_multicnt) { |
1564 | /* The number of multicast addresses have increased */ | | 1574 | /* The number of multicast addresses has changed */ |
1565 | ETHER_UNLOCK(ec); | | 1575 | ETHER_UNLOCK(ec); |
1566 | kmem_free(addrs, sizeof(*addrs) * multicnt); | | 1576 | kmem_free(addrs, sizeof(*addrs) * multicnt); |
1567 | goto retry; | | 1577 | goto retry; |
1568 | } | | 1578 | } |
1569 | | | 1579 | |
1570 | i = 0; | | 1580 | i = 0; |
1571 | LIST_FOREACH(enm, &ec->ec_multiaddrs, enm_list) { | | 1581 | LIST_FOREACH(enm, &ec->ec_multiaddrs, enm_list) { |
1572 | struct ether_multi_sysctl *addr = &addrs[i]; | | 1582 | struct ether_multi_sysctl *addr = &addrs[i]; |
1573 | addr->enm_refcount = enm->enm_refcount; | | 1583 | addr->enm_refcount = enm->enm_refcount; |
1574 | memcpy(addr->enm_addrlo, enm->enm_addrlo, ETHER_ADDR_LEN); | | 1584 | memcpy(addr->enm_addrlo, enm->enm_addrlo, ETHER_ADDR_LEN); |
1575 | memcpy(addr->enm_addrhi, enm->enm_addrhi, ETHER_ADDR_LEN); | | 1585 | memcpy(addr->enm_addrhi, enm->enm_addrhi, ETHER_ADDR_LEN); |
1576 | i++; | | 1586 | i++; |
1577 | } | | 1587 | } |