/* * After a change in the NPmode for some NP, move packets from the * npqueue to the send queue or the fast queue as appropriate. * Should be called at splsoftnet. */ static void ppp_requeue(struct ppp_softc *sc) { struct mbuf *m, **mpp; struct ifqueue *ifq; enum NPmode mode; int error; splsoftassert(IPL_SOFTNET); for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) { switch (PPP_PROTOCOL(mtod(m, u_char *))) { case PPP_IP: mode = sc->sc_npmode[NP_IP]; break; default: mode = NPMODE_PASS; } switch (mode) { case NPMODE_PASS: /* * This packet can now go on one of the queues to be sent. */ *mpp = m->m_nextpkt; m->m_nextpkt = NULL; if (m->m_flags & M_HIGHPRI) { ifq = &sc->sc_fastq; if (IF_QFULL(ifq)) { IF_DROP(ifq); m_freem(m); error = ENOBUFS; } else { IF_ENQUEUE(ifq, m); error = 0; } } else IFQ_ENQUEUE(&sc->sc_if.if_snd, m, NULL, error); if (error) { sc->sc_if.if_oerrors++; sc->sc_stats.ppp_oerrors++; } break; case NPMODE_DROP: case NPMODE_ERROR: *mpp = m->m_nextpkt; m_freem(m); break; case NPMODE_QUEUE: mpp = &m->m_nextpkt; break; } } sc->sc_npqtail = mpp; }
int looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct rtentry *rt) { pktqueue_t *pktq = NULL; struct ifqueue *ifq = NULL; int s, isr = -1; int csum_flags; size_t pktlen; MCLAIM(m, ifp->if_mowner); KASSERT(KERNEL_LOCKED_P()); if ((m->m_flags & M_PKTHDR) == 0) panic("looutput: no header mbuf"); if (ifp->if_flags & IFF_LOOPBACK) bpf_mtap_af(ifp, dst->sa_family, m); m->m_pkthdr.rcvif = ifp; if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { m_freem(m); return (rt->rt_flags & RTF_BLACKHOLE ? 0 : rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); } pktlen = m->m_pkthdr.len; ifp->if_opackets++; ifp->if_obytes += pktlen; #ifdef ALTQ /* * ALTQ on the loopback interface is just for debugging. It's * used only for loopback interfaces, not for a simplex interface. */ if ((ALTQ_IS_ENABLED(&ifp->if_snd) || TBR_IS_ENABLED(&ifp->if_snd)) && ifp->if_start == lostart) { struct altq_pktattr pktattr; int error; /* * If the queueing discipline needs packet classification, * do it before prepending the link headers. */ IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr); M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); if (m == NULL) return (ENOBUFS); *(mtod(m, uint32_t *)) = dst->sa_family; s = splnet(); IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error); (*ifp->if_start)(ifp); splx(s); return (error); } #endif /* ALTQ */ m_tag_delete_nonpersistent(m); #ifdef MPLS if (rt != NULL && rt_gettag(rt) != NULL && rt_gettag(rt)->sa_family == AF_MPLS && (m->m_flags & (M_MCAST | M_BCAST)) == 0) { union mpls_shim msh; msh.s_addr = MPLS_GETSADDR(rt); if (msh.shim.label != MPLS_LABEL_IMPLNULL) { ifq = &mplsintrq; isr = NETISR_MPLS; } } if (isr != NETISR_MPLS) #endif switch (dst->sa_family) { #ifdef INET case AF_INET: csum_flags = m->m_pkthdr.csum_flags; KASSERT((csum_flags & ~(M_CSUM_IPv4|M_CSUM_UDPv4)) == 0); if (csum_flags != 0 && IN_LOOPBACK_NEED_CHECKSUM(csum_flags)) { ip_undefer_csum(m, 0, csum_flags); } m->m_pkthdr.csum_flags = 0; pktq = ip_pktq; break; #endif #ifdef INET6 case AF_INET6: csum_flags = m->m_pkthdr.csum_flags; KASSERT((csum_flags & ~M_CSUM_UDPv6) == 0); if (csum_flags != 0 && IN6_LOOPBACK_NEED_CHECKSUM(csum_flags)) { ip6_undefer_csum(m, 0, csum_flags); } m->m_pkthdr.csum_flags = 0; m->m_flags |= M_LOOP; pktq = ip6_pktq; break; #endif #ifdef IPX case AF_IPX: ifq = &ipxintrq; isr = NETISR_IPX; break; #endif #ifdef NETATALK case AF_APPLETALK: ifq = &atintrq2; isr = NETISR_ATALK; break; #endif default: printf("%s: can't handle af%d\n", ifp->if_xname, dst->sa_family); m_freem(m); return (EAFNOSUPPORT); } s = splnet(); if (__predict_true(pktq)) { int error = 0; if (__predict_true(pktq_enqueue(pktq, m, 0))) { ifp->if_ipackets++; ifp->if_ibytes += pktlen; } else { m_freem(m); error = ENOBUFS; } splx(s); return error; } if (IF_QFULL(ifq)) { IF_DROP(ifq); m_freem(m); splx(s); return (ENOBUFS); } IF_ENQUEUE(ifq, m); schednetisr(isr); ifp->if_ipackets++; ifp->if_ibytes += m->m_pkthdr.len; splx(s); return (0); }
int looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct rtentry *rt) { int s, isr; struct ifqueue *ifq = NULL; MCLAIM(m, ifp->if_mowner); if ((m->m_flags & M_PKTHDR) == 0) panic("looutput: no header mbuf"); #if NBPFILTER > 0 if (ifp->if_bpf && (ifp->if_flags & IFF_LOOPBACK)) bpf_mtap_af(ifp->if_bpf, dst->sa_family, m); #endif m->m_pkthdr.rcvif = ifp; if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { m_freem(m); return (rt->rt_flags & RTF_BLACKHOLE ? 0 : rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); } ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; #ifdef ALTQ /* * ALTQ on the loopback interface is just for debugging. It's * used only for loopback interfaces, not for a simplex interface. */ if ((ALTQ_IS_ENABLED(&ifp->if_snd) || TBR_IS_ENABLED(&ifp->if_snd)) && ifp->if_start == lostart) { struct altq_pktattr pktattr; int error; /* * If the queueing discipline needs packet classification, * do it before prepending the link headers. */ IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr); M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); if (m == NULL) return (ENOBUFS); *(mtod(m, uint32_t *)) = dst->sa_family; s = splnet(); IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error); (*ifp->if_start)(ifp); splx(s); return (error); } #endif /* ALTQ */ m_tag_delete_nonpersistent(m); switch (dst->sa_family) { #ifdef INET case AF_INET: ifq = &ipintrq; isr = NETISR_IP; break; #endif #ifdef INET6 case AF_INET6: m->m_flags |= M_LOOP; ifq = &ip6intrq; isr = NETISR_IPV6; break; #endif #ifdef ISO case AF_ISO: ifq = &clnlintrq; isr = NETISR_ISO; break; #endif #ifdef IPX case AF_IPX: ifq = &ipxintrq; isr = NETISR_IPX; break; #endif #ifdef NETATALK case AF_APPLETALK: ifq = &atintrq2; isr = NETISR_ATALK; break; #endif default: printf("%s: can't handle af%d\n", ifp->if_xname, dst->sa_family); m_freem(m); return (EAFNOSUPPORT); } s = splnet(); if (IF_QFULL(ifq)) { IF_DROP(ifq); m_freem(m); splx(s); return (ENOBUFS); } IF_ENQUEUE(ifq, m); // schednetisr(isr); ifp->if_ipackets++; ifp->if_ibytes += m->m_pkthdr.len; splx(s); return (0); }
/* * Send an EAPOL-Key frame to node `ni'. If MIC or encryption is required, * the PTK must be passed (otherwise it can be set to NULL.) */ int ieee80211_send_eapol_key(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_ptk *ptk) { struct ifnet *ifp = &ic->ic_if; struct ether_header *eh; struct ieee80211_eapol_key *key; u_int16_t info; int s, len, error; M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT); if (m == NULL) return ENOMEM; /* no need to m_pullup here (ok by construction) */ eh = mtod(m, struct ether_header *); eh->ether_type = htons(ETHERTYPE_PAE); IEEE80211_ADDR_COPY(eh->ether_shost, ic->ic_myaddr); IEEE80211_ADDR_COPY(eh->ether_dhost, ni->ni_macaddr); key = (struct ieee80211_eapol_key *)&eh[1]; key->version = EAPOL_VERSION; key->type = EAPOL_KEY; key->desc = (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ? EAPOL_KEY_DESC_IEEE80211 : EAPOL_KEY_DESC_WPA; info = BE_READ_2(key->info); /* use V3 descriptor if KDF is SHA256-based */ if (ieee80211_is_sha256_akm(ni->ni_rsnakms)) info |= EAPOL_KEY_DESC_V3; /* use V2 descriptor if pairwise or group cipher is CCMP */ else if (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP || ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP) info |= EAPOL_KEY_DESC_V2; else info |= EAPOL_KEY_DESC_V1; BE_WRITE_2(key->info, info); len = m->m_len - sizeof(struct ether_header); BE_WRITE_2(key->paylen, len - sizeof(*key)); BE_WRITE_2(key->len, len - 4); #ifndef IEEE80211_STA_ONLY if (info & EAPOL_KEY_ENCRYPTED) { if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) { /* clear "Encrypted" bit for WPA */ info &= ~EAPOL_KEY_ENCRYPTED; BE_WRITE_2(key->info, info); } ieee80211_eapol_key_encrypt(ic, key, ptk->kek); if ((info & EAPOL_KEY_VERSION_MASK) != EAPOL_KEY_DESC_V1) { /* AES Key Wrap adds 8 bytes + padding */ m->m_pkthdr.len = m->m_len = sizeof(*eh) + 4 + BE_READ_2(key->len); } } #endif if (info & EAPOL_KEY_KEYMIC) ieee80211_eapol_key_mic(key, ptk->kck); len = m->m_pkthdr.len; s = splnet(); #ifndef IEEE80211_STA_ONLY /* start a 100ms timeout if an answer is expected from supplicant */ if (info & EAPOL_KEY_KEYACK) timeout_add_msec(&ni->ni_eapol_to, 100); #endif IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error); if (error == 0) { ifp->if_obytes += len; if ((ifp->if_flags & IFF_OACTIVE) == 0) (*ifp->if_start)(ifp); } splx(s); return error; }
/* * Queue a packet. Start transmission if not active. * Packet is placed in Information field of PPP frame. */ int pppoutput(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, struct rtentry *rtp) { struct ppp_softc *sc = ifp->if_softc; int protocol, address, control; u_char *cp; int s, error; struct ip *ip; struct ifqueue *ifq; enum NPmode mode; int len; if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0 || ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) { error = ENETDOWN; /* sort of */ goto bad; } #ifdef DIAGNOSTIC if (ifp->if_rdomain != rtable_l2(m0->m_pkthdr.ph_rtableid)) { printf("%s: trying to send packet on wrong domain. " "if %d vs. mbuf %d, AF %d\n", ifp->if_xname, ifp->if_rdomain, rtable_l2(m0->m_pkthdr.ph_rtableid), dst->sa_family); } #endif /* * Compute PPP header. */ m0->m_flags &= ~M_HIGHPRI; switch (dst->sa_family) { #ifdef INET case AF_INET: address = PPP_ALLSTATIONS; control = PPP_UI; protocol = PPP_IP; mode = sc->sc_npmode[NP_IP]; /* * If this packet has the "low delay" bit set in the IP header, * put it on the fastq instead. */ ip = mtod(m0, struct ip *); if (ip->ip_tos & IPTOS_LOWDELAY) m0->m_flags |= M_HIGHPRI; break; #endif case AF_UNSPEC: address = PPP_ADDRESS(dst->sa_data); control = PPP_CONTROL(dst->sa_data); protocol = PPP_PROTOCOL(dst->sa_data); mode = NPMODE_PASS; break; default: printf("%s: af%d not supported\n", ifp->if_xname, dst->sa_family); error = EAFNOSUPPORT; goto bad; } /* * Drop this packet, or return an error, if necessary. */ if (mode == NPMODE_ERROR) { error = ENETDOWN; goto bad; } if (mode == NPMODE_DROP) { error = 0; goto bad; } /* * Add PPP header. If no space in first mbuf, allocate another. * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.) */ M_PREPEND(m0, PPP_HDRLEN, M_DONTWAIT); if (m0 == 0) { error = ENOBUFS; goto bad; } cp = mtod(m0, u_char *); *cp++ = address; *cp++ = control; *cp++ = protocol >> 8; *cp++ = protocol & 0xff; if ((m0->m_flags & M_PKTHDR) == 0) panic("mbuf packet without packet header!"); len = m0->m_pkthdr.len; if (sc->sc_flags & SC_LOG_OUTPKT) { printf("%s output: ", ifp->if_xname); pppdumpm(m0); } if ((protocol & 0x8000) == 0) { #if NBPFILTER > 0 /* * Apply the pass and active filters to the packet, * but only if it is a data packet. */ *mtod(m0, u_char *) = 1; /* indicates outbound */ if (sc->sc_pass_filt.bf_insns != 0 && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m0, len, 0) == 0) { error = 0; /* drop this packet */ goto bad; } /* * Update the time we sent the most recent packet. */ if (sc->sc_active_filt.bf_insns == 0 || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0)) sc->sc_last_sent = time_second; *mtod(m0, u_char *) = address; #else /* * Update the time we sent the most recent packet. */ sc->sc_last_sent = time_second; #endif } #if NBPFILTER > 0 /* * See if bpf wants to look at the packet. */ if (sc->sc_bpf) bpf_mtap(sc->sc_bpf, m0, BPF_DIRECTION_OUT); #endif /* * Put the packet on the appropriate queue. */ s = splsoftnet(); if (mode == NPMODE_QUEUE) { /* XXX we should limit the number of packets on this queue */ *sc->sc_npqtail = m0; m0->m_nextpkt = NULL; sc->sc_npqtail = &m0->m_nextpkt; } else { if (m0->m_flags & M_HIGHPRI) { ifq = &sc->sc_fastq; if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) { IF_DROP(ifq); m_freem(m0); error = ENOBUFS; } else { IF_ENQUEUE(ifq, m0); error = 0; } } else IFQ_ENQUEUE(&sc->sc_if.if_snd, m0, NULL, error); if (error) { splx(s); sc->sc_if.if_oerrors++; sc->sc_stats.ppp_oerrors++; return (error); } (*sc->sc_start)(sc); } ifp->if_opackets++; ifp->if_obytes += len; splx(s); return (0); bad: m_freem(m0); return (error); }
/* * Ethernet output routine. * Encapsulate a packet of type family for the local net. * Assumes that ifp is actually pointer to arpcom structure. */ int ether_output(struct ifnet *ifp0, struct mbuf *m0, struct sockaddr *dst, struct rtentry *rt0) { u_int16_t etype; int s, len, error = 0; u_char edst[ETHER_ADDR_LEN]; u_char *esrc; struct mbuf *m = m0; struct rtentry *rt; struct mbuf *mcopy = NULL; struct ether_header *eh; struct arpcom *ac = (struct arpcom *)ifp0; short mflags; struct ifnet *ifp = ifp0; #ifdef DIAGNOSTIC if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) { printf("%s: trying to send packet on wrong domain. " "if %d vs. mbuf %d, AF %d\n", ifp->if_xname, ifp->if_rdomain, rtable_l2(m->m_pkthdr.ph_rtableid), dst->sa_family); } #endif #if NTRUNK > 0 /* restrict transmission on trunk members to bpf only */ if (ifp->if_type == IFT_IEEE8023ADLAG && (m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) senderr(EBUSY); #endif #if NCARP > 0 if (ifp->if_type == IFT_CARP) { ifp = ifp->if_carpdev; ac = (struct arpcom *)ifp; if ((ifp0->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); } #endif /* NCARP > 0 */ if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); if ((rt = rt0) != NULL) { if ((rt->rt_flags & RTF_UP) == 0) { if ((rt0 = rt = rtalloc1(dst, RT_REPORT, m->m_pkthdr.ph_rtableid)) != NULL) rt->rt_refcnt--; else senderr(EHOSTUNREACH); } if (rt->rt_flags & RTF_GATEWAY) { if (rt->rt_gwroute == NULL) goto lookup; if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { rtfree(rt); rt = rt0; lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, RT_REPORT, ifp->if_rdomain); if ((rt = rt->rt_gwroute) == NULL) senderr(EHOSTUNREACH); } } if (rt->rt_flags & RTF_REJECT) if (rt->rt_rmx.rmx_expire == 0 || time_second < rt->rt_rmx.rmx_expire) senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } esrc = ac->ac_enaddr; switch (dst->sa_family) { #ifdef INET case AF_INET: if (!arpresolve(ac, rt, m, dst, edst)) return (0); /* if not yet resolved */ /* If broadcasting on a simplex interface, loopback a copy */ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && !m->m_pkthdr.pf.routed) mcopy = m_copy(m, 0, (int)M_COPYALL); etype = htons(ETHERTYPE_IP); break; #endif #ifdef INET6 case AF_INET6: if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)) return (0); /* it must be impossible, but... */ etype = htons(ETHERTYPE_IPV6); break; #endif #ifdef MPLS case AF_MPLS: if (rt) dst = rt_key(rt); else senderr(EHOSTUNREACH); if (!ISSET(ifp->if_xflags, IFXF_MPLS)) senderr(ENETUNREACH); switch (dst->sa_family) { case AF_LINK: if (((struct sockaddr_dl *)dst)->sdl_alen < sizeof(edst)) senderr(EHOSTUNREACH); memcpy(edst, LLADDR((struct sockaddr_dl *)dst), sizeof(edst)); break; case AF_INET: if (!arpresolve(ac, rt, m, dst, edst)) return (0); /* if not yet resolved */ break; default: senderr(EHOSTUNREACH); } /* XXX handling for simplex devices in case of M/BCAST ?? */ if (m->m_flags & (M_BCAST | M_MCAST)) etype = htons(ETHERTYPE_MPLS_MCAST); else etype = htons(ETHERTYPE_MPLS); break; #endif /* MPLS */ case pseudo_AF_HDRCMPLT: eh = (struct ether_header *)dst->sa_data; esrc = eh->ether_shost; /* FALLTHROUGH */ case AF_UNSPEC: eh = (struct ether_header *)dst->sa_data; memcpy(edst, eh->ether_dhost, sizeof(edst)); /* AF_UNSPEC doesn't swap the byte order of the ether_type. */ etype = eh->ether_type; break; default: printf("%s: can't handle af%d\n", ifp->if_xname, dst->sa_family); senderr(EAFNOSUPPORT); } /* XXX Should we feed-back an unencrypted IPsec packet ? */ if (mcopy) (void) looutput(ifp, mcopy, dst, rt); #if NCARP > 0 if (ifp0 != ifp && ifp0->if_type == IFT_CARP) esrc = carp_get_srclladdr(ifp0, esrc); #endif if (ether_addheader(&m, ifp, etype, esrc, edst) == -1) senderr(ENOBUFS); #if NBRIDGE > 0 /* * Interfaces that are bridgeports need special handling for output. */ if (ifp->if_bridgeport) { struct m_tag *mtag; /* * Check if this packet has already been sent out through * this bridgeport, in which case we simply send it out * without further bridge processing. */ for (mtag = m_tag_find(m, PACKET_TAG_BRIDGE, NULL); mtag; mtag = m_tag_find(m, PACKET_TAG_BRIDGE, mtag)) { #ifdef DEBUG /* Check that the information is there */ if (mtag->m_tag_len != sizeof(caddr_t)) { error = EINVAL; goto bad; } #endif if (!memcmp(&ifp->if_bridgeport, mtag + 1, sizeof(caddr_t))) break; } if (mtag == NULL) { /* Attach a tag so we can detect loops */ mtag = m_tag_get(PACKET_TAG_BRIDGE, sizeof(caddr_t), M_NOWAIT); if (mtag == NULL) { error = ENOBUFS; goto bad; } memcpy(mtag + 1, &ifp->if_bridgeport, sizeof(caddr_t)); m_tag_prepend(m, mtag); error = bridge_output(ifp, m, NULL, NULL); return (error); } } #endif mflags = m->m_flags; len = m->m_pkthdr.len; s = splnet(); /* * Queue message on interface, and start output if interface * not yet active. */ IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error); if (error) { /* mbuf is already freed */ splx(s); return (error); } ifp->if_obytes += len; #if NCARP > 0 if (ifp != ifp0) ifp0->if_obytes += len; #endif /* NCARP > 0 */ if (mflags & M_MCAST) ifp->if_omcasts++; if_start(ifp); splx(s); return (error); bad: if (m) m_freem(m); return (error); }