| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if.c,v 1.529.2.1.2.4 2023/11/16 05:13:13 thorpej Exp $ */ | | 1 | /* $NetBSD: if.c,v 1.529.2.1.2.5 2023/11/16 14:45:40 thorpej Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1999, 2000, 2001, 2008, 2023 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1999, 2000, 2001, 2008, 2023 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by William Studenmund and Jason R. Thorpe. | | 8 | * by William Studenmund and Jason R. Thorpe. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -80,27 +80,27 @@ | | | @@ -80,27 +80,27 @@ |
80 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 80 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
81 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 81 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
82 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 82 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
83 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 83 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
84 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 84 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
85 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 85 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
86 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 86 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
87 | * SUCH DAMAGE. | | 87 | * SUCH DAMAGE. |
88 | * | | 88 | * |
89 | * @(#)if.c 8.5 (Berkeley) 1/9/95 | | 89 | * @(#)if.c 8.5 (Berkeley) 1/9/95 |
90 | */ | | 90 | */ |
91 | | | 91 | |
92 | #include <sys/cdefs.h> | | 92 | #include <sys/cdefs.h> |
93 | __KERNEL_RCSID(0, "$NetBSD: if.c,v 1.529.2.1.2.4 2023/11/16 05:13:13 thorpej Exp $"); | | 93 | __KERNEL_RCSID(0, "$NetBSD: if.c,v 1.529.2.1.2.5 2023/11/16 14:45:40 thorpej Exp $"); |
94 | | | 94 | |
95 | #if defined(_KERNEL_OPT) | | 95 | #if defined(_KERNEL_OPT) |
96 | #include "opt_inet.h" | | 96 | #include "opt_inet.h" |
97 | #include "opt_ipsec.h" | | 97 | #include "opt_ipsec.h" |
98 | #include "opt_atalk.h" | | 98 | #include "opt_atalk.h" |
99 | #include "opt_wlan.h" | | 99 | #include "opt_wlan.h" |
100 | #include "opt_net_mpsafe.h" | | 100 | #include "opt_net_mpsafe.h" |
101 | #include "opt_mrouting.h" | | 101 | #include "opt_mrouting.h" |
102 | #endif | | 102 | #endif |
103 | | | 103 | |
104 | #define __IFQ_PRIVATE | | 104 | #define __IFQ_PRIVATE |
105 | | | 105 | |
106 | #include <sys/param.h> | | 106 | #include <sys/param.h> |
| @@ -221,27 +221,27 @@ static int if_cloners_count; | | | @@ -221,27 +221,27 @@ static int if_cloners_count; |
221 | pfil_head_t * if_pfil __read_mostly; | | 221 | pfil_head_t * if_pfil __read_mostly; |
222 | | | 222 | |
223 | static kauth_listener_t if_listener; | | 223 | static kauth_listener_t if_listener; |
224 | | | 224 | |
225 | static int doifioctl(struct socket *, u_long, void *, struct lwp *); | | 225 | static int doifioctl(struct socket *, u_long, void *, struct lwp *); |
226 | static void sysctl_sndq_setup(struct sysctllog **, const char *, | | 226 | static void sysctl_sndq_setup(struct sysctllog **, const char *, |
227 | struct ifqueue *); | | 227 | struct ifqueue *); |
228 | static void if_slowtimo_intr(void *); | | 228 | static void if_slowtimo_intr(void *); |
229 | static void if_slowtimo_work(struct work *, void *); | | 229 | static void if_slowtimo_work(struct work *, void *); |
230 | static int sysctl_if_watchdog(SYSCTLFN_PROTO); | | 230 | static int sysctl_if_watchdog(SYSCTLFN_PROTO); |
231 | static void sysctl_watchdog_setup(struct ifnet *); | | 231 | static void sysctl_watchdog_setup(struct ifnet *); |
232 | static void if_attachdomain1(struct ifnet *); | | 232 | static void if_attachdomain1(struct ifnet *); |
233 | static int ifconf(u_long, void *); | | 233 | static int ifconf(u_long, void *); |
234 | static int if_transmit(struct ifnet *, struct mbuf *); | | 234 | static int if_transmit_default(struct ifnet *, struct mbuf *); |
235 | static int if_clone_create(const char *); | | 235 | static int if_clone_create(const char *); |
236 | static int if_clone_destroy(const char *); | | 236 | static int if_clone_destroy(const char *); |
237 | static void if_link_state_change_work(struct work *, void *); | | 237 | static void if_link_state_change_work(struct work *, void *); |
238 | static void if_up_locked(struct ifnet *); | | 238 | static void if_up_locked(struct ifnet *); |
239 | static void _if_down(struct ifnet *); | | 239 | static void _if_down(struct ifnet *); |
240 | static void if_down_deactivated(struct ifnet *); | | 240 | static void if_down_deactivated(struct ifnet *); |
241 | | | 241 | |
242 | struct if_percpuq { | | 242 | struct if_percpuq { |
243 | struct ifnet *ipq_ifp; | | 243 | struct ifnet *ipq_ifp; |
244 | void *ipq_si; | | 244 | void *ipq_si; |
245 | struct percpu *ipq_ifqs; /* struct ifqueue */ | | 245 | struct percpu *ipq_ifqs; /* struct ifqueue */ |
246 | }; | | 246 | }; |
247 | | | 247 | |
| @@ -799,27 +799,27 @@ if_register(ifnet_t *ifp) | | | @@ -799,27 +799,27 @@ if_register(ifnet_t *ifp) |
799 | mutex_init(&isd->isd_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK); | | 799 | mutex_init(&isd->isd_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK); |
800 | callout_init(&isd->isd_ch, CALLOUT_MPSAFE); | | 800 | callout_init(&isd->isd_ch, CALLOUT_MPSAFE); |
801 | callout_setfunc(&isd->isd_ch, if_slowtimo_intr, ifp); | | 801 | callout_setfunc(&isd->isd_ch, if_slowtimo_intr, ifp); |
802 | isd->isd_ifp = ifp; | | 802 | isd->isd_ifp = ifp; |
803 | | | 803 | |
804 | ifp->if_slowtimo_data = isd; | | 804 | ifp->if_slowtimo_data = isd; |
805 | | | 805 | |
806 | if_slowtimo_intr(ifp); | | 806 | if_slowtimo_intr(ifp); |
807 | | | 807 | |
808 | sysctl_watchdog_setup(ifp); | | 808 | sysctl_watchdog_setup(ifp); |
809 | } | | 809 | } |
810 | | | 810 | |
811 | if (ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit) | | 811 | if (ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit) |
812 | ifp->if_transmit = if_transmit; | | 812 | ifp->if_transmit = if_transmit_default; |
813 | | | 813 | |
814 | IFNET_GLOBAL_LOCK(); | | 814 | IFNET_GLOBAL_LOCK(); |
815 | TAILQ_INSERT_TAIL(&ifnet_list, ifp, if_list); | | 815 | TAILQ_INSERT_TAIL(&ifnet_list, ifp, if_list); |
816 | IFNET_WRITER_INSERT_TAIL(ifp); | | 816 | IFNET_WRITER_INSERT_TAIL(ifp); |
817 | IFNET_GLOBAL_UNLOCK(); | | 817 | IFNET_GLOBAL_UNLOCK(); |
818 | } | | 818 | } |
819 | | | 819 | |
820 | /* | | 820 | /* |
821 | * The if_percpuq framework | | 821 | * The if_percpuq framework |
822 | * | | 822 | * |
823 | * It allows network device drivers to execute the network stack | | 823 | * It allows network device drivers to execute the network stack |
824 | * in softint (so called softint-based if_input). It utilizes | | 824 | * in softint (so called softint-based if_input). It utilizes |
825 | * softint and percpu ifqueue. It doesn't distribute any packets | | 825 | * softint and percpu ifqueue. It doesn't distribute any packets |
| @@ -1057,27 +1057,27 @@ if_deferred_start_softint(void *arg) | | | @@ -1057,27 +1057,27 @@ if_deferred_start_softint(void *arg) |
1057 | static void | | 1057 | static void |
1058 | if_deferred_start_common(struct ifnet *ifp) | | 1058 | if_deferred_start_common(struct ifnet *ifp) |
1059 | { | | 1059 | { |
1060 | const int s = splnet(); | | 1060 | const int s = splnet(); |
1061 | if_start_lock(ifp); | | 1061 | if_start_lock(ifp); |
1062 | splx(s); | | 1062 | splx(s); |
1063 | } | | 1063 | } |
1064 | | | 1064 | |
1065 | static inline bool | | 1065 | static inline bool |
1066 | if_snd_is_used(struct ifnet *ifp) | | 1066 | if_snd_is_used(struct ifnet *ifp) |
1067 | { | | 1067 | { |
1068 | | | 1068 | |
1069 | return ALTQ_IS_ENABLED(&ifp->if_snd) || | | 1069 | return ALTQ_IS_ENABLED(&ifp->if_snd) || |
1070 | ifp->if_transmit == if_transmit || | | 1070 | ifp->if_transmit == if_transmit_default || |
1071 | ifp->if_transmit == NULL || | | 1071 | ifp->if_transmit == NULL || |
1072 | ifp->if_transmit == if_nulltransmit; | | 1072 | ifp->if_transmit == if_nulltransmit; |
1073 | } | | 1073 | } |
1074 | | | 1074 | |
1075 | /* | | 1075 | /* |
1076 | * Schedule deferred if_start. | | 1076 | * Schedule deferred if_start. |
1077 | */ | | 1077 | */ |
1078 | void | | 1078 | void |
1079 | if_schedule_deferred_start(struct ifnet *ifp) | | 1079 | if_schedule_deferred_start(struct ifnet *ifp) |
1080 | { | | 1080 | { |
1081 | | | 1081 | |
1082 | KASSERT(ifp->if_deferred_start != NULL); | | 1082 | KASSERT(ifp->if_deferred_start != NULL); |
1083 | | | 1083 | |
| @@ -3755,58 +3755,26 @@ ifreq_setaddr(u_long cmd, struct ifreq * | | | @@ -3755,58 +3755,26 @@ ifreq_setaddr(u_long cmd, struct ifreq * |
3755 | | | 3755 | |
3756 | if (len < sa->sa_len) | | 3756 | if (len < sa->sa_len) |
3757 | return EFBIG; | | 3757 | return EFBIG; |
3758 | | | 3758 | |
3759 | memset(&ifr->ifr_addr, 0, len); | | 3759 | memset(&ifr->ifr_addr, 0, len); |
3760 | sockaddr_copy(&ifr->ifr_addr, len, sa); | | 3760 | sockaddr_copy(&ifr->ifr_addr, len, sa); |
3761 | | | 3761 | |
3762 | if (cmd != ocmd) | | 3762 | if (cmd != ocmd) |
3763 | IFREQN2O_43(oifr, ifr); | | 3763 | IFREQN2O_43(oifr, ifr); |
3764 | return 0; | | 3764 | return 0; |
3765 | } | | 3765 | } |
3766 | | | 3766 | |
3767 | /* | | 3767 | /* |
3768 | * wrapper function for the drivers which doesn't have if_transmit(). | | | |
3769 | */ | | | |
3770 | static int | | | |
3771 | if_transmit(struct ifnet *ifp, struct mbuf *m) | | | |
3772 | { | | | |
3773 | int error; | | | |
3774 | size_t pktlen = m->m_pkthdr.len; | | | |
3775 | bool mcast = (m->m_flags & M_MCAST) != 0; | | | |
3776 | | | | |
3777 | const int s = splnet(); | | | |
3778 | | | | |
3779 | IFQ_ENQUEUE(&ifp->if_snd, m, error); | | | |
3780 | if (error != 0) { | | | |
3781 | /* mbuf is already freed */ | | | |
3782 | goto out; | | | |
3783 | } | | | |
3784 | | | | |
3785 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); | | | |
3786 | if_statadd_ref(nsr, if_obytes, pktlen); | | | |
3787 | if (mcast) | | | |
3788 | if_statinc_ref(nsr, if_omcasts); | | | |
3789 | IF_STAT_PUTREF(ifp); | | | |
3790 | | | | |
3791 | if ((ifp->if_flags & IFF_OACTIVE) == 0) | | | |
3792 | if_start_lock(ifp); | | | |
3793 | out: | | | |
3794 | splx(s); | | | |
3795 | | | | |
3796 | return error; | | | |
3797 | } | | | |
3798 | | | | |
3799 | /* | | | |
3800 | * ifq_init -- | | 3768 | * ifq_init -- |
3801 | * | | 3769 | * |
3802 | * Initialize an interface queue. | | 3770 | * Initialize an interface queue. |
3803 | */ | | 3771 | */ |
3804 | void | | 3772 | void |
3805 | ifq_init(struct ifqueue * const ifq, unsigned int maxqlen) | | 3773 | ifq_init(struct ifqueue * const ifq, unsigned int maxqlen) |
3806 | { | | 3774 | { |
3807 | #ifdef ALTQ | | 3775 | #ifdef ALTQ |
3808 | /* | | 3776 | /* |
3809 | * ALTQ data can be allocated via IFQ_SET_READY() which | | 3777 | * ALTQ data can be allocated via IFQ_SET_READY() which |
3810 | * can be called before if_initialize(), which in turn | | 3778 | * can be called before if_initialize(), which in turn |
3811 | * calls ifq_init(). Preserve it. | | 3779 | * calls ifq_init(). Preserve it. |
3812 | */ | | 3780 | */ |
| @@ -4391,69 +4359,131 @@ ifq_classify_packet(struct ifqueue * con | | | @@ -4391,69 +4359,131 @@ ifq_classify_packet(struct ifqueue * con |
4391 | (m)->m_pkthdr.pattr_class = | | 4359 | (m)->m_pkthdr.pattr_class = |
4392 | (*altq->altq_classify) | | 4360 | (*altq->altq_classify) |
4393 | (altq->altq_clfier, m, af); | | 4361 | (altq->altq_clfier, m, af); |
4394 | } | | 4362 | } |
4395 | m->m_pkthdr.pattr_af = af; | | 4363 | m->m_pkthdr.pattr_af = af; |
4396 | m->m_pkthdr.pattr_hdr = mtod(m, void *); | | 4364 | m->m_pkthdr.pattr_hdr = mtod(m, void *); |
4397 | } | | 4365 | } |
4398 | KERNEL_UNLOCK_ONE(NULL); | | 4366 | KERNEL_UNLOCK_ONE(NULL); |
4399 | } | | 4367 | } |
4400 | mutex_exit((ifq)->ifq_lock); | | 4368 | mutex_exit((ifq)->ifq_lock); |
4401 | #endif /* ALTQ */ | | 4369 | #endif /* ALTQ */ |
4402 | } | | 4370 | } |
4403 | | | 4371 | |
4404 | #ifdef ALTQ | | | |
4405 | static void | | 4372 | static void |
4406 | ifq_lock2(struct ifqueue * const ifq0, struct ifqueue * const ifq1) | | 4373 | if_transmit_tail(struct ifnet *ifp, size_t pktlen, bool mcast) |
4407 | { | | 4374 | { |
4408 | KASSERT(ifq0 != ifq1); | | 4375 | const int s = splnet(); /* XXX */ |
4409 | if (ifq0 < ifq1) { | | 4376 | |
4410 | mutex_enter(ifq0->ifq_lock); | | 4377 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); |
4411 | mutex_enter(ifq1->ifq_lock); | | 4378 | if_statadd_ref(nsr, if_obytes, pktlen); |
4412 | } else { | | 4379 | if (mcast) |
4413 | mutex_enter(ifq1->ifq_lock); | | 4380 | if_statinc_ref(nsr, if_omcasts); |
4414 | mutex_enter(ifq0->ifq_lock); | | 4381 | IF_STAT_PUTREF(ifp); |
| | | 4382 | |
| | | 4383 | if ((ifp->if_flags & IFF_OACTIVE) == 0) |
| | | 4384 | if_start_lock(ifp); |
| | | 4385 | |
| | | 4386 | splx(s); |
| | | 4387 | } |
| | | 4388 | |
| | | 4389 | /* |
| | | 4390 | * wrapper function for the drivers which doesn't have if_transmit(). |
| | | 4391 | */ |
| | | 4392 | static int |
| | | 4393 | if_transmit_default(struct ifnet *ifp, struct mbuf *m) |
| | | 4394 | { |
| | | 4395 | int error; |
| | | 4396 | size_t pktlen = m->m_pkthdr.len; |
| | | 4397 | bool mcast = (m->m_flags & M_MCAST) != 0; |
| | | 4398 | |
| | | 4399 | error = ifq_put(&ifp->if_snd, m); |
| | | 4400 | if (error == 0) { |
| | | 4401 | if_transmit_tail(ifp, pktlen, mcast); |
4415 | } | | 4402 | } |
| | | 4403 | |
| | | 4404 | return error; |
4416 | } | | 4405 | } |
4417 | #endif /* ALTQ */ | | | |
4418 | | | 4406 | |
4419 | /* | | 4407 | /* |
4420 | * Queue message on interface, and start output if interface | | 4408 | * Queue message on interface, and start output if interface |
4421 | * not yet active. | | 4409 | * not yet active. |
4422 | */ | | 4410 | */ |
4423 | int | | 4411 | int |
4424 | if_enqueue(struct ifnet *ifp, struct mbuf *m) | | 4412 | if_enqueue(struct ifnet *ifp, struct mbuf *m) |
4425 | { | | 4413 | { |
4426 | int error; | | | |
4427 | | | | |
4428 | kmsan_check_mbuf(m); | | 4414 | kmsan_check_mbuf(m); |
4429 | | | 4415 | |
4430 | #ifdef ALTQ | | 4416 | #ifdef ALTQ |
4431 | KERNEL_LOCK(1, NULL); | | 4417 | mutex_enter(ifp->if_snd.ifq_lock); |
4432 | if (ALTQ_IS_ENABLED(&ifp->if_snd)) { | | 4418 | if (__predict_false(ALTQ_IS_ENABLED(&ifp->if_snd))) { |
4433 | error = if_transmit(ifp, m); | | 4419 | size_t pktlen = m->m_pkthdr.len; |
4434 | KERNEL_UNLOCK_ONE(NULL); | | 4420 | bool mcast = (m->m_flags & M_MCAST) != 0; |
4435 | } else { | | 4421 | int error; |
| | | 4422 | |
| | | 4423 | /* |
| | | 4424 | * All of this amounts to an elaborate ifq_put_slow() |
| | | 4425 | * that kicks the output queue. |
| | | 4426 | */ |
| | | 4427 | |
| | | 4428 | mutex_exit(ifp->if_snd.ifq_lock); |
| | | 4429 | KERNEL_LOCK(1, NULL); |
| | | 4430 | mutex_enter(ifp->if_snd.ifq_lock); |
| | | 4431 | if (__predict_true(ALTQ_IS_ENABLED(&ifp->if_snd))) { |
| | | 4432 | ALTQ_ENQUEUE(&ifp->if_snd, m, error); |
| | | 4433 | KERNEL_UNLOCK_ONE(NULL); |
| | | 4434 | goto finish; |
| | | 4435 | } |
4436 | KERNEL_UNLOCK_ONE(NULL); | | 4436 | KERNEL_UNLOCK_ONE(NULL); |
4437 | error = (*ifp->if_transmit)(ifp, m); | | 4437 | |
4438 | /* mbuf is already freed */ | | 4438 | if (__predict_true(ifp->if_transmit == if_transmit_default)) { |
| | | 4439 | if (__predict_false(IF_QFULL(&ifp->if_snd))) { |
| | | 4440 | error = ENOBUFS; |
| | | 4441 | } else { |
| | | 4442 | IF_ENQUEUE(&ifp->if_snd, m); |
| | | 4443 | error = 0; |
| | | 4444 | } |
| | | 4445 | finish: |
| | | 4446 | if (__predict_false(error != 0)) { |
| | | 4447 | ifp->if_snd.ifq_drops++; |
| | | 4448 | mutex_exit(ifp->if_snd.ifq_lock); |
| | | 4449 | m_freem(m); |
| | | 4450 | return error; |
| | | 4451 | } |
| | | 4452 | mutex_exit(ifp->if_snd.ifq_lock); |
| | | 4453 | if_transmit_tail(ifp, pktlen, mcast); |
| | | 4454 | return 0; |
| | | 4455 | } |
4439 | } | | 4456 | } |
4440 | #else /* !ALTQ */ | | 4457 | mutex_exit(ifp->if_snd.ifq_lock); |
4441 | error = (*ifp->if_transmit)(ifp, m); | | 4458 | #endif /* ALTQ */ |
4442 | /* mbuf is already freed */ | | | |
4443 | #endif /* !ALTQ */ | | | |
4444 | | | 4459 | |
4445 | return error; | | 4460 | return (*ifp->if_transmit)(ifp, m); |
| | | 4461 | } |
| | | 4462 | |
| | | 4463 | #ifdef ALTQ |
| | | 4464 | static void |
| | | 4465 | ifq_lock2(struct ifqueue * const ifq0, struct ifqueue * const ifq1) |
| | | 4466 | { |
| | | 4467 | KASSERT(ifq0 != ifq1); |
| | | 4468 | if (ifq0 < ifq1) { |
| | | 4469 | mutex_enter(ifq0->ifq_lock); |
| | | 4470 | mutex_enter(ifq1->ifq_lock); |
| | | 4471 | } else { |
| | | 4472 | mutex_enter(ifq1->ifq_lock); |
| | | 4473 | mutex_enter(ifq0->ifq_lock); |
| | | 4474 | } |
4446 | } | | 4475 | } |
| | | 4476 | #endif /* ALTQ */ |
4447 | | | 4477 | |
4448 | /* | | 4478 | /* |
4449 | * Queue message on interface, possibly using a second fast queue | | 4479 | * Queue message on interface, possibly using a second fast queue |
4450 | * | | 4480 | * |
4451 | * N.B. Unlike ifq_enqueue(), this does *not* start transmission on | | 4481 | * N.B. Unlike ifq_enqueue(), this does *not* start transmission on |
4452 | * the interface. | | 4482 | * the interface. |
4453 | */ | | 4483 | */ |
4454 | int | | 4484 | int |
4455 | if_enqueue2(struct ifnet *ifp, struct ifqueue *ifq, struct mbuf *m) | | 4485 | if_enqueue2(struct ifnet *ifp, struct ifqueue *ifq, struct mbuf *m) |
4456 | { | | 4486 | { |
4457 | struct ifqueue * const ifq0 = &ifp->if_snd; | | 4487 | struct ifqueue * const ifq0 = &ifp->if_snd; |
4458 | int error = 0; | | 4488 | int error = 0; |
4459 | | | 4489 | |