1c398230bSWarner Losh /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1989, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 14df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 15df8bae1dSRodney W. Grimes * without specific prior written permission. 16df8bae1dSRodney W. Grimes * 17df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27df8bae1dSRodney W. Grimes * SUCH DAMAGE. 28df8bae1dSRodney W. Grimes * 29df8bae1dSRodney W. Grimes * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 30c3aac50fSPeter Wemm * $FreeBSD$ 31df8bae1dSRodney W. Grimes */ 32df8bae1dSRodney W. Grimes 331d5e9e22SEivind Eklund #include "opt_inet.h" 34cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 354cf49a43SJulian Elischer #include "opt_netgraph.h" 366eeac1d9SJulian Elischer #include "opt_mbuf_profiling.h" 377527624eSRobert Watson #include "opt_rss.h" 38430df5f4SEivind Eklund 39df8bae1dSRodney W. Grimes #include <sys/param.h> 40df8bae1dSRodney W. Grimes #include <sys/systm.h> 41df8bae1dSRodney W. Grimes #include <sys/kernel.h> 42385195c0SMarko Zec #include <sys/lock.h> 43df8bae1dSRodney W. Grimes #include <sys/malloc.h> 4441ee9f1cSPoul-Henning Kamp #include <sys/module.h> 45df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 4610b1fde0SMark Murray #include <sys/random.h> 47df8bae1dSRodney W. Grimes #include <sys/socket.h> 4851a53488SBruce Evans #include <sys/sockio.h> 49602d513cSGarrett Wollman #include <sys/sysctl.h> 50ef1f9169SMarcel Moolenaar #include <sys/uuid.h> 51df8bae1dSRodney W. Grimes 52df8bae1dSRodney W. Grimes #include <net/if.h> 5376039bc8SGleb Smirnoff #include <net/if_var.h> 54d7647d96SDag-Erling Smørgrav #include <net/if_arp.h> 55df8bae1dSRodney W. Grimes #include <net/netisr.h> 56df8bae1dSRodney W. Grimes #include <net/route.h> 57df8bae1dSRodney W. Grimes #include <net/if_llc.h> 58df8bae1dSRodney W. Grimes #include <net/if_dl.h> 59df8bae1dSRodney W. Grimes #include <net/if_types.h> 602e2de7f2SArchie Cobbs #include <net/bpf.h> 61e1e1452dSArchie Cobbs #include <net/ethernet.h> 62fd6238a6SAndrew Thompson #include <net/if_bridgevar.h> 63c1d93b05SSam Leffler #include <net/if_vlan_var.h> 646e6b3f7cSQing Li #include <net/if_llatbl.h> 657d4317bdSAlexander V. Chernikov #include <net/pfil.h> 664b79449eSBjoern A. Zeeb #include <net/vnet.h> 67df8bae1dSRodney W. Grimes 6875bf2db3SGleb Smirnoff #include <netpfil/pf/pf_mtag.h> 6975bf2db3SGleb Smirnoff 7082cd038dSYoshinobu Inoue #if defined(INET) || defined(INET6) 71df8bae1dSRodney W. Grimes #include <netinet/in.h> 72df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 73df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 747527624eSRobert Watson #include <netinet/in_rss.h> 7554bfbd51SWill Andrews #include <netinet/ip_carp.h> 760bcfa8e4SLuigi Rizzo #include <netinet/ip_var.h> 771d5e9e22SEivind Eklund #endif 7882cd038dSYoshinobu Inoue #ifdef INET6 7982cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 8082cd038dSYoshinobu Inoue #endif 81df8bae1dSRodney W. Grimes 824f93599fSBoris Popov int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m); 835accfb8cSBoris Popov int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp, 8447e8d432SGleb Smirnoff const struct sockaddr *dst, short *tp, int *hlen); 85cc6a66f2SJulian Elischer 86aed55708SRobert Watson #include <security/mac/mac_framework.h> 87aed55708SRobert Watson 88d54d93acSEd Maste #ifdef CTASSERT 89d54d93acSEd Maste CTASSERT(sizeof (struct ether_header) == ETHER_ADDR_LEN * 2 + 2); 90d54d93acSEd Maste CTASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN); 91d54d93acSEd Maste #endif 92d54d93acSEd Maste 937d4317bdSAlexander V. Chernikov VNET_DEFINE(struct pfil_head, link_pfil_hook); /* Packet filter hooks */ 947d4317bdSAlexander V. Chernikov 95e1e1452dSArchie Cobbs /* netgraph node hooks for ng_ether(4) */ 96c1d93b05SSam Leffler void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp); 97c1d93b05SSam Leffler void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m); 98e1e1452dSArchie Cobbs int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp); 99e1e1452dSArchie Cobbs void (*ng_ether_attach_p)(struct ifnet *ifp); 100e1e1452dSArchie Cobbs void (*ng_ether_detach_p)(struct ifnet *ifp); 101e1e1452dSArchie Cobbs 102824eb9dcSDavid E. O'Brien void (*vlan_input_p)(struct ifnet *, struct mbuf *); 1039d4fe4b2SBrooks Davis 104fd6238a6SAndrew Thompson /* if_bridge(4) support */ 1058f867517SAndrew Thompson struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *); 1068f867517SAndrew Thompson int (*bridge_output_p)(struct ifnet *, struct mbuf *, 1078f867517SAndrew Thompson struct sockaddr *, struct rtentry *); 108c8b01292SAndrew Thompson void (*bridge_dn_p)(struct mbuf *, struct ifnet *); 1098f867517SAndrew Thompson 11018242d3bSAndrew Thompson /* if_lagg(4) support */ 11118242d3bSAndrew Thompson struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *); 112b47888ceSAndrew Thompson 113e589108dSRobert Watson static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] = 114868d8b62SMatthew N. Dodd { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 115868d8b62SMatthew N. Dodd 116929ddbbbSAlfred Perlstein static int ether_resolvemulti(struct ifnet *, struct sockaddr **, 117929ddbbbSAlfred Perlstein struct sockaddr *); 118d3c351c5SMarko Zec #ifdef VIMAGE 119d3c351c5SMarko Zec static void ether_reassign(struct ifnet *, struct vnet *, char *); 120d3c351c5SMarko Zec #endif 121868d8b62SMatthew N. Dodd 122fc74a9f9SBrooks Davis /* XXX: should be in an arp support file, not here */ 123d745c852SEd Schouten static MALLOC_DEFINE(M_ARPCOM, "arpcom", "802.* interface internals"); 124fc74a9f9SBrooks Davis 12569462a82SBruce M Simpson #define ETHER_IS_BROADCAST(addr) \ 12669462a82SBruce M Simpson (bcmp(etherbroadcastaddr, (addr), ETHER_ADDR_LEN) == 0) 12769462a82SBruce M Simpson 1284c8e8c05SJulian Elischer #define senderr(e) do { error = (e); goto bad;} while (0) 129df8bae1dSRodney W. Grimes 13022f8ce43SAlexander V. Chernikov static void 13122f8ce43SAlexander V. Chernikov update_mbuf_csumflags(struct mbuf *src, struct mbuf *dst) 13222f8ce43SAlexander V. Chernikov { 13322f8ce43SAlexander V. Chernikov int csum_flags = 0; 13422f8ce43SAlexander V. Chernikov 13522f8ce43SAlexander V. Chernikov if (src->m_pkthdr.csum_flags & CSUM_IP) 13622f8ce43SAlexander V. Chernikov csum_flags |= (CSUM_IP_CHECKED|CSUM_IP_VALID); 13722f8ce43SAlexander V. Chernikov if (src->m_pkthdr.csum_flags & CSUM_DELAY_DATA) 13822f8ce43SAlexander V. Chernikov csum_flags |= (CSUM_DATA_VALID|CSUM_PSEUDO_HDR); 13922f8ce43SAlexander V. Chernikov if (src->m_pkthdr.csum_flags & CSUM_SCTP) 14022f8ce43SAlexander V. Chernikov csum_flags |= CSUM_SCTP_VALID; 14122f8ce43SAlexander V. Chernikov dst->m_pkthdr.csum_flags |= csum_flags; 14222f8ce43SAlexander V. Chernikov if (csum_flags & CSUM_DATA_VALID) 14322f8ce43SAlexander V. Chernikov dst->m_pkthdr.csum_data = 0xffff; 14422f8ce43SAlexander V. Chernikov } 14522f8ce43SAlexander V. Chernikov 146df8bae1dSRodney W. Grimes /* 147df8bae1dSRodney W. Grimes * Ethernet output routine. 148df8bae1dSRodney W. Grimes * Encapsulate a packet of type family for the local net. 149df8bae1dSRodney W. Grimes * Use trailer local net encapsulation if enough data in first 150df8bae1dSRodney W. Grimes * packet leaves a multiple of 512 bytes of data in remainder. 151df8bae1dSRodney W. Grimes */ 152df8bae1dSRodney W. Grimes int 15372fd1b6aSDag-Erling Smørgrav ether_output(struct ifnet *ifp, struct mbuf *m, 15447e8d432SGleb Smirnoff const struct sockaddr *dst, struct route *ro) 155df8bae1dSRodney W. Grimes { 156df8bae1dSRodney W. Grimes short type; 157279aa3d4SKip Macy int error = 0, hdrcmplt = 0; 15864760eb0SWarner Losh u_char esrc[ETHER_ADDR_LEN], edst[ETHER_ADDR_LEN]; 1596e6b3f7cSQing Li struct llentry *lle = NULL; 160279aa3d4SKip Macy struct rtentry *rt0 = NULL; 161098a8c3bSMatthew N. Dodd struct ether_header *eh; 16260ee3847SMax Laier struct pf_mtag *t; 163c54c76ccSOleg Bulyzhin int loop_copy = 1; 164d32864c3SRobert Watson int hlen; /* link layer header length */ 165df8bae1dSRodney W. Grimes 166279aa3d4SKip Macy if (ro != NULL) { 1679fca4f79SQing Li if (!(m->m_flags & (M_BCAST | M_MCAST))) 168279aa3d4SKip Macy lle = ro->ro_lle; 169279aa3d4SKip Macy rt0 = ro->ro_rt; 170279aa3d4SKip Macy } 17143b29369SRobert Watson #ifdef MAC 17230d239bcSRobert Watson error = mac_ifnet_check_transmit(ifp, m); 17343b29369SRobert Watson if (error) 17443b29369SRobert Watson senderr(error); 17543b29369SRobert Watson #endif 17643b29369SRobert Watson 1776eeac1d9SJulian Elischer M_PROFILE(m); 178afbe3a0fSPoul-Henning Kamp if (ifp->if_flags & IFF_MONITOR) 179afbe3a0fSPoul-Henning Kamp senderr(ENETDOWN); 18013f4c340SRobert Watson if (!((ifp->if_flags & IFF_UP) && 18113f4c340SRobert Watson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 182df8bae1dSRodney W. Grimes senderr(ENETDOWN); 1837f760c48SMatthew N. Dodd 18484dd0fd0SJulian Elischer hlen = ETHER_HDR_LEN; 185df8bae1dSRodney W. Grimes switch (dst->sa_family) { 186df8bae1dSRodney W. Grimes #ifdef INET 187df8bae1dSRodney W. Grimes case AF_INET: 188279aa3d4SKip Macy if (lle != NULL && (lle->la_flags & LLE_VALID)) 189279aa3d4SKip Macy memcpy(edst, &lle->ll_addr.mac16, sizeof(edst)); 190279aa3d4SKip Macy else 1916e6b3f7cSQing Li error = arpresolve(ifp, rt0, m, dst, edst, &lle); 192cd46a114SLuigi Rizzo if (error) 193cd46a114SLuigi Rizzo return (error == EWOULDBLOCK ? 0 : error); 19434bed8b0SDavid Greenman type = htons(ETHERTYPE_IP); 195df8bae1dSRodney W. Grimes break; 19643a6c75aSMatthew N. Dodd case AF_ARP: 19743a6c75aSMatthew N. Dodd { 19843a6c75aSMatthew N. Dodd struct arphdr *ah; 19943a6c75aSMatthew N. Dodd ah = mtod(m, struct arphdr *); 20043a6c75aSMatthew N. Dodd ah->ar_hrd = htons(ARPHRD_ETHER); 20143a6c75aSMatthew N. Dodd 202c54c76ccSOleg Bulyzhin loop_copy = 0; /* if this is for us, don't do it */ 20343a6c75aSMatthew N. Dodd 20443a6c75aSMatthew N. Dodd switch(ntohs(ah->ar_op)) { 20543a6c75aSMatthew N. Dodd case ARPOP_REVREQUEST: 20643a6c75aSMatthew N. Dodd case ARPOP_REVREPLY: 20743a6c75aSMatthew N. Dodd type = htons(ETHERTYPE_REVARP); 20843a6c75aSMatthew N. Dodd break; 20943a6c75aSMatthew N. Dodd case ARPOP_REQUEST: 21043a6c75aSMatthew N. Dodd case ARPOP_REPLY: 21143a6c75aSMatthew N. Dodd default: 21243a6c75aSMatthew N. Dodd type = htons(ETHERTYPE_ARP); 21343a6c75aSMatthew N. Dodd break; 21443a6c75aSMatthew N. Dodd } 21543a6c75aSMatthew N. Dodd 21643a6c75aSMatthew N. Dodd if (m->m_flags & M_BCAST) 21743a6c75aSMatthew N. Dodd bcopy(ifp->if_broadcastaddr, edst, ETHER_ADDR_LEN); 21843a6c75aSMatthew N. Dodd else 21943a6c75aSMatthew N. Dodd bcopy(ar_tha(ah), edst, ETHER_ADDR_LEN); 22043a6c75aSMatthew N. Dodd 22143a6c75aSMatthew N. Dodd } 22243a6c75aSMatthew N. Dodd break; 223df8bae1dSRodney W. Grimes #endif 22482cd038dSYoshinobu Inoue #ifdef INET6 22582cd038dSYoshinobu Inoue case AF_INET6: 226279aa3d4SKip Macy if (lle != NULL && (lle->la_flags & LLE_VALID)) 227279aa3d4SKip Macy memcpy(edst, &lle->ll_addr.mac16, sizeof(edst)); 228279aa3d4SKip Macy else 2299928dafbSQing Li error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); 230cd46a114SLuigi Rizzo if (error) 231cd46a114SLuigi Rizzo return error; 23282cd038dSYoshinobu Inoue type = htons(ETHERTYPE_IPV6); 23382cd038dSYoshinobu Inoue break; 23482cd038dSYoshinobu Inoue #endif 235114ae644SMike Smith case pseudo_AF_HDRCMPLT: 23647e8d432SGleb Smirnoff { 23747e8d432SGleb Smirnoff const struct ether_header *eh; 23847e8d432SGleb Smirnoff 239114ae644SMike Smith hdrcmplt = 1; 24047e8d432SGleb Smirnoff eh = (const struct ether_header *)dst->sa_data; 241114ae644SMike Smith (void)memcpy(esrc, eh->ether_shost, sizeof (esrc)); 242114ae644SMike Smith /* FALLTHROUGH */ 243114ae644SMike Smith 244df8bae1dSRodney W. Grimes case AF_UNSPEC: 245c54c76ccSOleg Bulyzhin loop_copy = 0; /* if this is for us, don't do it */ 24647e8d432SGleb Smirnoff eh = (const struct ether_header *)dst->sa_data; 24794a5d9b6SDavid Greenman (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); 248df8bae1dSRodney W. Grimes type = eh->ether_type; 249df8bae1dSRodney W. Grimes break; 25047e8d432SGleb Smirnoff } 251df8bae1dSRodney W. Grimes default: 25229e1b85fSBrooks Davis if_printf(ifp, "can't handle af%d\n", dst->sa_family); 253df8bae1dSRodney W. Grimes senderr(EAFNOSUPPORT); 254df8bae1dSRodney W. Grimes } 255df8bae1dSRodney W. Grimes 2566e6b3f7cSQing Li if (lle != NULL && (lle->la_flags & LLE_IFADDR)) { 25722f8ce43SAlexander V. Chernikov update_mbuf_csumflags(m, m); 2586e6b3f7cSQing Li return (if_simloop(ifp, m, dst->sa_family, 0)); 2596e6b3f7cSQing Li } 2606e6b3f7cSQing Li 261df8bae1dSRodney W. Grimes /* 262df8bae1dSRodney W. Grimes * Add local net header. If no space in first mbuf, 263df8bae1dSRodney W. Grimes * allocate another. 264df8bae1dSRodney W. Grimes */ 265eb1b1807SGleb Smirnoff M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT); 2662166ffe8SRobert Watson if (m == NULL) 267df8bae1dSRodney W. Grimes senderr(ENOBUFS); 268df8bae1dSRodney W. Grimes eh = mtod(m, struct ether_header *); 26994a5d9b6SDavid Greenman (void)memcpy(&eh->ether_type, &type, 270df8bae1dSRodney W. Grimes sizeof(eh->ether_type)); 27194a5d9b6SDavid Greenman (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); 272114ae644SMike Smith if (hdrcmplt) 273114ae644SMike Smith (void)memcpy(eh->ether_shost, esrc, 274114ae644SMike Smith sizeof(eh->ether_shost)); 275114ae644SMike Smith else 2764a0d6638SRuslan Ermilov (void)memcpy(eh->ether_shost, IF_LLADDR(ifp), 277df8bae1dSRodney W. Grimes sizeof(eh->ether_shost)); 278ed7509acSJulian Elischer 279ed7509acSJulian Elischer /* 280ed7509acSJulian Elischer * If a simplex interface, and the packet is being sent to our 281ed7509acSJulian Elischer * Ethernet address or a broadcast address, loopback a copy. 282ed7509acSJulian Elischer * XXX To make a simplex device behave exactly like a duplex 283ed7509acSJulian Elischer * device, we should copy in the case of sending to our own 284ed7509acSJulian Elischer * ethernet address (thus letting the original actually appear 285ed7509acSJulian Elischer * on the wire). However, we don't do that here for security 286ed7509acSJulian Elischer * reasons and compatibility with the original behavior. 287ed7509acSJulian Elischer */ 288c54c76ccSOleg Bulyzhin if ((ifp->if_flags & IFF_SIMPLEX) && loop_copy && 28960ee3847SMax Laier ((t = pf_find_mtag(m)) == NULL || !t->routed)) { 290c54c76ccSOleg Bulyzhin if (m->m_flags & M_BCAST) { 29106f684b0SMatthew N. Dodd struct mbuf *n; 292ed7509acSJulian Elischer 293294dd290SLuigi Rizzo /* 294294dd290SLuigi Rizzo * Because if_simloop() modifies the packet, we need a 295294dd290SLuigi Rizzo * writable copy through m_dup() instead of a readonly 296294dd290SLuigi Rizzo * one as m_copy[m] would give us. The alternative would 297294dd290SLuigi Rizzo * be to modify if_simloop() to handle the readonly mbuf, 298294dd290SLuigi Rizzo * but performancewise it is mostly equivalent (trading 299294dd290SLuigi Rizzo * extra data copying vs. extra locking). 3009983b3c0SYaroslav Tykhiy * 3019983b3c0SYaroslav Tykhiy * XXX This is a local workaround. A number of less 3029983b3c0SYaroslav Tykhiy * often used kernel parts suffer from the same bug. 3039983b3c0SYaroslav Tykhiy * See PR kern/105943 for a proposed general solution. 304294dd290SLuigi Rizzo */ 305eb1b1807SGleb Smirnoff if ((n = m_dup(m, M_NOWAIT)) != NULL) { 30622f8ce43SAlexander V. Chernikov update_mbuf_csumflags(m, n); 30706a429a3SArchie Cobbs (void)if_simloop(ifp, n, dst->sa_family, hlen); 308c1404dc0SArchie Cobbs } else 309c1404dc0SArchie Cobbs ifp->if_iqdrops++; 31006f684b0SMatthew N. Dodd } else if (bcmp(eh->ether_dhost, eh->ether_shost, 31106f684b0SMatthew N. Dodd ETHER_ADDR_LEN) == 0) { 31222f8ce43SAlexander V. Chernikov update_mbuf_csumflags(m, m); 31306a429a3SArchie Cobbs (void) if_simloop(ifp, m, dst->sa_family, hlen); 314ed7509acSJulian Elischer return (0); /* XXX */ 315ed7509acSJulian Elischer } 316ed7509acSJulian Elischer } 3172e2de7f2SArchie Cobbs 3183f7d1396SAndrew Thompson /* 3193f7d1396SAndrew Thompson * Bridges require special output handling. 3203f7d1396SAndrew Thompson */ 3213f7d1396SAndrew Thompson if (ifp->if_bridge) { 3223f7d1396SAndrew Thompson BRIDGE_OUTPUT(ifp, m, error); 3233f7d1396SAndrew Thompson return (error); 3243f7d1396SAndrew Thompson } 3253f7d1396SAndrew Thompson 326259d2d54SBjoern A. Zeeb #if defined(INET) || defined(INET6) 327a9771948SGleb Smirnoff if (ifp->if_carp && 32808b68b0eSGleb Smirnoff (error = (*carp_output_p)(ifp, m, dst))) 329a9771948SGleb Smirnoff goto bad; 330a9771948SGleb Smirnoff #endif 331a9771948SGleb Smirnoff 332e1e1452dSArchie Cobbs /* Handle ng_ether(4) processing, if any */ 333eb46c866SGleb Smirnoff if (IFP2AC(ifp)->ac_netgraph != NULL) { 334514bcb89SPoul-Henning Kamp KASSERT(ng_ether_output_p != NULL, 335514bcb89SPoul-Henning Kamp ("ng_ether_output_p is NULL")); 336e1e1452dSArchie Cobbs if ((error = (*ng_ether_output_p)(ifp, &m)) != 0) { 337e1e1452dSArchie Cobbs bad: if (m != NULL) 338e1e1452dSArchie Cobbs m_freem(m); 339e1e1452dSArchie Cobbs return (error); 340e1e1452dSArchie Cobbs } 341e1e1452dSArchie Cobbs if (m == NULL) 342e1e1452dSArchie Cobbs return (0); 343e1e1452dSArchie Cobbs } 344e1e1452dSArchie Cobbs 345e1e1452dSArchie Cobbs /* Continue with link-layer output */ 346e1e1452dSArchie Cobbs return ether_output_frame(ifp, m); 347e1e1452dSArchie Cobbs } 348e1e1452dSArchie Cobbs 349e1e1452dSArchie Cobbs /* 350e1e1452dSArchie Cobbs * Ethernet link layer output routine to send a raw frame to the device. 351e1e1452dSArchie Cobbs * 352e1e1452dSArchie Cobbs * This assumes that the 14 byte Ethernet header is present and contiguous 353e1e1452dSArchie Cobbs * in the first mbuf (if BRIDGE'ing). 354e1e1452dSArchie Cobbs */ 355e1e1452dSArchie Cobbs int 356c1d93b05SSam Leffler ether_output_frame(struct ifnet *ifp, struct mbuf *m) 357e1e1452dSArchie Cobbs { 3587d4317bdSAlexander V. Chernikov int i; 3592b25acc1SLuigi Rizzo 3607d4317bdSAlexander V. Chernikov if (PFIL_HOOKED(&V_link_pfil_hook)) { 3617d4317bdSAlexander V. Chernikov i = pfil_run_hooks(&V_link_pfil_hook, &m, ifp, PFIL_OUT, NULL); 3627d4317bdSAlexander V. Chernikov 3637d4317bdSAlexander V. Chernikov if (i != 0) 3647d4317bdSAlexander V. Chernikov return (EACCES); 3657d4317bdSAlexander V. Chernikov 3667d4317bdSAlexander V. Chernikov if (m == NULL) 3677d4317bdSAlexander V. Chernikov return (0); 3684b984093SLuigi Rizzo } 3692b25acc1SLuigi Rizzo 370df8bae1dSRodney W. Grimes /* 371df5e1987SJonathan Lemon * Queue message on interface, update output statistics if 372df5e1987SJonathan Lemon * successful, and start output if interface not yet active. 373df8bae1dSRodney W. Grimes */ 374aea78d20SKip Macy return ((ifp->if_transmit)(ifp, m)); 375df8bae1dSRodney W. Grimes } 376df8bae1dSRodney W. Grimes 377d7647d96SDag-Erling Smørgrav #if defined(INET) || defined(INET6) 378d7647d96SDag-Erling Smørgrav #endif 3794b984093SLuigi Rizzo 3804b984093SLuigi Rizzo /* 381c1d93b05SSam Leffler * Process a received Ethernet packet; the packet is in the 382c1d93b05SSam Leffler * mbuf chain m with the ethernet header at the front. 383df8bae1dSRodney W. Grimes */ 384c1d93b05SSam Leffler static void 3856cb52192SRobert Watson ether_input_internal(struct ifnet *ifp, struct mbuf *m) 386df8bae1dSRodney W. Grimes { 387c1d93b05SSam Leffler struct ether_header *eh; 388c1d93b05SSam Leffler u_short etype; 389df8bae1dSRodney W. Grimes 39069462a82SBruce M Simpson if ((ifp->if_flags & IFF_UP) == 0) { 39169462a82SBruce M Simpson m_freem(m); 39269462a82SBruce M Simpson return; 39369462a82SBruce M Simpson } 39469462a82SBruce M Simpson #ifdef DIAGNOSTIC 39569462a82SBruce M Simpson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 39669462a82SBruce M Simpson if_printf(ifp, "discard frame at !IFF_DRV_RUNNING\n"); 39769462a82SBruce M Simpson m_freem(m); 39869462a82SBruce M Simpson return; 39969462a82SBruce M Simpson } 40069462a82SBruce M Simpson #endif 401c1d93b05SSam Leffler /* 402c1d93b05SSam Leffler * Do consistency checks to verify assumptions 403c1d93b05SSam Leffler * made by code past this point. 404c1d93b05SSam Leffler */ 405c1d93b05SSam Leffler if ((m->m_flags & M_PKTHDR) == 0) { 406c1d93b05SSam Leffler if_printf(ifp, "discard frame w/o packet header\n"); 407c1d93b05SSam Leffler ifp->if_ierrors++; 408c939f1aeSLuigi Rizzo m_freem(m); 409c939f1aeSLuigi Rizzo return; 410c939f1aeSLuigi Rizzo } 411797f247bSMatthew N. Dodd if (m->m_len < ETHER_HDR_LEN) { 412c1d93b05SSam Leffler /* XXX maybe should pullup? */ 413c1d93b05SSam Leffler if_printf(ifp, "discard frame w/o leading ethernet " 414c1d93b05SSam Leffler "header (len %u pkt len %u)\n", 415c1d93b05SSam Leffler m->m_len, m->m_pkthdr.len); 416c1d93b05SSam Leffler ifp->if_ierrors++; 417c1d93b05SSam Leffler m_freem(m); 418c1d93b05SSam Leffler return; 4192e2de7f2SArchie Cobbs } 420c1d93b05SSam Leffler eh = mtod(m, struct ether_header *); 421c1d93b05SSam Leffler etype = ntohs(eh->ether_type); 422c1d93b05SSam Leffler if (m->m_pkthdr.rcvif == NULL) { 423c1d93b05SSam Leffler if_printf(ifp, "discard frame w/o interface pointer\n"); 424c1d93b05SSam Leffler ifp->if_ierrors++; 425c1d93b05SSam Leffler m_freem(m); 426c1d93b05SSam Leffler return; 427c1d93b05SSam Leffler } 428c1d93b05SSam Leffler #ifdef DIAGNOSTIC 429c1d93b05SSam Leffler if (m->m_pkthdr.rcvif != ifp) { 4309bf40edeSBrooks Davis if_printf(ifp, "Warning, frame marked as received on %s\n", 4319bf40edeSBrooks Davis m->m_pkthdr.rcvif->if_xname); 432c1d93b05SSam Leffler } 433c1d93b05SSam Leffler #endif 434c1d93b05SSam Leffler 43521ca7b57SMarko Zec CURVNET_SET_QUIET(ifp->if_vnet); 43621ca7b57SMarko Zec 43769462a82SBruce M Simpson if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 43869462a82SBruce M Simpson if (ETHER_IS_BROADCAST(eh->ether_dhost)) 43969462a82SBruce M Simpson m->m_flags |= M_BCAST; 44069462a82SBruce M Simpson else 44169462a82SBruce M Simpson m->m_flags |= M_MCAST; 44269462a82SBruce M Simpson ifp->if_imcasts++; 44369462a82SBruce M Simpson } 44469462a82SBruce M Simpson 445533d8562SRobert Watson #ifdef MAC 446533d8562SRobert Watson /* 447533d8562SRobert Watson * Tag the mbuf with an appropriate MAC label before any other 448533d8562SRobert Watson * consumers can get to it. 449533d8562SRobert Watson */ 45030d239bcSRobert Watson mac_ifnet_create_mbuf(ifp, m); 451533d8562SRobert Watson #endif 452533d8562SRobert Watson 453c1d93b05SSam Leffler /* 45469462a82SBruce M Simpson * Give bpf a chance at the packet. 455c1d93b05SSam Leffler */ 456d05d4616SChristian S.J. Peron ETHER_BPF_MTAP(ifp, m); 4572e2de7f2SArchie Cobbs 45869462a82SBruce M Simpson /* 45969462a82SBruce M Simpson * If the CRC is still on the packet, trim it off. We do this once 46069462a82SBruce M Simpson * and once only in case we are re-entered. Nothing else on the 46169462a82SBruce M Simpson * Ethernet receive path expects to see the FCS. 46269462a82SBruce M Simpson */ 463c1d93b05SSam Leffler if (m->m_flags & M_HASFCS) { 464c1d93b05SSam Leffler m_adj(m, -ETHER_CRC_LEN); 465c1d93b05SSam Leffler m->m_flags &= ~M_HASFCS; 466c1d93b05SSam Leffler } 467c1d93b05SSam Leffler 4684cdc1f54SGleb Smirnoff if (!(ifp->if_capenable & IFCAP_HWSTATS)) 469c1d93b05SSam Leffler ifp->if_ibytes += m->m_pkthdr.len; 47005463bb5SDavid Greenman 47169462a82SBruce M Simpson /* Allow monitor mode to claim this frame, after stats are updated. */ 472de572b37SChristian S.J. Peron if (ifp->if_flags & IFF_MONITOR) { 473de572b37SChristian S.J. Peron m_freem(m); 47421ca7b57SMarko Zec CURVNET_RESTORE(); 475de572b37SChristian S.J. Peron return; 476de572b37SChristian S.J. Peron } 477de572b37SChristian S.J. Peron 47818242d3bSAndrew Thompson /* Handle input from a lagg(4) port */ 479b47888ceSAndrew Thompson if (ifp->if_type == IFT_IEEE8023ADLAG) { 48018242d3bSAndrew Thompson KASSERT(lagg_input_p != NULL, 48118242d3bSAndrew Thompson ("%s: if_lagg not loaded!", __func__)); 48218242d3bSAndrew Thompson m = (*lagg_input_p)(ifp, m); 483b47888ceSAndrew Thompson if (m != NULL) 484b47888ceSAndrew Thompson ifp = m->m_pkthdr.rcvif; 4852db13e75SMarko Zec else { 4862db13e75SMarko Zec CURVNET_RESTORE(); 487b47888ceSAndrew Thompson return; 488b47888ceSAndrew Thompson } 4892db13e75SMarko Zec } 490b47888ceSAndrew Thompson 49169462a82SBruce M Simpson /* 49269462a82SBruce M Simpson * If the hardware did not process an 802.1Q tag, do this now, 49369462a82SBruce M Simpson * to allow 802.1P priority frames to be passed to the main input 49469462a82SBruce M Simpson * path correctly. 49569462a82SBruce M Simpson * TODO: Deal with Q-in-Q frames, but not arbitrary nesting levels. 49669462a82SBruce M Simpson */ 49769462a82SBruce M Simpson if ((m->m_flags & M_VLANTAG) == 0 && etype == ETHERTYPE_VLAN) { 49869462a82SBruce M Simpson struct ether_vlan_header *evl; 49969462a82SBruce M Simpson 50069462a82SBruce M Simpson if (m->m_len < sizeof(*evl) && 50169462a82SBruce M Simpson (m = m_pullup(m, sizeof(*evl))) == NULL) { 502402d5e27SBruce M Simpson #ifdef DIAGNOSTIC 50369462a82SBruce M Simpson if_printf(ifp, "cannot pullup VLAN header\n"); 504402d5e27SBruce M Simpson #endif 50569462a82SBruce M Simpson ifp->if_ierrors++; 50669462a82SBruce M Simpson m_freem(m); 5072db13e75SMarko Zec CURVNET_RESTORE(); 50869462a82SBruce M Simpson return; 50969462a82SBruce M Simpson } 51069462a82SBruce M Simpson 51169462a82SBruce M Simpson evl = mtod(m, struct ether_vlan_header *); 51269462a82SBruce M Simpson m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag); 51369462a82SBruce M Simpson m->m_flags |= M_VLANTAG; 51469462a82SBruce M Simpson 51569462a82SBruce M Simpson bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN, 51669462a82SBruce M Simpson ETHER_HDR_LEN - ETHER_TYPE_LEN); 51769462a82SBruce M Simpson m_adj(m, ETHER_VLAN_ENCAP_LEN); 51897cce87fSGleb Smirnoff eh = mtod(m, struct ether_header *); 51969462a82SBruce M Simpson } 52069462a82SBruce M Simpson 521a34c6aebSBjoern A. Zeeb M_SETFIB(m, ifp->if_fib); 522a34c6aebSBjoern A. Zeeb 52369462a82SBruce M Simpson /* Allow ng_ether(4) to claim this frame. */ 524eb46c866SGleb Smirnoff if (IFP2AC(ifp)->ac_netgraph != NULL) { 525514bcb89SPoul-Henning Kamp KASSERT(ng_ether_input_p != NULL, 52669462a82SBruce M Simpson ("%s: ng_ether_input_p is NULL", __func__)); 52769462a82SBruce M Simpson m->m_flags &= ~M_PROMISC; 528c1d93b05SSam Leffler (*ng_ether_input_p)(ifp, &m); 52921ca7b57SMarko Zec if (m == NULL) { 53021ca7b57SMarko Zec CURVNET_RESTORE(); 531e1e1452dSArchie Cobbs return; 532e1e1452dSArchie Cobbs } 5335e9a5429SGleb Smirnoff eh = mtod(m, struct ether_header *); 53421ca7b57SMarko Zec } 535e1e1452dSArchie Cobbs 5368f867517SAndrew Thompson /* 53769462a82SBruce M Simpson * Allow if_bridge(4) to claim this frame. 53869462a82SBruce M Simpson * The BRIDGE_INPUT() macro will update ifp if the bridge changed it 53969462a82SBruce M Simpson * and the frame should be delivered locally. 5408f867517SAndrew Thompson */ 54169462a82SBruce M Simpson if (ifp->if_bridge != NULL) { 54269462a82SBruce M Simpson m->m_flags &= ~M_PROMISC; 543fd6238a6SAndrew Thompson BRIDGE_INPUT(ifp, m); 54421ca7b57SMarko Zec if (m == NULL) { 54521ca7b57SMarko Zec CURVNET_RESTORE(); 5468f867517SAndrew Thompson return; 5478f867517SAndrew Thompson } 5485e9a5429SGleb Smirnoff eh = mtod(m, struct ether_header *); 54921ca7b57SMarko Zec } 5508f867517SAndrew Thompson 551259d2d54SBjoern A. Zeeb #if defined(INET) || defined(INET6) 55269462a82SBruce M Simpson /* 55369462a82SBruce M Simpson * Clear M_PROMISC on frame so that carp(4) will see it when the 55469462a82SBruce M Simpson * mbuf flows up to Layer 3. 55569462a82SBruce M Simpson * FreeBSD's implementation of carp(4) uses the inprotosw 55669462a82SBruce M Simpson * to dispatch IPPROTO_CARP. carp(4) also allocates its own 55769462a82SBruce M Simpson * Ethernet addresses of the form 00:00:5e:00:01:xx, which 55869462a82SBruce M Simpson * is outside the scope of the M_PROMISC test below. 55969462a82SBruce M Simpson * TODO: Maintain a hash table of ethernet addresses other than 56069462a82SBruce M Simpson * ether_dhost which may be active on this ifp. 56169462a82SBruce M Simpson */ 56254bfbd51SWill Andrews if (ifp->if_carp && (*carp_forus_p)(ifp, eh->ether_dhost)) { 56369462a82SBruce M Simpson m->m_flags &= ~M_PROMISC; 56469462a82SBruce M Simpson } else 56569462a82SBruce M Simpson #endif 56669462a82SBruce M Simpson { 56769462a82SBruce M Simpson /* 568e7f8c833SBruce M Simpson * If the frame received was not for our MAC address, set the 56969462a82SBruce M Simpson * M_PROMISC flag on the mbuf chain. The frame may need to 57069462a82SBruce M Simpson * be seen by the rest of the Ethernet input path in case of 57169462a82SBruce M Simpson * re-entry (e.g. bridge, vlan, netgraph) but should not be 57269462a82SBruce M Simpson * seen by upper protocol layers. 57369462a82SBruce M Simpson */ 57469462a82SBruce M Simpson if (!ETHER_IS_MULTICAST(eh->ether_dhost) && 575e7f8c833SBruce M Simpson bcmp(IF_LLADDR(ifp), eh->ether_dhost, ETHER_ADDR_LEN) != 0) 57669462a82SBruce M Simpson m->m_flags |= M_PROMISC; 57769462a82SBruce M Simpson } 57869462a82SBruce M Simpson 57910b1fde0SMark Murray if (harvest.ethernet) 580dd50b310SAdrian Chadd random_harvest(&(m->m_data), 12, 2, RANDOM_NET_ETHER); 58169462a82SBruce M Simpson 582acf032f5SRobert Watson ether_demux(ifp, m); 58321ca7b57SMarko Zec CURVNET_RESTORE(); 584e1e1452dSArchie Cobbs } 585e1e1452dSArchie Cobbs 586e1e1452dSArchie Cobbs /* 5876cb52192SRobert Watson * Ethernet input dispatch; by default, direct dispatch here regardless of 5887527624eSRobert Watson * global configuration. However, if RSS is enabled, hook up RSS affinity 5897527624eSRobert Watson * so that when deferred or hybrid dispatch is enabled, we can redistribute 5907527624eSRobert Watson * load based on RSS. 5917527624eSRobert Watson * 5927527624eSRobert Watson * XXXRW: Would be nice if the ifnet passed up a flag indicating whether or 5937527624eSRobert Watson * not it had already done work distribution via multi-queue. Then we could 5947527624eSRobert Watson * direct dispatch in the event load balancing was already complete and 5957527624eSRobert Watson * handle the case of interfaces with different capabilities better. 5967527624eSRobert Watson * 5977527624eSRobert Watson * XXXRW: Sort of want an M_DISTRIBUTED flag to avoid multiple distributions 5987527624eSRobert Watson * at multiple layers? 5997527624eSRobert Watson * 6007527624eSRobert Watson * XXXRW: For now, enable all this only if RSS is compiled in, although it 6017527624eSRobert Watson * works fine without RSS. Need to characterise the performance overhead 6027527624eSRobert Watson * of the detour through the netisr code in the event the result is always 6037527624eSRobert Watson * direct dispatch. 6046cb52192SRobert Watson */ 6056cb52192SRobert Watson static void 6066cb52192SRobert Watson ether_nh_input(struct mbuf *m) 6076cb52192SRobert Watson { 6086cb52192SRobert Watson 6096cb52192SRobert Watson ether_input_internal(m->m_pkthdr.rcvif, m); 6106cb52192SRobert Watson } 6116cb52192SRobert Watson 6126cb52192SRobert Watson static struct netisr_handler ether_nh = { 6136cb52192SRobert Watson .nh_name = "ether", 6146cb52192SRobert Watson .nh_handler = ether_nh_input, 6156cb52192SRobert Watson .nh_proto = NETISR_ETHER, 6167527624eSRobert Watson #ifdef RSS 6177527624eSRobert Watson .nh_policy = NETISR_POLICY_CPU, 6187527624eSRobert Watson .nh_dispatch = NETISR_DISPATCH_DIRECT, 6197527624eSRobert Watson .nh_m2cpuid = rss_m2cpuid, 6207527624eSRobert Watson #else 6216cb52192SRobert Watson .nh_policy = NETISR_POLICY_SOURCE, 6226cb52192SRobert Watson .nh_dispatch = NETISR_DISPATCH_DIRECT, 6237527624eSRobert Watson #endif 6246cb52192SRobert Watson }; 6256cb52192SRobert Watson 6266cb52192SRobert Watson static void 6276cb52192SRobert Watson ether_init(__unused void *arg) 6286cb52192SRobert Watson { 6296cb52192SRobert Watson 6306cb52192SRobert Watson netisr_register(ðer_nh); 6316cb52192SRobert Watson } 6326cb52192SRobert Watson SYSINIT(ether, SI_SUB_INIT_IF, SI_ORDER_ANY, ether_init, NULL); 6336cb52192SRobert Watson 6346cb52192SRobert Watson static void 6357d4317bdSAlexander V. Chernikov vnet_ether_init(__unused void *arg) 6367d4317bdSAlexander V. Chernikov { 6377d4317bdSAlexander V. Chernikov int i; 6387d4317bdSAlexander V. Chernikov 6397d4317bdSAlexander V. Chernikov /* Initialize packet filter hooks. */ 6407d4317bdSAlexander V. Chernikov V_link_pfil_hook.ph_type = PFIL_TYPE_AF; 6417d4317bdSAlexander V. Chernikov V_link_pfil_hook.ph_af = AF_LINK; 6427d4317bdSAlexander V. Chernikov if ((i = pfil_head_register(&V_link_pfil_hook)) != 0) 6437d4317bdSAlexander V. Chernikov printf("%s: WARNING: unable to register pfil link hook, " 6447d4317bdSAlexander V. Chernikov "error %d\n", __func__, i); 6457d4317bdSAlexander V. Chernikov } 6467d4317bdSAlexander V. Chernikov VNET_SYSINIT(vnet_ether_init, SI_SUB_PROTO_IF, SI_ORDER_ANY, 6477d4317bdSAlexander V. Chernikov vnet_ether_init, NULL); 6487d4317bdSAlexander V. Chernikov 6497d4317bdSAlexander V. Chernikov static void 6507d4317bdSAlexander V. Chernikov vnet_ether_destroy(__unused void *arg) 6517d4317bdSAlexander V. Chernikov { 6527d4317bdSAlexander V. Chernikov int i; 6537d4317bdSAlexander V. Chernikov 6547d4317bdSAlexander V. Chernikov if ((i = pfil_head_unregister(&V_link_pfil_hook)) != 0) 6557d4317bdSAlexander V. Chernikov printf("%s: WARNING: unable to unregister pfil link hook, " 6567d4317bdSAlexander V. Chernikov "error %d\n", __func__, i); 6577d4317bdSAlexander V. Chernikov } 6587d4317bdSAlexander V. Chernikov VNET_SYSUNINIT(vnet_ether_uninit, SI_SUB_PROTO_IF, SI_ORDER_ANY, 6597d4317bdSAlexander V. Chernikov vnet_ether_destroy, NULL); 6607d4317bdSAlexander V. Chernikov 6617d4317bdSAlexander V. Chernikov 6627d4317bdSAlexander V. Chernikov 6637d4317bdSAlexander V. Chernikov static void 6646cb52192SRobert Watson ether_input(struct ifnet *ifp, struct mbuf *m) 6656cb52192SRobert Watson { 6666cb52192SRobert Watson 6674857f5fbSGeorge V. Neville-Neil struct mbuf *mn; 6684857f5fbSGeorge V. Neville-Neil 6694857f5fbSGeorge V. Neville-Neil /* 6704857f5fbSGeorge V. Neville-Neil * The drivers are allowed to pass in a chain of packets linked with 6714857f5fbSGeorge V. Neville-Neil * m_nextpkt. We split them up into separate packets here and pass 6724857f5fbSGeorge V. Neville-Neil * them up. This allows the drivers to amortize the receive lock. 6734857f5fbSGeorge V. Neville-Neil */ 6744857f5fbSGeorge V. Neville-Neil while (m) { 6754857f5fbSGeorge V. Neville-Neil mn = m->m_nextpkt; 6764857f5fbSGeorge V. Neville-Neil m->m_nextpkt = NULL; 6774857f5fbSGeorge V. Neville-Neil 6786cb52192SRobert Watson /* 6796cb52192SRobert Watson * We will rely on rcvif being set properly in the deferred context, 6806cb52192SRobert Watson * so assert it is correct here. 6816cb52192SRobert Watson */ 6826cb52192SRobert Watson KASSERT(m->m_pkthdr.rcvif == ifp, ("%s: ifnet mismatch", __func__)); 6836cb52192SRobert Watson netisr_dispatch(NETISR_ETHER, m); 6844857f5fbSGeorge V. Neville-Neil m = mn; 6854857f5fbSGeorge V. Neville-Neil } 6866cb52192SRobert Watson } 6876cb52192SRobert Watson 6886cb52192SRobert Watson /* 689e1e1452dSArchie Cobbs * Upper layer processing for a received Ethernet packet. 690e1e1452dSArchie Cobbs */ 691e1e1452dSArchie Cobbs void 692c1d93b05SSam Leffler ether_demux(struct ifnet *ifp, struct mbuf *m) 693e1e1452dSArchie Cobbs { 694c1d93b05SSam Leffler struct ether_header *eh; 6957d4317bdSAlexander V. Chernikov int i, isr; 696e1e1452dSArchie Cobbs u_short ether_type; 69769462a82SBruce M Simpson 69869462a82SBruce M Simpson KASSERT(ifp != NULL, ("%s: NULL interface pointer", __func__)); 69969462a82SBruce M Simpson 7007d4317bdSAlexander V. Chernikov /* Do not grab PROMISC frames in case we are re-entered. */ 7017d4317bdSAlexander V. Chernikov if (PFIL_HOOKED(&V_link_pfil_hook) && !(m->m_flags & M_PROMISC)) { 7027d4317bdSAlexander V. Chernikov i = pfil_run_hooks(&V_link_pfil_hook, &m, ifp, PFIL_IN, NULL); 7037d4317bdSAlexander V. Chernikov 7047d4317bdSAlexander V. Chernikov if (i != 0 || m == NULL) 7057d4317bdSAlexander V. Chernikov return; 70669462a82SBruce M Simpson } 7077d4317bdSAlexander V. Chernikov 708c1d93b05SSam Leffler eh = mtod(m, struct ether_header *); 709cd0cd014SJoerg Wunsch ether_type = ntohs(eh->ether_type); 710c1d93b05SSam Leffler 711a9771948SGleb Smirnoff /* 71269462a82SBruce M Simpson * If this frame has a VLAN tag other than 0, call vlan_input() 71369462a82SBruce M Simpson * if its module is loaded. Otherwise, drop. 714a9771948SGleb Smirnoff */ 71569462a82SBruce M Simpson if ((m->m_flags & M_VLANTAG) && 71669462a82SBruce M Simpson EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) != 0) { 71775ee267cSGleb Smirnoff if (ifp->if_vlantrunk == NULL) { 7186c23e6ccSRuslan Ermilov ifp->if_noproto++; 7196c23e6ccSRuslan Ermilov m_freem(m); 7206c23e6ccSRuslan Ermilov return; 7216c23e6ccSRuslan Ermilov } 72269462a82SBruce M Simpson KASSERT(vlan_input_p != NULL,("%s: VLAN not loaded!", 72369462a82SBruce M Simpson __func__)); 72469462a82SBruce M Simpson /* Clear before possibly re-entering ether_input(). */ 72569462a82SBruce M Simpson m->m_flags &= ~M_PROMISC; 726c1d93b05SSam Leffler (*vlan_input_p)(ifp, m); 727c1d93b05SSam Leffler return; 728c1d93b05SSam Leffler } 729c1d93b05SSam Leffler 730c1d93b05SSam Leffler /* 73169462a82SBruce M Simpson * Pass promiscuously received frames to the upper layer if the user 73269462a82SBruce M Simpson * requested this by setting IFF_PPROMISC. Otherwise, drop them. 733c1d93b05SSam Leffler */ 73469462a82SBruce M Simpson if ((ifp->if_flags & IFF_PPROMISC) == 0 && (m->m_flags & M_PROMISC)) { 735c1d93b05SSam Leffler m_freem(m); 736c1d93b05SSam Leffler return; 737c1d93b05SSam Leffler } 738c1d93b05SSam Leffler 73969462a82SBruce M Simpson /* 74069462a82SBruce M Simpson * Reset layer specific mbuf flags to avoid confusing upper layers. 74169462a82SBruce M Simpson * Strip off Ethernet header. 74269462a82SBruce M Simpson */ 74369462a82SBruce M Simpson m->m_flags &= ~M_VLANTAG; 74486bd0491SAndre Oppermann m_clrprotoflags(m); 745797f247bSMatthew N. Dodd m_adj(m, ETHER_HDR_LEN); 746c1d93b05SSam Leffler 74769462a82SBruce M Simpson /* 74869462a82SBruce M Simpson * Dispatch frame to upper layer. 74969462a82SBruce M Simpson */ 750307d80beSDavid Greenman switch (ether_type) { 751df8bae1dSRodney W. Grimes #ifdef INET 752df8bae1dSRodney W. Grimes case ETHERTYPE_IP: 7535d691e6dSAndre Oppermann if ((m = ip_fastforward(m)) == NULL) 7541f91d8c5SDavid Greenman return; 7551cafed39SJonathan Lemon isr = NETISR_IP; 756df8bae1dSRodney W. Grimes break; 757df8bae1dSRodney W. Grimes 758df8bae1dSRodney W. Grimes case ETHERTYPE_ARP: 75908aadfbbSJonathan Lemon if (ifp->if_flags & IFF_NOARP) { 76008aadfbbSJonathan Lemon /* Discard packet if ARP is disabled on interface */ 76108aadfbbSJonathan Lemon m_freem(m); 76208aadfbbSJonathan Lemon return; 76308aadfbbSJonathan Lemon } 7641cafed39SJonathan Lemon isr = NETISR_ARP; 765df8bae1dSRodney W. Grimes break; 766df8bae1dSRodney W. Grimes #endif 76782cd038dSYoshinobu Inoue #ifdef INET6 76882cd038dSYoshinobu Inoue case ETHERTYPE_IPV6: 7691cafed39SJonathan Lemon isr = NETISR_IPV6; 77082cd038dSYoshinobu Inoue break; 77182cd038dSYoshinobu Inoue #endif 772df8bae1dSRodney W. Grimes default: 7731cafed39SJonathan Lemon goto discard; 774df8bae1dSRodney W. Grimes } 7751cafed39SJonathan Lemon netisr_dispatch(isr, m); 776c1d93b05SSam Leffler return; 7771cafed39SJonathan Lemon 778c1d93b05SSam Leffler discard: 779c1d93b05SSam Leffler /* 780c1d93b05SSam Leffler * Packet is to be discarded. If netgraph is present, 781c1d93b05SSam Leffler * hand the packet to it for last chance processing; 782c1d93b05SSam Leffler * otherwise dispose of it. 783c1d93b05SSam Leffler */ 784eb46c866SGleb Smirnoff if (IFP2AC(ifp)->ac_netgraph != NULL) { 785514bcb89SPoul-Henning Kamp KASSERT(ng_ether_input_orphan_p != NULL, 786514bcb89SPoul-Henning Kamp ("ng_ether_input_orphan_p is NULL")); 787c1d93b05SSam Leffler /* 788c1d93b05SSam Leffler * Put back the ethernet header so netgraph has a 789c1d93b05SSam Leffler * consistent view of inbound packets. 790c1d93b05SSam Leffler */ 791eb1b1807SGleb Smirnoff M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT); 792c1d93b05SSam Leffler (*ng_ether_input_orphan_p)(ifp, m); 793c1d93b05SSam Leffler return; 794c1d93b05SSam Leffler } 795c1d93b05SSam Leffler m_freem(m); 796c1d93b05SSam Leffler } 797c1d93b05SSam Leffler 798c1d93b05SSam Leffler /* 799c1d93b05SSam Leffler * Convert Ethernet address to printable (loggable) representation. 800c1d93b05SSam Leffler * This routine is for compatibility; it's better to just use 801c1d93b05SSam Leffler * 802c1d93b05SSam Leffler * printf("%6D", <pointer to address>, ":"); 803c1d93b05SSam Leffler * 804c1d93b05SSam Leffler * since there's no static buffer involved. 805c1d93b05SSam Leffler */ 806c1d93b05SSam Leffler char * 807c1d93b05SSam Leffler ether_sprintf(const u_char *ap) 808c1d93b05SSam Leffler { 809c1d93b05SSam Leffler static char etherbuf[18]; 810c1d93b05SSam Leffler snprintf(etherbuf, sizeof (etherbuf), "%6D", ap, ":"); 811c1d93b05SSam Leffler return (etherbuf); 812df8bae1dSRodney W. Grimes } 813df8bae1dSRodney W. Grimes 814df8bae1dSRodney W. Grimes /* 815df8bae1dSRodney W. Grimes * Perform common duties while attaching to interface list 816df8bae1dSRodney W. Grimes */ 817df8bae1dSRodney W. Grimes void 818d09ed26fSRuslan Ermilov ether_ifattach(struct ifnet *ifp, const u_int8_t *lla) 819df8bae1dSRodney W. Grimes { 820f93dfa28SBrooks Davis int i; 821098a8c3bSMatthew N. Dodd struct ifaddr *ifa; 822098a8c3bSMatthew N. Dodd struct sockaddr_dl *sdl; 823df8bae1dSRodney W. Grimes 824c1d93b05SSam Leffler ifp->if_addrlen = ETHER_ADDR_LEN; 825c1d93b05SSam Leffler ifp->if_hdrlen = ETHER_HDR_LEN; 826cfeff1b6SJonathan Lemon if_attach(ifp); 827df8bae1dSRodney W. Grimes ifp->if_mtu = ETHERMTU; 828c1d93b05SSam Leffler ifp->if_output = ether_output; 829c1d93b05SSam Leffler ifp->if_input = ether_input; 8301158dfb7SGarrett Wollman ifp->if_resolvemulti = ether_resolvemulti; 831d3c351c5SMarko Zec #ifdef VIMAGE 832d3c351c5SMarko Zec ifp->if_reassign = ether_reassign; 833d3c351c5SMarko Zec #endif 834a330e1f1SGary Palmer if (ifp->if_baudrate == 0) 835c1d93b05SSam Leffler ifp->if_baudrate = IF_Mbps(10); /* just a default */ 836322dcb8dSMax Khon ifp->if_broadcastaddr = etherbroadcastaddr; 837c1d93b05SSam Leffler 8384a0d6638SRuslan Ermilov ifa = ifp->if_addr; 8396e551fb6SDavid E. O'Brien KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 84059562606SGarrett Wollman sdl = (struct sockaddr_dl *)ifa->ifa_addr; 841df8bae1dSRodney W. Grimes sdl->sdl_type = IFT_ETHER; 842df8bae1dSRodney W. Grimes sdl->sdl_alen = ifp->if_addrlen; 843d09ed26fSRuslan Ermilov bcopy(lla, LLADDR(sdl), ifp->if_addrlen); 844c1d93b05SSam Leffler 845797f247bSMatthew N. Dodd bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN); 846e1e1452dSArchie Cobbs if (ng_ether_attach_p != NULL) 847e1e1452dSArchie Cobbs (*ng_ether_attach_p)(ifp); 848e3bbbec2SMatthew N. Dodd 849f93dfa28SBrooks Davis /* Announce Ethernet MAC address if non-zero. */ 850f93dfa28SBrooks Davis for (i = 0; i < ifp->if_addrlen; i++) 851d09ed26fSRuslan Ermilov if (lla[i] != 0) 852f93dfa28SBrooks Davis break; 853f93dfa28SBrooks Davis if (i != ifp->if_addrlen) 854d09ed26fSRuslan Ermilov if_printf(ifp, "Ethernet address: %6D\n", lla, ":"); 855ef1f9169SMarcel Moolenaar 856ef1f9169SMarcel Moolenaar uuid_ether_add(LLADDR(sdl)); 857e1e1452dSArchie Cobbs } 858e1e1452dSArchie Cobbs 85921b8ebd9SArchie Cobbs /* 86021b8ebd9SArchie Cobbs * Perform common duties while detaching an Ethernet interface 86121b8ebd9SArchie Cobbs */ 86221b8ebd9SArchie Cobbs void 863c1d93b05SSam Leffler ether_ifdetach(struct ifnet *ifp) 86421b8ebd9SArchie Cobbs { 865ef1f9169SMarcel Moolenaar struct sockaddr_dl *sdl; 866ef1f9169SMarcel Moolenaar 867ef1f9169SMarcel Moolenaar sdl = (struct sockaddr_dl *)(ifp->if_addr->ifa_addr); 868ef1f9169SMarcel Moolenaar uuid_ether_del(LLADDR(sdl)); 869ef1f9169SMarcel Moolenaar 870514bcb89SPoul-Henning Kamp if (IFP2AC(ifp)->ac_netgraph != NULL) { 871514bcb89SPoul-Henning Kamp KASSERT(ng_ether_detach_p != NULL, 872514bcb89SPoul-Henning Kamp ("ng_ether_detach_p is NULL")); 87321b8ebd9SArchie Cobbs (*ng_ether_detach_p)(ifp); 874514bcb89SPoul-Henning Kamp } 87520a65f37SAndrew Thompson 87621b8ebd9SArchie Cobbs bpfdetach(ifp); 87721b8ebd9SArchie Cobbs if_detach(ifp); 87821b8ebd9SArchie Cobbs } 87921b8ebd9SArchie Cobbs 880d3c351c5SMarko Zec #ifdef VIMAGE 881d3c351c5SMarko Zec void 882d3c351c5SMarko Zec ether_reassign(struct ifnet *ifp, struct vnet *new_vnet, char *unused __unused) 883d3c351c5SMarko Zec { 884d3c351c5SMarko Zec 885d3c351c5SMarko Zec if (IFP2AC(ifp)->ac_netgraph != NULL) { 886d3c351c5SMarko Zec KASSERT(ng_ether_detach_p != NULL, 887d3c351c5SMarko Zec ("ng_ether_detach_p is NULL")); 888d3c351c5SMarko Zec (*ng_ether_detach_p)(ifp); 889d3c351c5SMarko Zec } 890d3c351c5SMarko Zec 891d3c351c5SMarko Zec if (ng_ether_attach_p != NULL) { 892d3c351c5SMarko Zec CURVNET_SET_QUIET(new_vnet); 893d3c351c5SMarko Zec (*ng_ether_attach_p)(ifp); 894d3c351c5SMarko Zec CURVNET_RESTORE(); 895d3c351c5SMarko Zec } 896d3c351c5SMarko Zec } 897d3c351c5SMarko Zec #endif 898d3c351c5SMarko Zec 899ce02431fSDoug Rabson SYSCTL_DECL(_net_link); 900602d513cSGarrett Wollman SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); 90130106f6aSPoul-Henning Kamp 90216b4a343SChristian Weisgerber #if 0 90316b4a343SChristian Weisgerber /* 90416b4a343SChristian Weisgerber * This is for reference. We have a table-driven version 90516b4a343SChristian Weisgerber * of the little-endian crc32 generator, which is faster 90616b4a343SChristian Weisgerber * than the double-loop. 90716b4a343SChristian Weisgerber */ 90816b4a343SChristian Weisgerber uint32_t 90916b4a343SChristian Weisgerber ether_crc32_le(const uint8_t *buf, size_t len) 91016b4a343SChristian Weisgerber { 91116b4a343SChristian Weisgerber size_t i; 91216b4a343SChristian Weisgerber uint32_t crc; 91316b4a343SChristian Weisgerber int bit; 91416b4a343SChristian Weisgerber uint8_t data; 91516b4a343SChristian Weisgerber 91616b4a343SChristian Weisgerber crc = 0xffffffff; /* initial value */ 91716b4a343SChristian Weisgerber 91816b4a343SChristian Weisgerber for (i = 0; i < len; i++) { 919933dad75SAntoine Brodin for (data = *buf++, bit = 0; bit < 8; bit++, data >>= 1) { 92016b4a343SChristian Weisgerber carry = (crc ^ data) & 1; 92116b4a343SChristian Weisgerber crc >>= 1; 92216b4a343SChristian Weisgerber if (carry) 92316b4a343SChristian Weisgerber crc = (crc ^ ETHER_CRC_POLY_LE); 92416b4a343SChristian Weisgerber } 925933dad75SAntoine Brodin } 92616b4a343SChristian Weisgerber 92716b4a343SChristian Weisgerber return (crc); 92816b4a343SChristian Weisgerber } 92916b4a343SChristian Weisgerber #else 93016b4a343SChristian Weisgerber uint32_t 93116b4a343SChristian Weisgerber ether_crc32_le(const uint8_t *buf, size_t len) 93216b4a343SChristian Weisgerber { 93316b4a343SChristian Weisgerber static const uint32_t crctab[] = { 93416b4a343SChristian Weisgerber 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 93516b4a343SChristian Weisgerber 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 93616b4a343SChristian Weisgerber 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 93716b4a343SChristian Weisgerber 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c 93816b4a343SChristian Weisgerber }; 93916b4a343SChristian Weisgerber size_t i; 94016b4a343SChristian Weisgerber uint32_t crc; 94116b4a343SChristian Weisgerber 94216b4a343SChristian Weisgerber crc = 0xffffffff; /* initial value */ 94316b4a343SChristian Weisgerber 94416b4a343SChristian Weisgerber for (i = 0; i < len; i++) { 94516b4a343SChristian Weisgerber crc ^= buf[i]; 94616b4a343SChristian Weisgerber crc = (crc >> 4) ^ crctab[crc & 0xf]; 94716b4a343SChristian Weisgerber crc = (crc >> 4) ^ crctab[crc & 0xf]; 94816b4a343SChristian Weisgerber } 94916b4a343SChristian Weisgerber 95016b4a343SChristian Weisgerber return (crc); 95116b4a343SChristian Weisgerber } 95216b4a343SChristian Weisgerber #endif 95316b4a343SChristian Weisgerber 95416b4a343SChristian Weisgerber uint32_t 95516b4a343SChristian Weisgerber ether_crc32_be(const uint8_t *buf, size_t len) 95616b4a343SChristian Weisgerber { 95716b4a343SChristian Weisgerber size_t i; 95816b4a343SChristian Weisgerber uint32_t crc, carry; 95916b4a343SChristian Weisgerber int bit; 96016b4a343SChristian Weisgerber uint8_t data; 96116b4a343SChristian Weisgerber 96216b4a343SChristian Weisgerber crc = 0xffffffff; /* initial value */ 96316b4a343SChristian Weisgerber 96416b4a343SChristian Weisgerber for (i = 0; i < len; i++) { 96516b4a343SChristian Weisgerber for (data = *buf++, bit = 0; bit < 8; bit++, data >>= 1) { 96616b4a343SChristian Weisgerber carry = ((crc & 0x80000000) ? 1 : 0) ^ (data & 0x01); 96716b4a343SChristian Weisgerber crc <<= 1; 96816b4a343SChristian Weisgerber if (carry) 96916b4a343SChristian Weisgerber crc = (crc ^ ETHER_CRC_POLY_BE) | carry; 97016b4a343SChristian Weisgerber } 97116b4a343SChristian Weisgerber } 97216b4a343SChristian Weisgerber 97316b4a343SChristian Weisgerber return (crc); 97416b4a343SChristian Weisgerber } 97516b4a343SChristian Weisgerber 976fb583156SDavid Greenman int 977995c7fd1SYaroslav Tykhiy ether_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 97830106f6aSPoul-Henning Kamp { 97930106f6aSPoul-Henning Kamp struct ifaddr *ifa = (struct ifaddr *) data; 98030106f6aSPoul-Henning Kamp struct ifreq *ifr = (struct ifreq *) data; 981fb583156SDavid Greenman int error = 0; 98230106f6aSPoul-Henning Kamp 98330106f6aSPoul-Henning Kamp switch (command) { 98430106f6aSPoul-Henning Kamp case SIOCSIFADDR: 98530106f6aSPoul-Henning Kamp ifp->if_flags |= IFF_UP; 98630106f6aSPoul-Henning Kamp 98730106f6aSPoul-Henning Kamp switch (ifa->ifa_addr->sa_family) { 98830106f6aSPoul-Henning Kamp #ifdef INET 98930106f6aSPoul-Henning Kamp case AF_INET: 99030106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); /* before arpwhohas */ 991322dcb8dSMax Khon arp_ifinit(ifp, ifa); 99230106f6aSPoul-Henning Kamp break; 99330106f6aSPoul-Henning Kamp #endif 99430106f6aSPoul-Henning Kamp default: 99530106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 99630106f6aSPoul-Henning Kamp break; 99730106f6aSPoul-Henning Kamp } 99830106f6aSPoul-Henning Kamp break; 99930106f6aSPoul-Henning Kamp 100030106f6aSPoul-Henning Kamp case SIOCGIFADDR: 100130106f6aSPoul-Henning Kamp { 100230106f6aSPoul-Henning Kamp struct sockaddr *sa; 100330106f6aSPoul-Henning Kamp 100430106f6aSPoul-Henning Kamp sa = (struct sockaddr *) & ifr->ifr_data; 10054a0d6638SRuslan Ermilov bcopy(IF_LLADDR(ifp), 100630106f6aSPoul-Henning Kamp (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 100730106f6aSPoul-Henning Kamp } 100830106f6aSPoul-Henning Kamp break; 1009fb583156SDavid Greenman 1010fb583156SDavid Greenman case SIOCSIFMTU: 1011fb583156SDavid Greenman /* 1012fb583156SDavid Greenman * Set the interface MTU. 1013fb583156SDavid Greenman */ 1014fb583156SDavid Greenman if (ifr->ifr_mtu > ETHERMTU) { 1015fb583156SDavid Greenman error = EINVAL; 1016fb583156SDavid Greenman } else { 1017fb583156SDavid Greenman ifp->if_mtu = ifr->ifr_mtu; 101830106f6aSPoul-Henning Kamp } 1019fb583156SDavid Greenman break; 1020c1d93b05SSam Leffler default: 1021c1d93b05SSam Leffler error = EINVAL; /* XXX netbsd has ENOTTY??? */ 1022c1d93b05SSam Leffler break; 1023fb583156SDavid Greenman } 1024fb583156SDavid Greenman return (error); 102530106f6aSPoul-Henning Kamp } 10261158dfb7SGarrett Wollman 102737c84183SPoul-Henning Kamp static int 102872fd1b6aSDag-Erling Smørgrav ether_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 102972fd1b6aSDag-Erling Smørgrav struct sockaddr *sa) 10301158dfb7SGarrett Wollman { 10311158dfb7SGarrett Wollman struct sockaddr_dl *sdl; 1032d7647d96SDag-Erling Smørgrav #ifdef INET 10331158dfb7SGarrett Wollman struct sockaddr_in *sin; 1034d7647d96SDag-Erling Smørgrav #endif 103582cd038dSYoshinobu Inoue #ifdef INET6 103682cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6; 103782cd038dSYoshinobu Inoue #endif 10381158dfb7SGarrett Wollman u_char *e_addr; 10391158dfb7SGarrett Wollman 10401158dfb7SGarrett Wollman switch(sa->sa_family) { 10411158dfb7SGarrett Wollman case AF_LINK: 10427f33a738SJulian Elischer /* 10437f33a738SJulian Elischer * No mapping needed. Just check that it's a valid MC address. 10447f33a738SJulian Elischer */ 10451158dfb7SGarrett Wollman sdl = (struct sockaddr_dl *)sa; 10461158dfb7SGarrett Wollman e_addr = LLADDR(sdl); 1047086e98c4SBruce M Simpson if (!ETHER_IS_MULTICAST(e_addr)) 10481158dfb7SGarrett Wollman return EADDRNOTAVAIL; 10491158dfb7SGarrett Wollman *llsa = 0; 10501158dfb7SGarrett Wollman return 0; 10511158dfb7SGarrett Wollman 10521158dfb7SGarrett Wollman #ifdef INET 10531158dfb7SGarrett Wollman case AF_INET: 10541158dfb7SGarrett Wollman sin = (struct sockaddr_in *)sa; 10551158dfb7SGarrett Wollman if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 10561158dfb7SGarrett Wollman return EADDRNOTAVAIL; 105795fbe4d0SAlexander V. Chernikov sdl = link_init_sdl(ifp, *llsa, IFT_ETHER); 10581158dfb7SGarrett Wollman sdl->sdl_alen = ETHER_ADDR_LEN; 10591158dfb7SGarrett Wollman e_addr = LLADDR(sdl); 10601158dfb7SGarrett Wollman ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 10611158dfb7SGarrett Wollman *llsa = (struct sockaddr *)sdl; 10621158dfb7SGarrett Wollman return 0; 10631158dfb7SGarrett Wollman #endif 106482cd038dSYoshinobu Inoue #ifdef INET6 106582cd038dSYoshinobu Inoue case AF_INET6: 106682cd038dSYoshinobu Inoue sin6 = (struct sockaddr_in6 *)sa; 1067595b8a1cSJun-ichiro itojun Hagino if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1068595b8a1cSJun-ichiro itojun Hagino /* 1069595b8a1cSJun-ichiro itojun Hagino * An IP6 address of 0 means listen to all 1070595b8a1cSJun-ichiro itojun Hagino * of the Ethernet multicast address used for IP6. 1071595b8a1cSJun-ichiro itojun Hagino * (This is used for multicast routers.) 1072595b8a1cSJun-ichiro itojun Hagino */ 1073595b8a1cSJun-ichiro itojun Hagino ifp->if_flags |= IFF_ALLMULTI; 1074595b8a1cSJun-ichiro itojun Hagino *llsa = 0; 1075595b8a1cSJun-ichiro itojun Hagino return 0; 1076595b8a1cSJun-ichiro itojun Hagino } 107782cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 107882cd038dSYoshinobu Inoue return EADDRNOTAVAIL; 107995fbe4d0SAlexander V. Chernikov sdl = link_init_sdl(ifp, *llsa, IFT_ETHER); 108082cd038dSYoshinobu Inoue sdl->sdl_alen = ETHER_ADDR_LEN; 108182cd038dSYoshinobu Inoue e_addr = LLADDR(sdl); 108282cd038dSYoshinobu Inoue ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 108382cd038dSYoshinobu Inoue *llsa = (struct sockaddr *)sdl; 108482cd038dSYoshinobu Inoue return 0; 108582cd038dSYoshinobu Inoue #endif 10861158dfb7SGarrett Wollman 10871158dfb7SGarrett Wollman default: 10881158dfb7SGarrett Wollman /* 10891158dfb7SGarrett Wollman * Well, the text isn't quite right, but it's the name 10901158dfb7SGarrett Wollman * that counts... 10911158dfb7SGarrett Wollman */ 10921158dfb7SGarrett Wollman return EAFNOSUPPORT; 10931158dfb7SGarrett Wollman } 10941158dfb7SGarrett Wollman } 109540811c14SMatthew N. Dodd 1096fc74a9f9SBrooks Davis static void* 1097fc74a9f9SBrooks Davis ether_alloc(u_char type, struct ifnet *ifp) 1098fc74a9f9SBrooks Davis { 1099fc74a9f9SBrooks Davis struct arpcom *ac; 1100fc74a9f9SBrooks Davis 1101fc74a9f9SBrooks Davis ac = malloc(sizeof(struct arpcom), M_ARPCOM, M_WAITOK | M_ZERO); 1102fc74a9f9SBrooks Davis ac->ac_ifp = ifp; 1103fc74a9f9SBrooks Davis 1104fc74a9f9SBrooks Davis return (ac); 1105fc74a9f9SBrooks Davis } 1106fc74a9f9SBrooks Davis 1107fc74a9f9SBrooks Davis static void 1108fc74a9f9SBrooks Davis ether_free(void *com, u_char type) 1109fc74a9f9SBrooks Davis { 1110fc74a9f9SBrooks Davis 1111fc74a9f9SBrooks Davis free(com, M_ARPCOM); 1112fc74a9f9SBrooks Davis } 1113fc74a9f9SBrooks Davis 1114fc74a9f9SBrooks Davis static int 1115fc74a9f9SBrooks Davis ether_modevent(module_t mod, int type, void *data) 1116fc74a9f9SBrooks Davis { 1117fc74a9f9SBrooks Davis 1118fc74a9f9SBrooks Davis switch (type) { 1119fc74a9f9SBrooks Davis case MOD_LOAD: 1120fc74a9f9SBrooks Davis if_register_com_alloc(IFT_ETHER, ether_alloc, ether_free); 1121fc74a9f9SBrooks Davis break; 1122fc74a9f9SBrooks Davis case MOD_UNLOAD: 1123fc74a9f9SBrooks Davis if_deregister_com_alloc(IFT_ETHER); 1124fc74a9f9SBrooks Davis break; 1125fc74a9f9SBrooks Davis default: 1126fc74a9f9SBrooks Davis return EOPNOTSUPP; 1127fc74a9f9SBrooks Davis } 1128fc74a9f9SBrooks Davis 1129fc74a9f9SBrooks Davis return (0); 1130fc74a9f9SBrooks Davis } 1131fc74a9f9SBrooks Davis 113240811c14SMatthew N. Dodd static moduledata_t ether_mod = { 113340811c14SMatthew N. Dodd "ether", 1134fc74a9f9SBrooks Davis ether_modevent, 11359823d527SKevin Lo 0 113640811c14SMatthew N. Dodd }; 113740811c14SMatthew N. Dodd 113852f1277eSChristian S.J. Peron void 113952f1277eSChristian S.J. Peron ether_vlan_mtap(struct bpf_if *bp, struct mbuf *m, void *data, u_int dlen) 114052f1277eSChristian S.J. Peron { 114152f1277eSChristian S.J. Peron struct ether_vlan_header vlan; 114252f1277eSChristian S.J. Peron struct mbuf mv, mb; 114352f1277eSChristian S.J. Peron 114452f1277eSChristian S.J. Peron KASSERT((m->m_flags & M_VLANTAG) != 0, 114552f1277eSChristian S.J. Peron ("%s: vlan information not present", __func__)); 114652f1277eSChristian S.J. Peron KASSERT(m->m_len >= sizeof(struct ether_header), 114752f1277eSChristian S.J. Peron ("%s: mbuf not large enough for header", __func__)); 114852f1277eSChristian S.J. Peron bcopy(mtod(m, char *), &vlan, sizeof(struct ether_header)); 114952f1277eSChristian S.J. Peron vlan.evl_proto = vlan.evl_encap_proto; 115052f1277eSChristian S.J. Peron vlan.evl_encap_proto = htons(ETHERTYPE_VLAN); 115152f1277eSChristian S.J. Peron vlan.evl_tag = htons(m->m_pkthdr.ether_vtag); 115252f1277eSChristian S.J. Peron m->m_len -= sizeof(struct ether_header); 115352f1277eSChristian S.J. Peron m->m_data += sizeof(struct ether_header); 115452f1277eSChristian S.J. Peron /* 115552f1277eSChristian S.J. Peron * If a data link has been supplied by the caller, then we will need to 115652f1277eSChristian S.J. Peron * re-create a stack allocated mbuf chain with the following structure: 115752f1277eSChristian S.J. Peron * 115852f1277eSChristian S.J. Peron * (1) mbuf #1 will contain the supplied data link 115952f1277eSChristian S.J. Peron * (2) mbuf #2 will contain the vlan header 116052f1277eSChristian S.J. Peron * (3) mbuf #3 will contain the original mbuf's packet data 116152f1277eSChristian S.J. Peron * 116252f1277eSChristian S.J. Peron * Otherwise, submit the packet and vlan header via bpf_mtap2(). 116352f1277eSChristian S.J. Peron */ 116452f1277eSChristian S.J. Peron if (data != NULL) { 116552f1277eSChristian S.J. Peron mv.m_next = m; 116652f1277eSChristian S.J. Peron mv.m_data = (caddr_t)&vlan; 116752f1277eSChristian S.J. Peron mv.m_len = sizeof(vlan); 116852f1277eSChristian S.J. Peron mb.m_next = &mv; 116952f1277eSChristian S.J. Peron mb.m_data = data; 117052f1277eSChristian S.J. Peron mb.m_len = dlen; 117152f1277eSChristian S.J. Peron bpf_mtap(bp, &mb); 117252f1277eSChristian S.J. Peron } else 117352f1277eSChristian S.J. Peron bpf_mtap2(bp, &vlan, sizeof(vlan), m); 117452f1277eSChristian S.J. Peron m->m_len += sizeof(struct ether_header); 117552f1277eSChristian S.J. Peron m->m_data -= sizeof(struct ether_header); 117652f1277eSChristian S.J. Peron } 117752f1277eSChristian S.J. Peron 117860e87ca8SAndrew Thompson struct mbuf * 1179a0cf8186SAndrew Thompson ether_vlanencap(struct mbuf *m, uint16_t tag) 118060e87ca8SAndrew Thompson { 118160e87ca8SAndrew Thompson struct ether_vlan_header *evl; 118260e87ca8SAndrew Thompson 1183eb1b1807SGleb Smirnoff M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_NOWAIT); 118460e87ca8SAndrew Thompson if (m == NULL) 118560e87ca8SAndrew Thompson return (NULL); 118660e87ca8SAndrew Thompson /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ 118760e87ca8SAndrew Thompson 118860e87ca8SAndrew Thompson if (m->m_len < sizeof(*evl)) { 118960e87ca8SAndrew Thompson m = m_pullup(m, sizeof(*evl)); 119060e87ca8SAndrew Thompson if (m == NULL) 119160e87ca8SAndrew Thompson return (NULL); 119260e87ca8SAndrew Thompson } 119360e87ca8SAndrew Thompson 119460e87ca8SAndrew Thompson /* 119560e87ca8SAndrew Thompson * Transform the Ethernet header into an Ethernet header 119660e87ca8SAndrew Thompson * with 802.1Q encapsulation. 119760e87ca8SAndrew Thompson */ 119860e87ca8SAndrew Thompson evl = mtod(m, struct ether_vlan_header *); 119960e87ca8SAndrew Thompson bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN, 120060e87ca8SAndrew Thompson (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN); 120160e87ca8SAndrew Thompson evl->evl_encap_proto = htons(ETHERTYPE_VLAN); 120260e87ca8SAndrew Thompson evl->evl_tag = htons(tag); 120360e87ca8SAndrew Thompson return (m); 120460e87ca8SAndrew Thompson } 120560e87ca8SAndrew Thompson 1206fc74a9f9SBrooks Davis DECLARE_MODULE(ether, ether_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 120740811c14SMatthew N. Dodd MODULE_VERSION(ether, 1); 1208