1df8bae1dSRodney W. Grimes /* 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 * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 377262d3e4SEivind Eklund #include "opt_atalk.h" 381d5e9e22SEivind Eklund #include "opt_inet.h" 39cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 40430df5f4SEivind Eklund #include "opt_ipx.h" 41fb5fbe46SLuigi Rizzo #include "opt_bdg.h" 4243b29369SRobert Watson #include "opt_mac.h" 434cf49a43SJulian Elischer #include "opt_netgraph.h" 44430df5f4SEivind Eklund 45df8bae1dSRodney W. Grimes #include <sys/param.h> 46df8bae1dSRodney W. Grimes #include <sys/systm.h> 47df8bae1dSRodney W. Grimes #include <sys/kernel.h> 4843b29369SRobert Watson #include <sys/mac.h> 49df8bae1dSRodney W. Grimes #include <sys/malloc.h> 50df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 5110b1fde0SMark Murray #include <sys/random.h> 52df8bae1dSRodney W. Grimes #include <sys/socket.h> 5351a53488SBruce Evans #include <sys/sockio.h> 54602d513cSGarrett Wollman #include <sys/sysctl.h> 55df8bae1dSRodney W. Grimes 56df8bae1dSRodney W. Grimes #include <net/if.h> 57df8bae1dSRodney W. Grimes #include <net/netisr.h> 58df8bae1dSRodney W. Grimes #include <net/route.h> 59df8bae1dSRodney W. Grimes #include <net/if_llc.h> 60df8bae1dSRodney W. Grimes #include <net/if_dl.h> 61df8bae1dSRodney W. Grimes #include <net/if_types.h> 622e2de7f2SArchie Cobbs #include <net/bpf.h> 63e1e1452dSArchie Cobbs #include <net/ethernet.h> 64db69a05dSPaul Saab #include <net/bridge.h> 65df8bae1dSRodney W. Grimes 6682cd038dSYoshinobu Inoue #if defined(INET) || defined(INET6) 67df8bae1dSRodney W. Grimes #include <netinet/in.h> 68df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 69df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 704b984093SLuigi Rizzo #include <netinet/ip_fw.h> 714b984093SLuigi Rizzo #include <netinet/ip_dummynet.h> 721d5e9e22SEivind Eklund #endif 7382cd038dSYoshinobu Inoue #ifdef INET6 7482cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 7582cd038dSYoshinobu Inoue #endif 76df8bae1dSRodney W. Grimes 77cc6a66f2SJulian Elischer #ifdef IPX 78cc6a66f2SJulian Elischer #include <netipx/ipx.h> 79cc6a66f2SJulian Elischer #include <netipx/ipx_if.h> 804f93599fSBoris Popov int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m); 815accfb8cSBoris Popov int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp, 822a7e8eceSBoris Popov struct sockaddr *dst, short *tp, int *hlen); 83cc6a66f2SJulian Elischer #endif 84cc6a66f2SJulian Elischer 85df8bae1dSRodney W. Grimes #ifdef NS 86df8bae1dSRodney W. Grimes #include <netns/ns.h> 87df8bae1dSRodney W. Grimes #include <netns/ns_if.h> 88d0ec898dSJordan K. Hubbard ushort ns_nettype; 8988e038feSJordan K. Hubbard int ether_outputdebug = 0; 9088e038feSJordan K. Hubbard int ether_inputdebug = 0; 91df8bae1dSRodney W. Grimes #endif 92df8bae1dSRodney W. Grimes 93655929bfSJulian Elischer #ifdef NETATALK 94655929bfSJulian Elischer #include <netatalk/at.h> 95655929bfSJulian Elischer #include <netatalk/at_var.h> 96655929bfSJulian Elischer #include <netatalk/at_extern.h> 97655929bfSJulian Elischer 98655929bfSJulian Elischer #define llc_snap_org_code llc_un.type_snap.org_code 99655929bfSJulian Elischer #define llc_snap_ether_type llc_un.type_snap.ether_type 100655929bfSJulian Elischer 101655929bfSJulian Elischer extern u_char at_org_code[3]; 102655929bfSJulian Elischer extern u_char aarp_org_code[3]; 1032cc2df49SGarrett Wollman #endif /* NETATALK */ 1042cc2df49SGarrett Wollman 105e1e1452dSArchie Cobbs /* netgraph node hooks for ng_ether(4) */ 106e1e1452dSArchie Cobbs void (*ng_ether_input_p)(struct ifnet *ifp, 107e1e1452dSArchie Cobbs struct mbuf **mp, struct ether_header *eh); 108e1e1452dSArchie Cobbs void (*ng_ether_input_orphan_p)(struct ifnet *ifp, 109e1e1452dSArchie Cobbs struct mbuf *m, struct ether_header *eh); 110e1e1452dSArchie Cobbs int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp); 111e1e1452dSArchie Cobbs void (*ng_ether_attach_p)(struct ifnet *ifp); 112e1e1452dSArchie Cobbs void (*ng_ether_detach_p)(struct ifnet *ifp); 113e1e1452dSArchie Cobbs 1149d4fe4b2SBrooks Davis int (*vlan_input_p)(struct ether_header *eh, struct mbuf *m); 1159d4fe4b2SBrooks Davis int (*vlan_input_tag_p)(struct ether_header *eh, struct mbuf *m, 1169d4fe4b2SBrooks Davis u_int16_t t); 1179d4fe4b2SBrooks Davis 118db69a05dSPaul Saab /* bridge support */ 119cad15830SLuigi Rizzo int do_bridge; 120db69a05dSPaul Saab bridge_in_t *bridge_in_ptr; 121db69a05dSPaul Saab bdg_forward_t *bdg_forward_ptr; 122db69a05dSPaul Saab bdgtakeifaces_t *bdgtakeifaces_ptr; 123cad15830SLuigi Rizzo struct bdg_softc *ifp2sc; 124db69a05dSPaul Saab 125929ddbbbSAlfred Perlstein static int ether_resolvemulti(struct ifnet *, struct sockaddr **, 126929ddbbbSAlfred Perlstein struct sockaddr *); 127df8bae1dSRodney W. Grimes u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 1284c8e8c05SJulian Elischer #define senderr(e) do { error = (e); goto bad;} while (0) 1294c8e8c05SJulian Elischer #define IFP2AC(IFP) ((struct arpcom *)IFP) 130df8bae1dSRodney W. Grimes 1314b984093SLuigi Rizzo int 1324b984093SLuigi Rizzo ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, 1334b984093SLuigi Rizzo struct ip_fw **rule, struct ether_header *eh, int shared); 1344b984093SLuigi Rizzo static int ether_ipfw; 1354b984093SLuigi Rizzo 136df8bae1dSRodney W. Grimes /* 137df8bae1dSRodney W. Grimes * Ethernet output routine. 138df8bae1dSRodney W. Grimes * Encapsulate a packet of type family for the local net. 139df8bae1dSRodney W. Grimes * Use trailer local net encapsulation if enough data in first 140df8bae1dSRodney W. Grimes * packet leaves a multiple of 512 bytes of data in remainder. 141df8bae1dSRodney W. Grimes * Assumes that ifp is actually pointer to arpcom structure. 142df8bae1dSRodney W. Grimes */ 143df8bae1dSRodney W. Grimes int 144d25f3712SBrian Feldman ether_output(ifp, m, dst, rt0) 145df8bae1dSRodney W. Grimes register struct ifnet *ifp; 146d25f3712SBrian Feldman struct mbuf *m; 147df8bae1dSRodney W. Grimes struct sockaddr *dst; 148df8bae1dSRodney W. Grimes struct rtentry *rt0; 149df8bae1dSRodney W. Grimes { 150df8bae1dSRodney W. Grimes short type; 151e1e1452dSArchie Cobbs int error = 0, hdrcmplt = 0; 152114ae644SMike Smith u_char esrc[6], edst[6]; 153df8bae1dSRodney W. Grimes register struct rtentry *rt; 154df8bae1dSRodney W. Grimes register struct ether_header *eh; 1559961e27dSLuigi Rizzo int loop_copy = 0; 15684dd0fd0SJulian Elischer int hlen; /* link layer header lenght */ 1574c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 158df8bae1dSRodney W. Grimes 15943b29369SRobert Watson #ifdef MAC 16043b29369SRobert Watson error = mac_check_ifnet_transmit(ifp, m); 16143b29369SRobert Watson if (error) 16243b29369SRobert Watson senderr(error); 16343b29369SRobert Watson #endif 16443b29369SRobert Watson 165afbe3a0fSPoul-Henning Kamp if (ifp->if_flags & IFF_MONITOR) 166afbe3a0fSPoul-Henning Kamp senderr(ENETDOWN); 167df8bae1dSRodney W. Grimes if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 168df8bae1dSRodney W. Grimes senderr(ENETDOWN); 1693bda9f9bSPoul-Henning Kamp rt = rt0; 1703bda9f9bSPoul-Henning Kamp if (rt) { 171df8bae1dSRodney W. Grimes if ((rt->rt_flags & RTF_UP) == 0) { 1723bda9f9bSPoul-Henning Kamp rt0 = rt = rtalloc1(dst, 1, 0UL); 1733bda9f9bSPoul-Henning Kamp if (rt0) 174df8bae1dSRodney W. Grimes rt->rt_refcnt--; 175df8bae1dSRodney W. Grimes else 176df8bae1dSRodney W. Grimes senderr(EHOSTUNREACH); 177df8bae1dSRodney W. Grimes } 178df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) { 179df8bae1dSRodney W. Grimes if (rt->rt_gwroute == 0) 180df8bae1dSRodney W. Grimes goto lookup; 181df8bae1dSRodney W. Grimes if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 182df8bae1dSRodney W. Grimes rtfree(rt); rt = rt0; 183995add1aSGarrett Wollman lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 184995add1aSGarrett Wollman 0UL); 185df8bae1dSRodney W. Grimes if ((rt = rt->rt_gwroute) == 0) 186df8bae1dSRodney W. Grimes senderr(EHOSTUNREACH); 187df8bae1dSRodney W. Grimes } 188df8bae1dSRodney W. Grimes } 189df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_REJECT) 190df8bae1dSRodney W. Grimes if (rt->rt_rmx.rmx_expire == 0 || 191227ee8a1SPoul-Henning Kamp time_second < rt->rt_rmx.rmx_expire) 192df8bae1dSRodney W. Grimes senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 193df8bae1dSRodney W. Grimes } 19484dd0fd0SJulian Elischer hlen = ETHER_HDR_LEN; 195df8bae1dSRodney W. Grimes switch (dst->sa_family) { 196df8bae1dSRodney W. Grimes #ifdef INET 197df8bae1dSRodney W. Grimes case AF_INET: 198322dcb8dSMax Khon if (!arpresolve(ifp, rt, m, dst, edst, rt0)) 199df8bae1dSRodney W. Grimes return (0); /* if not yet resolved */ 20034bed8b0SDavid Greenman type = htons(ETHERTYPE_IP); 201df8bae1dSRodney W. Grimes break; 202df8bae1dSRodney W. Grimes #endif 20382cd038dSYoshinobu Inoue #ifdef INET6 20482cd038dSYoshinobu Inoue case AF_INET6: 20582cd038dSYoshinobu Inoue if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { 206fef5fd23SBosko Milekic /* Something bad happened */ 20782cd038dSYoshinobu Inoue return(0); 20882cd038dSYoshinobu Inoue } 20982cd038dSYoshinobu Inoue type = htons(ETHERTYPE_IPV6); 21082cd038dSYoshinobu Inoue break; 21182cd038dSYoshinobu Inoue #endif 212cc6a66f2SJulian Elischer #ifdef IPX 213cc6a66f2SJulian Elischer case AF_IPX: 2144f93599fSBoris Popov if (ef_outputp) { 2152a7e8eceSBoris Popov error = ef_outputp(ifp, &m, dst, &type, &hlen); 2165accfb8cSBoris Popov if (error) 2175accfb8cSBoris Popov goto bad; 2184f93599fSBoris Popov } else 21934bed8b0SDavid Greenman type = htons(ETHERTYPE_IPX); 220cc6a66f2SJulian Elischer bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 221cc6a66f2SJulian Elischer (caddr_t)edst, sizeof (edst)); 222cc6a66f2SJulian Elischer break; 223cc6a66f2SJulian Elischer #endif 224655929bfSJulian Elischer #ifdef NETATALK 225655929bfSJulian Elischer case AF_APPLETALK: 2261d0eab59SJulian Elischer { 227ed7509acSJulian Elischer struct at_ifaddr *aa; 2281d0eab59SJulian Elischer 229ed7509acSJulian Elischer if ((aa = at_ifawithnet((struct sockaddr_at *)dst)) == NULL) { 2301d0eab59SJulian Elischer goto bad; 2311d0eab59SJulian Elischer } 232ed7509acSJulian Elischer if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) 2331d0eab59SJulian Elischer return (0); 234655929bfSJulian Elischer /* 235ed7509acSJulian Elischer * In the phase 2 case, need to prepend an mbuf for the llc header. 236655929bfSJulian Elischer * Since we must preserve the value of m, which is passed to us by 237655929bfSJulian Elischer * value, we m_copy() the first mbuf, and use it for our llc header. 238655929bfSJulian Elischer */ 239655929bfSJulian Elischer if ( aa->aa_flags & AFA_PHASE2 ) { 240655929bfSJulian Elischer struct llc llc; 241655929bfSJulian Elischer 2422a0c503eSBosko Milekic M_PREPEND(m, sizeof(struct llc), M_TRYWAIT); 243655929bfSJulian Elischer llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 244655929bfSJulian Elischer llc.llc_control = LLC_UI; 245655929bfSJulian Elischer bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); 246655929bfSJulian Elischer llc.llc_snap_ether_type = htons( ETHERTYPE_AT ); 247655929bfSJulian Elischer bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); 24834bed8b0SDavid Greenman type = htons(m->m_pkthdr.len); 24984dd0fd0SJulian Elischer hlen = sizeof(struct llc) + ETHER_HDR_LEN; 250655929bfSJulian Elischer } else { 25134bed8b0SDavid Greenman type = htons(ETHERTYPE_AT); 252655929bfSJulian Elischer } 253655929bfSJulian Elischer break; 254ed7509acSJulian Elischer } 2558cdfefbdSPeter Wemm #endif /* NETATALK */ 256df8bae1dSRodney W. Grimes #ifdef NS 257df8bae1dSRodney W. Grimes case AF_NS: 25888e038feSJordan K. Hubbard switch(ns_nettype){ 25988e038feSJordan K. Hubbard default: 26088e038feSJordan K. Hubbard case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ 26188e038feSJordan K. Hubbard type = 0x8137; 26288e038feSJordan K. Hubbard break; 26388e038feSJordan K. Hubbard case 0x0: /* Novell 802.3 */ 26488e038feSJordan K. Hubbard type = htons( m->m_pkthdr.len); 26588e038feSJordan K. Hubbard break; 26688e038feSJordan K. Hubbard case 0xe0e0: /* Novell 802.2 and Token-Ring */ 2672a0c503eSBosko Milekic M_PREPEND(m, 3, M_TRYWAIT); 26888e038feSJordan K. Hubbard type = htons( m->m_pkthdr.len); 26988e038feSJordan K. Hubbard cp = mtod(m, u_char *); 27088e038feSJordan K. Hubbard *cp++ = 0xE0; 27188e038feSJordan K. Hubbard *cp++ = 0xE0; 27288e038feSJordan K. Hubbard *cp++ = 0x03; 27388e038feSJordan K. Hubbard break; 27488e038feSJordan K. Hubbard } 275df8bae1dSRodney W. Grimes bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 276df8bae1dSRodney W. Grimes (caddr_t)edst, sizeof (edst)); 2774c8e8c05SJulian Elischer /* 2784c8e8c05SJulian Elischer * XXX if ns_thishost is the same as the node's ethernet 2794c8e8c05SJulian Elischer * address then just the default code will catch this anyhow. 2804c8e8c05SJulian Elischer * So I'm not sure if this next clause should be here at all? 2814c8e8c05SJulian Elischer * [JRE] 2824c8e8c05SJulian Elischer */ 28388e038feSJordan K. Hubbard if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))){ 28488e038feSJordan K. Hubbard m->m_pkthdr.rcvif = ifp; 28588e038feSJordan K. Hubbard inq = &nsintrq; 286df5e1987SJonathan Lemon if (IF_HANDOFF(inq, m, NULL)) 287df5e1987SJonathan Lemon schednetisr(NETISR_NS); 28888e038feSJordan K. Hubbard return (error); 28988e038feSJordan K. Hubbard } 29088e038feSJordan K. Hubbard if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof(edst))){ 2914c8e8c05SJulian Elischer m->m_flags |= M_BCAST; 29288e038feSJordan K. Hubbard } 293df8bae1dSRodney W. Grimes break; 29488e038feSJordan K. Hubbard #endif /* NS */ 295df8bae1dSRodney W. Grimes 296114ae644SMike Smith case pseudo_AF_HDRCMPLT: 297114ae644SMike Smith hdrcmplt = 1; 298114ae644SMike Smith eh = (struct ether_header *)dst->sa_data; 299114ae644SMike Smith (void)memcpy(esrc, eh->ether_shost, sizeof (esrc)); 300114ae644SMike Smith /* FALLTHROUGH */ 301114ae644SMike Smith 302df8bae1dSRodney W. Grimes case AF_UNSPEC: 3039d3f194dSJulian Elischer loop_copy = -1; /* if this is for us, don't do it */ 304df8bae1dSRodney W. Grimes eh = (struct ether_header *)dst->sa_data; 30594a5d9b6SDavid Greenman (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); 306df8bae1dSRodney W. Grimes type = eh->ether_type; 307df8bae1dSRodney W. Grimes break; 308df8bae1dSRodney W. Grimes 309df8bae1dSRodney W. Grimes default: 310df8bae1dSRodney W. Grimes printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 311df8bae1dSRodney W. Grimes dst->sa_family); 312df8bae1dSRodney W. Grimes senderr(EAFNOSUPPORT); 313df8bae1dSRodney W. Grimes } 314df8bae1dSRodney W. Grimes 315df8bae1dSRodney W. Grimes /* 316df8bae1dSRodney W. Grimes * Add local net header. If no space in first mbuf, 317df8bae1dSRodney W. Grimes * allocate another. 318df8bae1dSRodney W. Grimes */ 319df8bae1dSRodney W. Grimes M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); 320df8bae1dSRodney W. Grimes if (m == 0) 321df8bae1dSRodney W. Grimes senderr(ENOBUFS); 322df8bae1dSRodney W. Grimes eh = mtod(m, struct ether_header *); 32394a5d9b6SDavid Greenman (void)memcpy(&eh->ether_type, &type, 324df8bae1dSRodney W. Grimes sizeof(eh->ether_type)); 32594a5d9b6SDavid Greenman (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); 326114ae644SMike Smith if (hdrcmplt) 327114ae644SMike Smith (void)memcpy(eh->ether_shost, esrc, 328114ae644SMike Smith sizeof(eh->ether_shost)); 329114ae644SMike Smith else 33094a5d9b6SDavid Greenman (void)memcpy(eh->ether_shost, ac->ac_enaddr, 331df8bae1dSRodney W. Grimes sizeof(eh->ether_shost)); 332ed7509acSJulian Elischer 333ed7509acSJulian Elischer /* 334ed7509acSJulian Elischer * If a simplex interface, and the packet is being sent to our 335ed7509acSJulian Elischer * Ethernet address or a broadcast address, loopback a copy. 336ed7509acSJulian Elischer * XXX To make a simplex device behave exactly like a duplex 337ed7509acSJulian Elischer * device, we should copy in the case of sending to our own 338ed7509acSJulian Elischer * ethernet address (thus letting the original actually appear 339ed7509acSJulian Elischer * on the wire). However, we don't do that here for security 340ed7509acSJulian Elischer * reasons and compatibility with the original behavior. 341ed7509acSJulian Elischer */ 3424c8e8c05SJulian Elischer if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 3433cd67511SJesper Skriver int csum_flags = 0; 3443cd67511SJesper Skriver 3453cd67511SJesper Skriver if (m->m_pkthdr.csum_flags & CSUM_IP) 3463cd67511SJesper Skriver csum_flags |= (CSUM_IP_CHECKED|CSUM_IP_VALID); 3473cd67511SJesper Skriver if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) 3483cd67511SJesper Skriver csum_flags |= (CSUM_DATA_VALID|CSUM_PSEUDO_HDR); 3499d3f194dSJulian Elischer if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 350ed7509acSJulian Elischer struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 351ed7509acSJulian Elischer 3523cd67511SJesper Skriver n->m_pkthdr.csum_flags |= csum_flags; 3533cd67511SJesper Skriver if (csum_flags & CSUM_DATA_VALID) 3543cd67511SJesper Skriver n->m_pkthdr.csum_data = 0xffff; 3553cd67511SJesper Skriver 35606a429a3SArchie Cobbs (void) if_simloop(ifp, n, dst->sa_family, hlen); 357ed7509acSJulian Elischer } else if (bcmp(eh->ether_dhost, 358ed7509acSJulian Elischer eh->ether_shost, ETHER_ADDR_LEN) == 0) { 3593cd67511SJesper Skriver m->m_pkthdr.csum_flags |= csum_flags; 3603cd67511SJesper Skriver if (csum_flags & CSUM_DATA_VALID) 3613cd67511SJesper Skriver m->m_pkthdr.csum_data = 0xffff; 36206a429a3SArchie Cobbs (void) if_simloop(ifp, m, dst->sa_family, hlen); 363ed7509acSJulian Elischer return (0); /* XXX */ 364ed7509acSJulian Elischer } 365ed7509acSJulian Elischer } 3662e2de7f2SArchie Cobbs 367e1e1452dSArchie Cobbs /* Handle ng_ether(4) processing, if any */ 368e1e1452dSArchie Cobbs if (ng_ether_output_p != NULL) { 369e1e1452dSArchie Cobbs if ((error = (*ng_ether_output_p)(ifp, &m)) != 0) { 370e1e1452dSArchie Cobbs bad: if (m != NULL) 371e1e1452dSArchie Cobbs m_freem(m); 372e1e1452dSArchie Cobbs return (error); 373e1e1452dSArchie Cobbs } 374e1e1452dSArchie Cobbs if (m == NULL) 375e1e1452dSArchie Cobbs return (0); 376e1e1452dSArchie Cobbs } 377e1e1452dSArchie Cobbs 378e1e1452dSArchie Cobbs /* Continue with link-layer output */ 379e1e1452dSArchie Cobbs return ether_output_frame(ifp, m); 380e1e1452dSArchie Cobbs } 381e1e1452dSArchie Cobbs 382e1e1452dSArchie Cobbs /* 383e1e1452dSArchie Cobbs * Ethernet link layer output routine to send a raw frame to the device. 384e1e1452dSArchie Cobbs * 385e1e1452dSArchie Cobbs * This assumes that the 14 byte Ethernet header is present and contiguous 386e1e1452dSArchie Cobbs * in the first mbuf (if BRIDGE'ing). 387e1e1452dSArchie Cobbs */ 388e1e1452dSArchie Cobbs int 389e1e1452dSArchie Cobbs ether_output_frame(ifp, m) 390e1e1452dSArchie Cobbs struct ifnet *ifp; 391e1e1452dSArchie Cobbs struct mbuf *m; 392e1e1452dSArchie Cobbs { 393df5e1987SJonathan Lemon int error = 0; 3944b984093SLuigi Rizzo struct ip_fw *rule = NULL; 3952b25acc1SLuigi Rizzo 3962b25acc1SLuigi Rizzo /* Extract info from dummynet tag, ignore others */ 3972b25acc1SLuigi Rizzo for (; m->m_type == MT_TAG; m = m->m_next) 3982b25acc1SLuigi Rizzo if (m->m_flags == PACKET_TAG_DUMMYNET) 3992b25acc1SLuigi Rizzo rule = ((struct dn_pkt *)m)->rule; 4002b25acc1SLuigi Rizzo 4012b25acc1SLuigi Rizzo if (rule) /* packet was already bridged */ 4024b984093SLuigi Rizzo goto no_bridge; 4032b25acc1SLuigi Rizzo 4047b109fa4SLuigi Rizzo if (BDG_ACTIVE(ifp) ) { 405507b4b54SLuigi Rizzo struct ether_header *eh; /* a ptr suffices */ 4061db59ce6SEivind Eklund 407fb5fbe46SLuigi Rizzo m->m_pkthdr.rcvif = NULL; 408507b4b54SLuigi Rizzo eh = mtod(m, struct ether_header *); 4092e2de7f2SArchie Cobbs m_adj(m, ETHER_HDR_LEN); 410db69a05dSPaul Saab m = bdg_forward_ptr(m, eh, ifp); 4112e2de7f2SArchie Cobbs if (m != NULL) 4122e2de7f2SArchie Cobbs m_freem(m); 4131db59ce6SEivind Eklund return (0); 414fb5fbe46SLuigi Rizzo } 4152e2de7f2SArchie Cobbs 4164b984093SLuigi Rizzo no_bridge: 4174b984093SLuigi Rizzo if (IPFW_LOADED && ether_ipfw != 0) { 4184b984093SLuigi Rizzo struct ether_header save_eh, *eh; 4194b984093SLuigi Rizzo 4204b984093SLuigi Rizzo eh = mtod(m, struct ether_header *); 4214b984093SLuigi Rizzo save_eh = *eh; 4224b984093SLuigi Rizzo m_adj(m, ETHER_HDR_LEN); 4234b984093SLuigi Rizzo if (ether_ipfw_chk(&m, ifp, &rule, eh, 0) == 0) { 4244b984093SLuigi Rizzo if (m) { 4254b984093SLuigi Rizzo m_freem(m); 4264b984093SLuigi Rizzo return ENOBUFS; /* pkt dropped */ 4274b984093SLuigi Rizzo } else 4284b984093SLuigi Rizzo return 0; /* consumed e.g. in a pipe */ 4294b984093SLuigi Rizzo } 4304b984093SLuigi Rizzo /* packet was ok, restore the ethernet header */ 4314b984093SLuigi Rizzo if ( (void *)(eh + 1) == (void *)m->m_data) { 4324b984093SLuigi Rizzo m->m_data -= ETHER_HDR_LEN ; 4334b984093SLuigi Rizzo m->m_len += ETHER_HDR_LEN ; 4344b984093SLuigi Rizzo m->m_pkthdr.len += ETHER_HDR_LEN ; 4354b984093SLuigi Rizzo } else { 4364b984093SLuigi Rizzo M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT); 4374b984093SLuigi Rizzo if (m == NULL) /* nope... */ 4384b984093SLuigi Rizzo return ENOBUFS; 4394b984093SLuigi Rizzo bcopy(&save_eh, mtod(m, struct ether_header *), 4404b984093SLuigi Rizzo ETHER_HDR_LEN); 4414b984093SLuigi Rizzo } 4424b984093SLuigi Rizzo } 4432b25acc1SLuigi Rizzo 444df8bae1dSRodney W. Grimes /* 445df5e1987SJonathan Lemon * Queue message on interface, update output statistics if 446df5e1987SJonathan Lemon * successful, and start output if interface not yet active. 447df8bae1dSRodney W. Grimes */ 448df5e1987SJonathan Lemon if (! IF_HANDOFF(&ifp->if_snd, m, ifp)) 449e1e1452dSArchie Cobbs return (ENOBUFS); 450df8bae1dSRodney W. Grimes return (error); 451df8bae1dSRodney W. Grimes } 452df8bae1dSRodney W. Grimes 453df8bae1dSRodney W. Grimes /* 4544b984093SLuigi Rizzo * ipfw processing for ethernet packets (in and out). 4554b984093SLuigi Rizzo * The second parameter is NULL from ether_demux, and ifp from 4564b984093SLuigi Rizzo * ether_output_frame. This section of code could be used from 4572f8ebbf4SLuigi Rizzo * bridge.c as well as long as we use some extra info 4584b984093SLuigi Rizzo * to distinguish that case from ether_output_frame(); 4594b984093SLuigi Rizzo */ 4604b984093SLuigi Rizzo int 4614b984093SLuigi Rizzo ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, 4624b984093SLuigi Rizzo struct ip_fw **rule, struct ether_header *eh, int shared) 4634b984093SLuigi Rizzo { 4642f8ebbf4SLuigi Rizzo struct ether_header save_eh = *eh; /* might be a ptr in m */ 4654b984093SLuigi Rizzo int i; 4662b25acc1SLuigi Rizzo struct ip_fw_args args; 4674b984093SLuigi Rizzo 46859083544SDavid E. O'Brien if (*rule != NULL /*&& fw_one_pass*/) /* HACK! need to obey fw_one_pass */ 469015d72e0SLuigi Rizzo return 1; /* dummynet packet, already partially processed */ 4702f8ebbf4SLuigi Rizzo 4714b984093SLuigi Rizzo /* 4722f8ebbf4SLuigi Rizzo * I need some amt of data to be contiguous, and in case others need 4734b984093SLuigi Rizzo * the packet (shared==1) also better be in the first mbuf. 4744b984093SLuigi Rizzo */ 4754b984093SLuigi Rizzo i = min( (*m0)->m_pkthdr.len, max_protohdr); 4764b984093SLuigi Rizzo if ( shared || (*m0)->m_len < i) { 4774b984093SLuigi Rizzo *m0 = m_pullup(*m0, i); 4782b25acc1SLuigi Rizzo if (*m0 == NULL) 4794b984093SLuigi Rizzo return 0; 4804b984093SLuigi Rizzo } 4814b984093SLuigi Rizzo 4822b25acc1SLuigi Rizzo args.m = *m0; /* the packet we are looking at */ 4832b25acc1SLuigi Rizzo args.oif = dst; /* destination, if any */ 4842b25acc1SLuigi Rizzo args.divert_rule = 0; /* we do not support divert yet */ 4852b25acc1SLuigi Rizzo args.rule = *rule; /* matching rule to restart */ 4862b25acc1SLuigi Rizzo args.next_hop = NULL; /* we do not support forward yet */ 4872b25acc1SLuigi Rizzo args.eh = &save_eh; /* MAC header for bridged/MAC packets */ 4882b25acc1SLuigi Rizzo i = ip_fw_chk_ptr(&args); 4892b25acc1SLuigi Rizzo *m0 = args.m; 4902b25acc1SLuigi Rizzo *rule = args.rule; 4912b25acc1SLuigi Rizzo 4924b984093SLuigi Rizzo if ( (i & IP_FW_PORT_DENY_FLAG) || *m0 == NULL) /* drop */ 4934b984093SLuigi Rizzo return 0; 4944b984093SLuigi Rizzo 4954b984093SLuigi Rizzo if (i == 0) /* a PASS rule. */ 4964b984093SLuigi Rizzo return 1; 4974b984093SLuigi Rizzo 4984b984093SLuigi Rizzo if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG)) { 4994b984093SLuigi Rizzo /* 5004b984093SLuigi Rizzo * Pass the pkt to dummynet, which consumes it. 5014b984093SLuigi Rizzo * If shared, make a copy and keep the original. 5024b984093SLuigi Rizzo */ 5034b984093SLuigi Rizzo struct mbuf *m ; 5044b984093SLuigi Rizzo 5054b984093SLuigi Rizzo if (shared) { 5064b984093SLuigi Rizzo m = m_copypacket(*m0, M_DONTWAIT); 5072b25acc1SLuigi Rizzo if (m == NULL) 5084b984093SLuigi Rizzo return 0; 5094b984093SLuigi Rizzo } else { 5104b984093SLuigi Rizzo m = *m0 ; /* pass the original to dummynet */ 5114b984093SLuigi Rizzo *m0 = NULL ; /* and nothing back to the caller */ 5124b984093SLuigi Rizzo } 5132b25acc1SLuigi Rizzo /* 5142b25acc1SLuigi Rizzo * Prepend the header, optimize for the common case of 5152b25acc1SLuigi Rizzo * eh pointing into the mbuf. 5162b25acc1SLuigi Rizzo */ 5174b984093SLuigi Rizzo if ( (void *)(eh + 1) == (void *)m->m_data) { 5184b984093SLuigi Rizzo m->m_data -= ETHER_HDR_LEN ; 5194b984093SLuigi Rizzo m->m_len += ETHER_HDR_LEN ; 5204b984093SLuigi Rizzo m->m_pkthdr.len += ETHER_HDR_LEN ; 5214b984093SLuigi Rizzo } else { 5224b984093SLuigi Rizzo M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT); 5234b984093SLuigi Rizzo if (m == NULL) /* nope... */ 5244b984093SLuigi Rizzo return 0; 5254b984093SLuigi Rizzo bcopy(&save_eh, mtod(m, struct ether_header *), 5264b984093SLuigi Rizzo ETHER_HDR_LEN); 5274b984093SLuigi Rizzo } 5282b25acc1SLuigi Rizzo ip_dn_io_ptr(m, (i & 0xffff), 5292b25acc1SLuigi Rizzo dst ? DN_TO_ETH_OUT: DN_TO_ETH_DEMUX, &args); 5304b984093SLuigi Rizzo return 0; 5314b984093SLuigi Rizzo } 5324b984093SLuigi Rizzo /* 5332f8ebbf4SLuigi Rizzo * XXX at some point add support for divert/forward actions. 5342f8ebbf4SLuigi Rizzo * If none of the above matches, we have to drop the pkt. 5354b984093SLuigi Rizzo */ 5364b984093SLuigi Rizzo return 0; 5374b984093SLuigi Rizzo } 5384b984093SLuigi Rizzo 5394b984093SLuigi Rizzo /* 540c939f1aeSLuigi Rizzo * Process a received Ethernet packet. We have two different interfaces: 541c939f1aeSLuigi Rizzo * one (conventional) assumes the packet in the mbuf, with the ethernet 542c939f1aeSLuigi Rizzo * header provided separately in *eh. The second one (new) has everything 543c939f1aeSLuigi Rizzo * in the mbuf, and we can tell it because eh == NULL. 544c939f1aeSLuigi Rizzo * The caller MUST MAKE SURE that there are at least 545c939f1aeSLuigi Rizzo * sizeof(struct ether_header) bytes in the first mbuf. 546c939f1aeSLuigi Rizzo * 547c939f1aeSLuigi Rizzo * This allows us to concentrate in one place a bunch of code which 548c939f1aeSLuigi Rizzo * is replicated in all device drivers. Also, many functions called 549c939f1aeSLuigi Rizzo * from ether_input() try to put the eh back into the mbuf, so we 550c939f1aeSLuigi Rizzo * can later propagate the 'contiguous packet' interface to them, 551c939f1aeSLuigi Rizzo * and handle the old interface just here. 552e1e1452dSArchie Cobbs * 55302a282acSLuigi Rizzo * NOTA BENE: for many drivers "eh" is a pointer into the first mbuf or 55402a282acSLuigi Rizzo * cluster, right before m_data. So be very careful when working on m, 55502a282acSLuigi Rizzo * as you could destroy *eh !! 55602a282acSLuigi Rizzo * 557e1e1452dSArchie Cobbs * First we perform any link layer operations, then continue 558e1e1452dSArchie Cobbs * to the upper layers with ether_demux(). 559df8bae1dSRodney W. Grimes */ 560df8bae1dSRodney W. Grimes void 561c939f1aeSLuigi Rizzo ether_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m) 562df8bae1dSRodney W. Grimes { 563507b4b54SLuigi Rizzo struct ether_header save_eh; 564df8bae1dSRodney W. Grimes 565c939f1aeSLuigi Rizzo if (eh == NULL) { 566c939f1aeSLuigi Rizzo if (m->m_len < sizeof(struct ether_header)) { 567c939f1aeSLuigi Rizzo /* XXX error in the caller. */ 568c939f1aeSLuigi Rizzo m_freem(m); 569c939f1aeSLuigi Rizzo return; 570c939f1aeSLuigi Rizzo } 5712201e1b0SPoul-Henning Kamp if (ifp->if_bpf != NULL) 5722201e1b0SPoul-Henning Kamp bpf_mtap(ifp, m); 573c939f1aeSLuigi Rizzo m->m_pkthdr.rcvif = ifp; 574c939f1aeSLuigi Rizzo eh = mtod(m, struct ether_header *); 575c939f1aeSLuigi Rizzo m->m_data += sizeof(struct ether_header); 576c939f1aeSLuigi Rizzo m->m_len -= sizeof(struct ether_header); 577c939f1aeSLuigi Rizzo m->m_pkthdr.len = m->m_len; 5782201e1b0SPoul-Henning Kamp } else if (ifp->if_bpf != NULL) { 5792e2de7f2SArchie Cobbs struct m_hdr mh; 5802e2de7f2SArchie Cobbs 5812e2de7f2SArchie Cobbs /* This kludge is OK; BPF treats the "mbuf" as read-only */ 5822e2de7f2SArchie Cobbs mh.mh_next = m; 5832e2de7f2SArchie Cobbs mh.mh_data = (char *)eh; 5842e2de7f2SArchie Cobbs mh.mh_len = ETHER_HDR_LEN; 5852e2de7f2SArchie Cobbs bpf_mtap(ifp, (struct mbuf *)&mh); 5862e2de7f2SArchie Cobbs } 5872e2de7f2SArchie Cobbs 588afbe3a0fSPoul-Henning Kamp if (ifp->if_flags & IFF_MONITOR) { 589afbe3a0fSPoul-Henning Kamp m_freem(m); 590afbe3a0fSPoul-Henning Kamp return; 591afbe3a0fSPoul-Henning Kamp } 592afbe3a0fSPoul-Henning Kamp 5932201e1b0SPoul-Henning Kamp #ifdef MAC 5942201e1b0SPoul-Henning Kamp mac_create_mbuf_from_ifnet(ifp, m); 5952201e1b0SPoul-Henning Kamp #endif 5962201e1b0SPoul-Henning Kamp 59705463bb5SDavid Greenman ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); 59805463bb5SDavid Greenman 599e1e1452dSArchie Cobbs /* Handle ng_ether(4) processing, if any */ 600e1e1452dSArchie Cobbs if (ng_ether_input_p != NULL) { 601e1e1452dSArchie Cobbs (*ng_ether_input_p)(ifp, &m, eh); 602e1e1452dSArchie Cobbs if (m == NULL) 603e1e1452dSArchie Cobbs return; 604e1e1452dSArchie Cobbs } 605e1e1452dSArchie Cobbs 6062e2de7f2SArchie Cobbs /* Check for bridging mode */ 6077b109fa4SLuigi Rizzo if (BDG_ACTIVE(ifp) ) { 6082e2de7f2SArchie Cobbs struct ifnet *bif; 6092e2de7f2SArchie Cobbs 6102e2de7f2SArchie Cobbs /* Check with bridging code */ 611db69a05dSPaul Saab if ((bif = bridge_in_ptr(ifp, eh)) == BDG_DROP) { 6122e2de7f2SArchie Cobbs m_freem(m); 6132e2de7f2SArchie Cobbs return; 6142e2de7f2SArchie Cobbs } 615ddacb30fSBosko Milekic if (bif != BDG_LOCAL) { 616507b4b54SLuigi Rizzo struct mbuf *oldm = m ; 617507b4b54SLuigi Rizzo 618507b4b54SLuigi Rizzo save_eh = *eh ; /* because it might change */ 619db69a05dSPaul Saab m = bdg_forward_ptr(m, eh, bif); /* needs forwarding */ 620ddacb30fSBosko Milekic /* 621db69a05dSPaul Saab * Do not continue if bdg_forward_ptr() processed our 622ddacb30fSBosko Milekic * packet (and cleared the mbuf pointer m) or if 623ddacb30fSBosko Milekic * it dropped (m_free'd) the packet itself. 624ddacb30fSBosko Milekic */ 625507b4b54SLuigi Rizzo if (m == NULL) { 626507b4b54SLuigi Rizzo if (bif == BDG_BCAST || bif == BDG_MCAST) 627507b4b54SLuigi Rizzo printf("bdg_forward drop MULTICAST PKT\n"); 628ddacb30fSBosko Milekic return; 629ddacb30fSBosko Milekic } 630507b4b54SLuigi Rizzo if (m != oldm) /* m changed! */ 631507b4b54SLuigi Rizzo eh = &save_eh ; 632507b4b54SLuigi Rizzo } 6332e2de7f2SArchie Cobbs if (bif == BDG_LOCAL 6342e2de7f2SArchie Cobbs || bif == BDG_BCAST 6352e2de7f2SArchie Cobbs || bif == BDG_MCAST) 6362e2de7f2SArchie Cobbs goto recvLocal; /* receive locally */ 6372e2de7f2SArchie Cobbs 6382e2de7f2SArchie Cobbs /* If not local and not multicast, just drop it */ 6392e2de7f2SArchie Cobbs if (m != NULL) 6402e2de7f2SArchie Cobbs m_freem(m); 6412e2de7f2SArchie Cobbs return; 6422e2de7f2SArchie Cobbs } 6432e2de7f2SArchie Cobbs 6442e2de7f2SArchie Cobbs recvLocal: 645e1e1452dSArchie Cobbs /* Continue with upper layer processing */ 646e1e1452dSArchie Cobbs ether_demux(ifp, eh, m); 647a6ddbff0SPoul-Henning Kamp /* First chunk of an mbuf contains good entropy */ 64810b1fde0SMark Murray if (harvest.ethernet) 64910b1fde0SMark Murray random_harvest(m, 16, 3, 0, RANDOM_NET); 650e1e1452dSArchie Cobbs } 651e1e1452dSArchie Cobbs 652e1e1452dSArchie Cobbs /* 653e1e1452dSArchie Cobbs * Upper layer processing for a received Ethernet packet. 654e1e1452dSArchie Cobbs */ 655e1e1452dSArchie Cobbs void 656e1e1452dSArchie Cobbs ether_demux(ifp, eh, m) 657e1e1452dSArchie Cobbs struct ifnet *ifp; 658e1e1452dSArchie Cobbs struct ether_header *eh; 659e1e1452dSArchie Cobbs struct mbuf *m; 660e1e1452dSArchie Cobbs { 661e1e1452dSArchie Cobbs struct ifqueue *inq; 662e1e1452dSArchie Cobbs u_short ether_type; 663e1e1452dSArchie Cobbs #if defined(NETATALK) 664e1e1452dSArchie Cobbs register struct llc *l; 665e1e1452dSArchie Cobbs #endif 6664b984093SLuigi Rizzo struct ip_fw *rule = NULL; 6672b25acc1SLuigi Rizzo 6682b25acc1SLuigi Rizzo /* Extract info from dummynet tag, ignore others */ 6692b25acc1SLuigi Rizzo for (;m->m_type == MT_TAG; m = m->m_next) 6702b25acc1SLuigi Rizzo if (m->m_flags == PACKET_TAG_DUMMYNET) { 6712b25acc1SLuigi Rizzo rule = ((struct dn_pkt *)m)->rule; 6722b25acc1SLuigi Rizzo ifp = m->m_next->m_pkthdr.rcvif; 6734b984093SLuigi Rizzo } 6742b25acc1SLuigi Rizzo 6752b25acc1SLuigi Rizzo if (rule) /* packet was already bridged */ 6762b25acc1SLuigi Rizzo goto post_stats; 6774b984093SLuigi Rizzo 6787b109fa4SLuigi Rizzo if (! (BDG_ACTIVE(ifp) ) ) 679cb24f323SArchie Cobbs /* Discard packet if upper layers shouldn't see it because it was 680cb24f323SArchie Cobbs unicast to a different Ethernet address. If the driver is working 681cb24f323SArchie Cobbs properly, then this situation can only happen when the interface 682cb24f323SArchie Cobbs is in promiscuous mode. */ 683cb24f323SArchie Cobbs if ((ifp->if_flags & IFF_PROMISC) != 0 684cb24f323SArchie Cobbs && (eh->ether_dhost[0] & 1) == 0 685cb24f323SArchie Cobbs && bcmp(eh->ether_dhost, 686ffb079beSMaxim Sobolev IFP2AC(ifp)->ac_enaddr, ETHER_ADDR_LEN) != 0 68725faf49dSMaxim Sobolev && (ifp->if_flags & IFF_PPROMISC) == 0) { 688cb24f323SArchie Cobbs m_freem(m); 689cb24f323SArchie Cobbs return; 690cb24f323SArchie Cobbs } 691cb24f323SArchie Cobbs 6922e2de7f2SArchie Cobbs /* Discard packet if interface is not up */ 693df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) { 694df8bae1dSRodney W. Grimes m_freem(m); 695df8bae1dSRodney W. Grimes return; 696df8bae1dSRodney W. Grimes } 6972cc2df49SGarrett Wollman if (eh->ether_dhost[0] & 1) { 698df8bae1dSRodney W. Grimes if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 699df8bae1dSRodney W. Grimes sizeof(etherbroadcastaddr)) == 0) 700df8bae1dSRodney W. Grimes m->m_flags |= M_BCAST; 7012cc2df49SGarrett Wollman else 702df8bae1dSRodney W. Grimes m->m_flags |= M_MCAST; 7032cc2df49SGarrett Wollman } 704df8bae1dSRodney W. Grimes if (m->m_flags & (M_BCAST|M_MCAST)) 705df8bae1dSRodney W. Grimes ifp->if_imcasts++; 706df8bae1dSRodney W. Grimes 7074b984093SLuigi Rizzo post_stats: 7084b984093SLuigi Rizzo if (IPFW_LOADED && ether_ipfw != 0) { 7094b984093SLuigi Rizzo if (ether_ipfw_chk(&m, NULL, &rule, eh, 0 ) == 0) { 7104b984093SLuigi Rizzo if (m) 7114b984093SLuigi Rizzo m_freem(m); 7124b984093SLuigi Rizzo return; 7134b984093SLuigi Rizzo } 7144b984093SLuigi Rizzo } 7154b984093SLuigi Rizzo 716307d80beSDavid Greenman ether_type = ntohs(eh->ether_type); 717307d80beSDavid Greenman 718307d80beSDavid Greenman switch (ether_type) { 719df8bae1dSRodney W. Grimes #ifdef INET 720df8bae1dSRodney W. Grimes case ETHERTYPE_IP: 7211f91d8c5SDavid Greenman if (ipflow_fastforward(m)) 7221f91d8c5SDavid Greenman return; 723df8bae1dSRodney W. Grimes schednetisr(NETISR_IP); 724df8bae1dSRodney W. Grimes inq = &ipintrq; 725df8bae1dSRodney W. Grimes break; 726df8bae1dSRodney W. Grimes 727df8bae1dSRodney W. Grimes case ETHERTYPE_ARP: 72808aadfbbSJonathan Lemon if (ifp->if_flags & IFF_NOARP) { 72908aadfbbSJonathan Lemon /* Discard packet if ARP is disabled on interface */ 73008aadfbbSJonathan Lemon m_freem(m); 73108aadfbbSJonathan Lemon return; 73208aadfbbSJonathan Lemon } 733df8bae1dSRodney W. Grimes schednetisr(NETISR_ARP); 734df8bae1dSRodney W. Grimes inq = &arpintrq; 735df8bae1dSRodney W. Grimes break; 736df8bae1dSRodney W. Grimes #endif 737cc6a66f2SJulian Elischer #ifdef IPX 738cc6a66f2SJulian Elischer case ETHERTYPE_IPX: 7394f93599fSBoris Popov if (ef_inputp && ef_inputp(ifp, eh, m) == 0) 7404f93599fSBoris Popov return; 741cc6a66f2SJulian Elischer schednetisr(NETISR_IPX); 742cc6a66f2SJulian Elischer inq = &ipxintrq; 743cc6a66f2SJulian Elischer break; 744cc6a66f2SJulian Elischer #endif 74582cd038dSYoshinobu Inoue #ifdef INET6 74682cd038dSYoshinobu Inoue case ETHERTYPE_IPV6: 74782cd038dSYoshinobu Inoue schednetisr(NETISR_IPV6); 74882cd038dSYoshinobu Inoue inq = &ip6intrq; 74982cd038dSYoshinobu Inoue break; 75082cd038dSYoshinobu Inoue #endif 751df8bae1dSRodney W. Grimes #ifdef NS 75288e038feSJordan K. Hubbard case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ 753df8bae1dSRodney W. Grimes schednetisr(NETISR_NS); 754df8bae1dSRodney W. Grimes inq = &nsintrq; 755df8bae1dSRodney W. Grimes break; 75688e038feSJordan K. Hubbard 75788e038feSJordan K. Hubbard #endif /* NS */ 758655929bfSJulian Elischer #ifdef NETATALK 759655929bfSJulian Elischer case ETHERTYPE_AT: 760655929bfSJulian Elischer schednetisr(NETISR_ATALK); 761655929bfSJulian Elischer inq = &atintrq1; 762655929bfSJulian Elischer break; 763655929bfSJulian Elischer case ETHERTYPE_AARP: 764655929bfSJulian Elischer /* probably this should be done with a NETISR as well */ 7654c8e8c05SJulian Elischer aarpinput(IFP2AC(ifp), m); /* XXX */ 766655929bfSJulian Elischer return; 7678cdfefbdSPeter Wemm #endif /* NETATALK */ 7689d4fe4b2SBrooks Davis case ETHERTYPE_VLAN: 7697d3e4c6eSLuigi Rizzo /* XXX lock ? */ 7707d3e4c6eSLuigi Rizzo if (vlan_input_p != NULL) 7717d3e4c6eSLuigi Rizzo (*vlan_input_p)(eh, m); 7727d3e4c6eSLuigi Rizzo else { 7737d3e4c6eSLuigi Rizzo m->m_pkthdr.rcvif->if_noproto++; 7747d3e4c6eSLuigi Rizzo m_freem(m); 7757d3e4c6eSLuigi Rizzo } 7767d3e4c6eSLuigi Rizzo /* XXX unlock ? */ 7779d4fe4b2SBrooks Davis return; 778df8bae1dSRodney W. Grimes default: 7794f93599fSBoris Popov #ifdef IPX 7804f93599fSBoris Popov if (ef_inputp && ef_inputp(ifp, eh, m) == 0) 7814f93599fSBoris Popov return; 7824f93599fSBoris Popov #endif /* IPX */ 78388e038feSJordan K. Hubbard #ifdef NS 78488e038feSJordan K. Hubbard checksum = mtod(m, ushort *); 78588e038feSJordan K. Hubbard /* Novell 802.3 */ 78688e038feSJordan K. Hubbard if ((ether_type <= ETHERMTU) && 78788e038feSJordan K. Hubbard ((*checksum == 0xffff) || (*checksum == 0xE0E0))){ 78888e038feSJordan K. Hubbard if(*checksum == 0xE0E0) { 78988e038feSJordan K. Hubbard m->m_pkthdr.len -= 3; 79088e038feSJordan K. Hubbard m->m_len -= 3; 79188e038feSJordan K. Hubbard m->m_data += 3; 79288e038feSJordan K. Hubbard } 79388e038feSJordan K. Hubbard schednetisr(NETISR_NS); 79488e038feSJordan K. Hubbard inq = &nsintrq; 79588e038feSJordan K. Hubbard break; 79688e038feSJordan K. Hubbard } 79788e038feSJordan K. Hubbard #endif /* NS */ 798242c5536SPeter Wemm #if defined(NETATALK) 799307d80beSDavid Greenman if (ether_type > ETHERMTU) 800df8bae1dSRodney W. Grimes goto dropanyway; 801df8bae1dSRodney W. Grimes l = mtod(m, struct llc *); 802df8bae1dSRodney W. Grimes switch (l->llc_dsap) { 803655929bfSJulian Elischer case LLC_SNAP_LSAP: 804655929bfSJulian Elischer switch (l->llc_control) { 805655929bfSJulian Elischer case LLC_UI: 806655929bfSJulian Elischer if (l->llc_ssap != LLC_SNAP_LSAP) 807655929bfSJulian Elischer goto dropanyway; 808655929bfSJulian Elischer 809655929bfSJulian Elischer if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, 810655929bfSJulian Elischer sizeof(at_org_code)) == 0 && 811655929bfSJulian Elischer ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { 812655929bfSJulian Elischer inq = &atintrq2; 813655929bfSJulian Elischer m_adj( m, sizeof( struct llc )); 814655929bfSJulian Elischer schednetisr(NETISR_ATALK); 815655929bfSJulian Elischer break; 816655929bfSJulian Elischer } 817655929bfSJulian Elischer 818655929bfSJulian Elischer if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, 819655929bfSJulian Elischer sizeof(aarp_org_code)) == 0 && 820655929bfSJulian Elischer ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { 821655929bfSJulian Elischer m_adj( m, sizeof( struct llc )); 8224c8e8c05SJulian Elischer aarpinput(IFP2AC(ifp), m); /* XXX */ 823655929bfSJulian Elischer return; 824655929bfSJulian Elischer } 825655929bfSJulian Elischer 826655929bfSJulian Elischer default: 827655929bfSJulian Elischer goto dropanyway; 828655929bfSJulian Elischer } 829655929bfSJulian Elischer break; 830df8bae1dSRodney W. Grimes dropanyway: 831df8bae1dSRodney W. Grimes default: 832e1e1452dSArchie Cobbs if (ng_ether_input_orphan_p != NULL) 833e1e1452dSArchie Cobbs (*ng_ether_input_orphan_p)(ifp, m, eh); 834e1e1452dSArchie Cobbs else 835df8bae1dSRodney W. Grimes m_freem(m); 836df8bae1dSRodney W. Grimes return; 837df8bae1dSRodney W. Grimes } 838242c5536SPeter Wemm #else /* NETATALK */ 839e1e1452dSArchie Cobbs if (ng_ether_input_orphan_p != NULL) 840e1e1452dSArchie Cobbs (*ng_ether_input_orphan_p)(ifp, m, eh); 841e1e1452dSArchie Cobbs else 842df8bae1dSRodney W. Grimes m_freem(m); 843df8bae1dSRodney W. Grimes return; 844242c5536SPeter Wemm #endif /* NETATALK */ 845df8bae1dSRodney W. Grimes } 846df8bae1dSRodney W. Grimes 847df5e1987SJonathan Lemon (void) IF_HANDOFF(inq, m, NULL); 848df8bae1dSRodney W. Grimes } 849df8bae1dSRodney W. Grimes 850df8bae1dSRodney W. Grimes /* 851df8bae1dSRodney W. Grimes * Perform common duties while attaching to interface list 852df8bae1dSRodney W. Grimes */ 853df8bae1dSRodney W. Grimes void 85421b8ebd9SArchie Cobbs ether_ifattach(ifp, bpf) 855df8bae1dSRodney W. Grimes register struct ifnet *ifp; 85621b8ebd9SArchie Cobbs int bpf; 857df8bae1dSRodney W. Grimes { 858df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 859df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl; 860df8bae1dSRodney W. Grimes 861df8bae1dSRodney W. Grimes ifp->if_type = IFT_ETHER; 862df8bae1dSRodney W. Grimes ifp->if_addrlen = 6; 863df8bae1dSRodney W. Grimes ifp->if_hdrlen = 14; 864cfeff1b6SJonathan Lemon if_attach(ifp); 865df8bae1dSRodney W. Grimes ifp->if_mtu = ETHERMTU; 8661158dfb7SGarrett Wollman ifp->if_resolvemulti = ether_resolvemulti; 867a330e1f1SGary Palmer if (ifp->if_baudrate == 0) 868a330e1f1SGary Palmer ifp->if_baudrate = 10000000; 869322dcb8dSMax Khon ifp->if_broadcastaddr = etherbroadcastaddr; 870f9132cebSJonathan Lemon ifa = ifaddr_byindex(ifp->if_index); 8716e551fb6SDavid E. O'Brien KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 87259562606SGarrett Wollman sdl = (struct sockaddr_dl *)ifa->ifa_addr; 873df8bae1dSRodney W. Grimes sdl->sdl_type = IFT_ETHER; 874df8bae1dSRodney W. Grimes sdl->sdl_alen = ifp->if_addrlen; 8754c8e8c05SJulian Elischer bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 87621b8ebd9SArchie Cobbs if (bpf) 87721b8ebd9SArchie Cobbs bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 878e1e1452dSArchie Cobbs if (ng_ether_attach_p != NULL) 879e1e1452dSArchie Cobbs (*ng_ether_attach_p)(ifp); 8807b109fa4SLuigi Rizzo if (BDG_LOADED) 881db69a05dSPaul Saab bdgtakeifaces_ptr(); 882e1e1452dSArchie Cobbs } 883e1e1452dSArchie Cobbs 88421b8ebd9SArchie Cobbs /* 88521b8ebd9SArchie Cobbs * Perform common duties while detaching an Ethernet interface 88621b8ebd9SArchie Cobbs */ 88721b8ebd9SArchie Cobbs void 88821b8ebd9SArchie Cobbs ether_ifdetach(ifp, bpf) 88921b8ebd9SArchie Cobbs struct ifnet *ifp; 89021b8ebd9SArchie Cobbs int bpf; 89121b8ebd9SArchie Cobbs { 89221b8ebd9SArchie Cobbs if (ng_ether_detach_p != NULL) 89321b8ebd9SArchie Cobbs (*ng_ether_detach_p)(ifp); 89421b8ebd9SArchie Cobbs if (bpf) 89521b8ebd9SArchie Cobbs bpfdetach(ifp); 89621b8ebd9SArchie Cobbs if_detach(ifp); 8977b109fa4SLuigi Rizzo if (BDG_LOADED) 898db69a05dSPaul Saab bdgtakeifaces_ptr(); 89921b8ebd9SArchie Cobbs } 90021b8ebd9SArchie Cobbs 901ce02431fSDoug Rabson SYSCTL_DECL(_net_link); 902602d513cSGarrett Wollman SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); 9034b984093SLuigi Rizzo SYSCTL_INT(_net_link_ether, OID_AUTO, ipfw, CTLFLAG_RW, 9044b984093SLuigi Rizzo ðer_ipfw,0,"Pass ether pkts through firewall"); 90530106f6aSPoul-Henning Kamp 906fb583156SDavid Greenman int 907c5a1016bSBruce Evans ether_ioctl(ifp, command, data) 908c5a1016bSBruce Evans struct ifnet *ifp; 909c5a1016bSBruce Evans int command; 910c5a1016bSBruce Evans caddr_t data; 91130106f6aSPoul-Henning Kamp { 91230106f6aSPoul-Henning Kamp struct ifaddr *ifa = (struct ifaddr *) data; 91330106f6aSPoul-Henning Kamp struct ifreq *ifr = (struct ifreq *) data; 914fb583156SDavid Greenman int error = 0; 91530106f6aSPoul-Henning Kamp 91630106f6aSPoul-Henning Kamp switch (command) { 91730106f6aSPoul-Henning Kamp case SIOCSIFADDR: 91830106f6aSPoul-Henning Kamp ifp->if_flags |= IFF_UP; 91930106f6aSPoul-Henning Kamp 92030106f6aSPoul-Henning Kamp switch (ifa->ifa_addr->sa_family) { 92130106f6aSPoul-Henning Kamp #ifdef INET 92230106f6aSPoul-Henning Kamp case AF_INET: 92330106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); /* before arpwhohas */ 924322dcb8dSMax Khon arp_ifinit(ifp, ifa); 92530106f6aSPoul-Henning Kamp break; 92630106f6aSPoul-Henning Kamp #endif 92730106f6aSPoul-Henning Kamp #ifdef IPX 92830106f6aSPoul-Henning Kamp /* 92930106f6aSPoul-Henning Kamp * XXX - This code is probably wrong 93030106f6aSPoul-Henning Kamp */ 93130106f6aSPoul-Henning Kamp case AF_IPX: 93230106f6aSPoul-Henning Kamp { 93330106f6aSPoul-Henning Kamp register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 9344c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 93530106f6aSPoul-Henning Kamp 93630106f6aSPoul-Henning Kamp if (ipx_nullhost(*ina)) 93730106f6aSPoul-Henning Kamp ina->x_host = 93886101139SPoul-Henning Kamp *(union ipx_host *) 93986101139SPoul-Henning Kamp ac->ac_enaddr; 94030106f6aSPoul-Henning Kamp else { 94130106f6aSPoul-Henning Kamp bcopy((caddr_t) ina->x_host.c_host, 94286101139SPoul-Henning Kamp (caddr_t) ac->ac_enaddr, 94386101139SPoul-Henning Kamp sizeof(ac->ac_enaddr)); 94430106f6aSPoul-Henning Kamp } 94530106f6aSPoul-Henning Kamp 94630106f6aSPoul-Henning Kamp /* 94730106f6aSPoul-Henning Kamp * Set new address 94830106f6aSPoul-Henning Kamp */ 94930106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 95030106f6aSPoul-Henning Kamp break; 95130106f6aSPoul-Henning Kamp } 95230106f6aSPoul-Henning Kamp #endif 95330106f6aSPoul-Henning Kamp #ifdef NS 95430106f6aSPoul-Henning Kamp /* 95530106f6aSPoul-Henning Kamp * XXX - This code is probably wrong 95630106f6aSPoul-Henning Kamp */ 95730106f6aSPoul-Henning Kamp case AF_NS: 95830106f6aSPoul-Henning Kamp { 95930106f6aSPoul-Henning Kamp register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 9604c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 96130106f6aSPoul-Henning Kamp 96230106f6aSPoul-Henning Kamp if (ns_nullhost(*ina)) 96330106f6aSPoul-Henning Kamp ina->x_host = 96486101139SPoul-Henning Kamp *(union ns_host *) (ac->ac_enaddr); 96530106f6aSPoul-Henning Kamp else { 96630106f6aSPoul-Henning Kamp bcopy((caddr_t) ina->x_host.c_host, 96786101139SPoul-Henning Kamp (caddr_t) ac->ac_enaddr, 96886101139SPoul-Henning Kamp sizeof(ac->ac_enaddr)); 96930106f6aSPoul-Henning Kamp } 97030106f6aSPoul-Henning Kamp 97130106f6aSPoul-Henning Kamp /* 97230106f6aSPoul-Henning Kamp * Set new address 97330106f6aSPoul-Henning Kamp */ 97430106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 97530106f6aSPoul-Henning Kamp break; 97630106f6aSPoul-Henning Kamp } 97730106f6aSPoul-Henning Kamp #endif 97830106f6aSPoul-Henning Kamp default: 97930106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 98030106f6aSPoul-Henning Kamp break; 98130106f6aSPoul-Henning Kamp } 98230106f6aSPoul-Henning Kamp break; 98330106f6aSPoul-Henning Kamp 98430106f6aSPoul-Henning Kamp case SIOCGIFADDR: 98530106f6aSPoul-Henning Kamp { 98630106f6aSPoul-Henning Kamp struct sockaddr *sa; 98730106f6aSPoul-Henning Kamp 98830106f6aSPoul-Henning Kamp sa = (struct sockaddr *) & ifr->ifr_data; 9894c8e8c05SJulian Elischer bcopy(IFP2AC(ifp)->ac_enaddr, 99030106f6aSPoul-Henning Kamp (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 99130106f6aSPoul-Henning Kamp } 99230106f6aSPoul-Henning Kamp break; 993fb583156SDavid Greenman 994fb583156SDavid Greenman case SIOCSIFMTU: 995fb583156SDavid Greenman /* 996fb583156SDavid Greenman * Set the interface MTU. 997fb583156SDavid Greenman */ 998fb583156SDavid Greenman if (ifr->ifr_mtu > ETHERMTU) { 999fb583156SDavid Greenman error = EINVAL; 1000fb583156SDavid Greenman } else { 1001fb583156SDavid Greenman ifp->if_mtu = ifr->ifr_mtu; 100230106f6aSPoul-Henning Kamp } 1003fb583156SDavid Greenman break; 1004fb583156SDavid Greenman } 1005fb583156SDavid Greenman return (error); 100630106f6aSPoul-Henning Kamp } 10071158dfb7SGarrett Wollman 100837c84183SPoul-Henning Kamp static int 10091158dfb7SGarrett Wollman ether_resolvemulti(ifp, llsa, sa) 10101158dfb7SGarrett Wollman struct ifnet *ifp; 10111158dfb7SGarrett Wollman struct sockaddr **llsa; 10121158dfb7SGarrett Wollman struct sockaddr *sa; 10131158dfb7SGarrett Wollman { 10141158dfb7SGarrett Wollman struct sockaddr_dl *sdl; 10151158dfb7SGarrett Wollman struct sockaddr_in *sin; 101682cd038dSYoshinobu Inoue #ifdef INET6 101782cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6; 101882cd038dSYoshinobu Inoue #endif 10191158dfb7SGarrett Wollman u_char *e_addr; 10201158dfb7SGarrett Wollman 10211158dfb7SGarrett Wollman switch(sa->sa_family) { 10221158dfb7SGarrett Wollman case AF_LINK: 10237f33a738SJulian Elischer /* 10247f33a738SJulian Elischer * No mapping needed. Just check that it's a valid MC address. 10257f33a738SJulian Elischer */ 10261158dfb7SGarrett Wollman sdl = (struct sockaddr_dl *)sa; 10271158dfb7SGarrett Wollman e_addr = LLADDR(sdl); 10281158dfb7SGarrett Wollman if ((e_addr[0] & 1) != 1) 10291158dfb7SGarrett Wollman return EADDRNOTAVAIL; 10301158dfb7SGarrett Wollman *llsa = 0; 10311158dfb7SGarrett Wollman return 0; 10321158dfb7SGarrett Wollman 10331158dfb7SGarrett Wollman #ifdef INET 10341158dfb7SGarrett Wollman case AF_INET: 10351158dfb7SGarrett Wollman sin = (struct sockaddr_in *)sa; 10361158dfb7SGarrett Wollman if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 10371158dfb7SGarrett Wollman return EADDRNOTAVAIL; 10381158dfb7SGarrett Wollman MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 103926e30963SBill Fenner M_WAITOK|M_ZERO); 10401158dfb7SGarrett Wollman sdl->sdl_len = sizeof *sdl; 10411158dfb7SGarrett Wollman sdl->sdl_family = AF_LINK; 10421158dfb7SGarrett Wollman sdl->sdl_index = ifp->if_index; 10431158dfb7SGarrett Wollman sdl->sdl_type = IFT_ETHER; 10441158dfb7SGarrett Wollman sdl->sdl_alen = ETHER_ADDR_LEN; 10451158dfb7SGarrett Wollman e_addr = LLADDR(sdl); 10461158dfb7SGarrett Wollman ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 10471158dfb7SGarrett Wollman *llsa = (struct sockaddr *)sdl; 10481158dfb7SGarrett Wollman return 0; 10491158dfb7SGarrett Wollman #endif 105082cd038dSYoshinobu Inoue #ifdef INET6 105182cd038dSYoshinobu Inoue case AF_INET6: 105282cd038dSYoshinobu Inoue sin6 = (struct sockaddr_in6 *)sa; 1053595b8a1cSJun-ichiro itojun Hagino if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1054595b8a1cSJun-ichiro itojun Hagino /* 1055595b8a1cSJun-ichiro itojun Hagino * An IP6 address of 0 means listen to all 1056595b8a1cSJun-ichiro itojun Hagino * of the Ethernet multicast address used for IP6. 1057595b8a1cSJun-ichiro itojun Hagino * (This is used for multicast routers.) 1058595b8a1cSJun-ichiro itojun Hagino */ 1059595b8a1cSJun-ichiro itojun Hagino ifp->if_flags |= IFF_ALLMULTI; 1060595b8a1cSJun-ichiro itojun Hagino *llsa = 0; 1061595b8a1cSJun-ichiro itojun Hagino return 0; 1062595b8a1cSJun-ichiro itojun Hagino } 106382cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 106482cd038dSYoshinobu Inoue return EADDRNOTAVAIL; 106582cd038dSYoshinobu Inoue MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 106626e30963SBill Fenner M_WAITOK|M_ZERO); 106782cd038dSYoshinobu Inoue sdl->sdl_len = sizeof *sdl; 106882cd038dSYoshinobu Inoue sdl->sdl_family = AF_LINK; 106982cd038dSYoshinobu Inoue sdl->sdl_index = ifp->if_index; 107082cd038dSYoshinobu Inoue sdl->sdl_type = IFT_ETHER; 107182cd038dSYoshinobu Inoue sdl->sdl_alen = ETHER_ADDR_LEN; 107282cd038dSYoshinobu Inoue e_addr = LLADDR(sdl); 107382cd038dSYoshinobu Inoue ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 107482cd038dSYoshinobu Inoue *llsa = (struct sockaddr *)sdl; 107582cd038dSYoshinobu Inoue return 0; 107682cd038dSYoshinobu Inoue #endif 10771158dfb7SGarrett Wollman 10781158dfb7SGarrett Wollman default: 10791158dfb7SGarrett Wollman /* 10801158dfb7SGarrett Wollman * Well, the text isn't quite right, but it's the name 10811158dfb7SGarrett Wollman * that counts... 10821158dfb7SGarrett Wollman */ 10831158dfb7SGarrett Wollman return EAFNOSUPPORT; 10841158dfb7SGarrett Wollman } 10851158dfb7SGarrett Wollman } 1086