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" 424cf49a43SJulian Elischer #include "opt_netgraph.h" 43430df5f4SEivind Eklund 44df8bae1dSRodney W. Grimes #include <sys/param.h> 45df8bae1dSRodney W. Grimes #include <sys/systm.h> 46df8bae1dSRodney W. Grimes #include <sys/kernel.h> 47df8bae1dSRodney W. Grimes #include <sys/malloc.h> 48df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 4910b1fde0SMark Murray #include <sys/random.h> 50df8bae1dSRodney W. Grimes #include <sys/socket.h> 5151a53488SBruce Evans #include <sys/sockio.h> 52602d513cSGarrett Wollman #include <sys/sysctl.h> 53df8bae1dSRodney W. Grimes 54df8bae1dSRodney W. Grimes #include <net/if.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> 62db69a05dSPaul Saab #include <net/bridge.h> 63df8bae1dSRodney W. Grimes 6482cd038dSYoshinobu Inoue #if defined(INET) || defined(INET6) 65df8bae1dSRodney W. Grimes #include <netinet/in.h> 66df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 67df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 681d5e9e22SEivind Eklund #endif 6982cd038dSYoshinobu Inoue #ifdef INET6 7082cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 7182cd038dSYoshinobu Inoue #endif 72df8bae1dSRodney W. Grimes 73cc6a66f2SJulian Elischer #ifdef IPX 74cc6a66f2SJulian Elischer #include <netipx/ipx.h> 75cc6a66f2SJulian Elischer #include <netipx/ipx_if.h> 764f93599fSBoris Popov int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m); 775accfb8cSBoris Popov int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp, 782a7e8eceSBoris Popov struct sockaddr *dst, short *tp, int *hlen); 79cc6a66f2SJulian Elischer #endif 80cc6a66f2SJulian Elischer 81df8bae1dSRodney W. Grimes #ifdef NS 82df8bae1dSRodney W. Grimes #include <netns/ns.h> 83df8bae1dSRodney W. Grimes #include <netns/ns_if.h> 84d0ec898dSJordan K. Hubbard ushort ns_nettype; 8588e038feSJordan K. Hubbard int ether_outputdebug = 0; 8688e038feSJordan K. Hubbard int ether_inputdebug = 0; 87df8bae1dSRodney W. Grimes #endif 88df8bae1dSRodney W. Grimes 89655929bfSJulian Elischer #ifdef NETATALK 90655929bfSJulian Elischer #include <netatalk/at.h> 91655929bfSJulian Elischer #include <netatalk/at_var.h> 92655929bfSJulian Elischer #include <netatalk/at_extern.h> 93655929bfSJulian Elischer 94655929bfSJulian Elischer #define llc_snap_org_code llc_un.type_snap.org_code 95655929bfSJulian Elischer #define llc_snap_ether_type llc_un.type_snap.ether_type 96655929bfSJulian Elischer 97655929bfSJulian Elischer extern u_char at_org_code[3]; 98655929bfSJulian Elischer extern u_char aarp_org_code[3]; 992cc2df49SGarrett Wollman #endif /* NETATALK */ 1002cc2df49SGarrett Wollman 101e1e1452dSArchie Cobbs /* netgraph node hooks for ng_ether(4) */ 102e1e1452dSArchie Cobbs void (*ng_ether_input_p)(struct ifnet *ifp, 103e1e1452dSArchie Cobbs struct mbuf **mp, struct ether_header *eh); 104e1e1452dSArchie Cobbs void (*ng_ether_input_orphan_p)(struct ifnet *ifp, 105e1e1452dSArchie Cobbs struct mbuf *m, struct ether_header *eh); 106e1e1452dSArchie Cobbs int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp); 107e1e1452dSArchie Cobbs void (*ng_ether_attach_p)(struct ifnet *ifp); 108e1e1452dSArchie Cobbs void (*ng_ether_detach_p)(struct ifnet *ifp); 109e1e1452dSArchie Cobbs 1109d4fe4b2SBrooks Davis int (*vlan_input_p)(struct ether_header *eh, struct mbuf *m); 1119d4fe4b2SBrooks Davis int (*vlan_input_tag_p)(struct ether_header *eh, struct mbuf *m, 1129d4fe4b2SBrooks Davis u_int16_t t); 1139d4fe4b2SBrooks Davis 114db69a05dSPaul Saab /* bridge support */ 115cad15830SLuigi Rizzo int do_bridge; 116db69a05dSPaul Saab bridge_in_t *bridge_in_ptr; 117db69a05dSPaul Saab bdg_forward_t *bdg_forward_ptr; 118db69a05dSPaul Saab bdgtakeifaces_t *bdgtakeifaces_ptr; 119cad15830SLuigi Rizzo struct bdg_softc *ifp2sc; 120db69a05dSPaul Saab 1211158dfb7SGarrett Wollman static int ether_resolvemulti __P((struct ifnet *, struct sockaddr **, 1221158dfb7SGarrett Wollman struct sockaddr *)); 123df8bae1dSRodney W. Grimes u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 1244c8e8c05SJulian Elischer #define senderr(e) do { error = (e); goto bad;} while (0) 1254c8e8c05SJulian Elischer #define IFP2AC(IFP) ((struct arpcom *)IFP) 126df8bae1dSRodney W. Grimes 127df8bae1dSRodney W. Grimes /* 128df8bae1dSRodney W. Grimes * Ethernet output routine. 129df8bae1dSRodney W. Grimes * Encapsulate a packet of type family for the local net. 130df8bae1dSRodney W. Grimes * Use trailer local net encapsulation if enough data in first 131df8bae1dSRodney W. Grimes * packet leaves a multiple of 512 bytes of data in remainder. 132df8bae1dSRodney W. Grimes * Assumes that ifp is actually pointer to arpcom structure. 133df8bae1dSRodney W. Grimes */ 134df8bae1dSRodney W. Grimes int 135d25f3712SBrian Feldman ether_output(ifp, m, dst, rt0) 136df8bae1dSRodney W. Grimes register struct ifnet *ifp; 137d25f3712SBrian Feldman struct mbuf *m; 138df8bae1dSRodney W. Grimes struct sockaddr *dst; 139df8bae1dSRodney W. Grimes struct rtentry *rt0; 140df8bae1dSRodney W. Grimes { 141df8bae1dSRodney W. Grimes short type; 142e1e1452dSArchie Cobbs int error = 0, hdrcmplt = 0; 143114ae644SMike Smith u_char esrc[6], edst[6]; 144df8bae1dSRodney W. Grimes register struct rtentry *rt; 145df8bae1dSRodney W. Grimes register struct ether_header *eh; 146e1e1452dSArchie Cobbs int off, loop_copy = 0; 14784dd0fd0SJulian Elischer int hlen; /* link layer header lenght */ 1484c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 149df8bae1dSRodney W. Grimes 150df8bae1dSRodney W. Grimes if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 151df8bae1dSRodney W. Grimes senderr(ENETDOWN); 1523bda9f9bSPoul-Henning Kamp rt = rt0; 1533bda9f9bSPoul-Henning Kamp if (rt) { 154df8bae1dSRodney W. Grimes if ((rt->rt_flags & RTF_UP) == 0) { 1553bda9f9bSPoul-Henning Kamp rt0 = rt = rtalloc1(dst, 1, 0UL); 1563bda9f9bSPoul-Henning Kamp if (rt0) 157df8bae1dSRodney W. Grimes rt->rt_refcnt--; 158df8bae1dSRodney W. Grimes else 159df8bae1dSRodney W. Grimes senderr(EHOSTUNREACH); 160df8bae1dSRodney W. Grimes } 161df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) { 162df8bae1dSRodney W. Grimes if (rt->rt_gwroute == 0) 163df8bae1dSRodney W. Grimes goto lookup; 164df8bae1dSRodney W. Grimes if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 165df8bae1dSRodney W. Grimes rtfree(rt); rt = rt0; 166995add1aSGarrett Wollman lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 167995add1aSGarrett Wollman 0UL); 168df8bae1dSRodney W. Grimes if ((rt = rt->rt_gwroute) == 0) 169df8bae1dSRodney W. Grimes senderr(EHOSTUNREACH); 170df8bae1dSRodney W. Grimes } 171df8bae1dSRodney W. Grimes } 172df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_REJECT) 173df8bae1dSRodney W. Grimes if (rt->rt_rmx.rmx_expire == 0 || 174227ee8a1SPoul-Henning Kamp time_second < rt->rt_rmx.rmx_expire) 175df8bae1dSRodney W. Grimes senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 176df8bae1dSRodney W. Grimes } 17784dd0fd0SJulian Elischer hlen = ETHER_HDR_LEN; 178df8bae1dSRodney W. Grimes switch (dst->sa_family) { 179df8bae1dSRodney W. Grimes #ifdef INET 180df8bae1dSRodney W. Grimes case AF_INET: 181322dcb8dSMax Khon if (!arpresolve(ifp, rt, m, dst, edst, rt0)) 182df8bae1dSRodney W. Grimes return (0); /* if not yet resolved */ 183df8bae1dSRodney W. Grimes off = m->m_pkthdr.len - m->m_len; 18434bed8b0SDavid Greenman type = htons(ETHERTYPE_IP); 185df8bae1dSRodney W. Grimes break; 186df8bae1dSRodney W. Grimes #endif 18782cd038dSYoshinobu Inoue #ifdef INET6 18882cd038dSYoshinobu Inoue case AF_INET6: 18982cd038dSYoshinobu Inoue if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { 190fef5fd23SBosko Milekic /* Something bad happened */ 19182cd038dSYoshinobu Inoue return(0); 19282cd038dSYoshinobu Inoue } 19382cd038dSYoshinobu Inoue off = m->m_pkthdr.len - m->m_len; 19482cd038dSYoshinobu Inoue type = htons(ETHERTYPE_IPV6); 19582cd038dSYoshinobu Inoue break; 19682cd038dSYoshinobu Inoue #endif 197cc6a66f2SJulian Elischer #ifdef IPX 198cc6a66f2SJulian Elischer case AF_IPX: 1994f93599fSBoris Popov if (ef_outputp) { 2002a7e8eceSBoris Popov error = ef_outputp(ifp, &m, dst, &type, &hlen); 2015accfb8cSBoris Popov if (error) 2025accfb8cSBoris Popov goto bad; 2034f93599fSBoris Popov } else 20434bed8b0SDavid Greenman type = htons(ETHERTYPE_IPX); 205cc6a66f2SJulian Elischer bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 206cc6a66f2SJulian Elischer (caddr_t)edst, sizeof (edst)); 207cc6a66f2SJulian Elischer break; 208cc6a66f2SJulian Elischer #endif 209655929bfSJulian Elischer #ifdef NETATALK 210655929bfSJulian Elischer case AF_APPLETALK: 2111d0eab59SJulian Elischer { 212ed7509acSJulian Elischer struct at_ifaddr *aa; 2131d0eab59SJulian Elischer 214ed7509acSJulian Elischer if ((aa = at_ifawithnet((struct sockaddr_at *)dst)) == NULL) { 2151d0eab59SJulian Elischer goto bad; 2161d0eab59SJulian Elischer } 217ed7509acSJulian Elischer if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) 2181d0eab59SJulian Elischer return (0); 219655929bfSJulian Elischer /* 220ed7509acSJulian Elischer * In the phase 2 case, need to prepend an mbuf for the llc header. 221655929bfSJulian Elischer * Since we must preserve the value of m, which is passed to us by 222655929bfSJulian Elischer * value, we m_copy() the first mbuf, and use it for our llc header. 223655929bfSJulian Elischer */ 224655929bfSJulian Elischer if ( aa->aa_flags & AFA_PHASE2 ) { 225655929bfSJulian Elischer struct llc llc; 226655929bfSJulian Elischer 2272a0c503eSBosko Milekic M_PREPEND(m, sizeof(struct llc), M_TRYWAIT); 228655929bfSJulian Elischer llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 229655929bfSJulian Elischer llc.llc_control = LLC_UI; 230655929bfSJulian Elischer bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); 231655929bfSJulian Elischer llc.llc_snap_ether_type = htons( ETHERTYPE_AT ); 232655929bfSJulian Elischer bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); 23334bed8b0SDavid Greenman type = htons(m->m_pkthdr.len); 23484dd0fd0SJulian Elischer hlen = sizeof(struct llc) + ETHER_HDR_LEN; 235655929bfSJulian Elischer } else { 23634bed8b0SDavid Greenman type = htons(ETHERTYPE_AT); 237655929bfSJulian Elischer } 238655929bfSJulian Elischer break; 239ed7509acSJulian Elischer } 2408cdfefbdSPeter Wemm #endif /* NETATALK */ 241df8bae1dSRodney W. Grimes #ifdef NS 242df8bae1dSRodney W. Grimes case AF_NS: 24388e038feSJordan K. Hubbard switch(ns_nettype){ 24488e038feSJordan K. Hubbard default: 24588e038feSJordan K. Hubbard case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ 24688e038feSJordan K. Hubbard type = 0x8137; 24788e038feSJordan K. Hubbard break; 24888e038feSJordan K. Hubbard case 0x0: /* Novell 802.3 */ 24988e038feSJordan K. Hubbard type = htons( m->m_pkthdr.len); 25088e038feSJordan K. Hubbard break; 25188e038feSJordan K. Hubbard case 0xe0e0: /* Novell 802.2 and Token-Ring */ 2522a0c503eSBosko Milekic M_PREPEND(m, 3, M_TRYWAIT); 25388e038feSJordan K. Hubbard type = htons( m->m_pkthdr.len); 25488e038feSJordan K. Hubbard cp = mtod(m, u_char *); 25588e038feSJordan K. Hubbard *cp++ = 0xE0; 25688e038feSJordan K. Hubbard *cp++ = 0xE0; 25788e038feSJordan K. Hubbard *cp++ = 0x03; 25888e038feSJordan K. Hubbard break; 25988e038feSJordan K. Hubbard } 260df8bae1dSRodney W. Grimes bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 261df8bae1dSRodney W. Grimes (caddr_t)edst, sizeof (edst)); 2624c8e8c05SJulian Elischer /* 2634c8e8c05SJulian Elischer * XXX if ns_thishost is the same as the node's ethernet 2644c8e8c05SJulian Elischer * address then just the default code will catch this anyhow. 2654c8e8c05SJulian Elischer * So I'm not sure if this next clause should be here at all? 2664c8e8c05SJulian Elischer * [JRE] 2674c8e8c05SJulian Elischer */ 26888e038feSJordan K. Hubbard if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))){ 26988e038feSJordan K. Hubbard m->m_pkthdr.rcvif = ifp; 27088e038feSJordan K. Hubbard inq = &nsintrq; 271df5e1987SJonathan Lemon if (IF_HANDOFF(inq, m, NULL)) 272df5e1987SJonathan Lemon schednetisr(NETISR_NS); 27388e038feSJordan K. Hubbard return (error); 27488e038feSJordan K. Hubbard } 27588e038feSJordan K. Hubbard if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof(edst))){ 2764c8e8c05SJulian Elischer m->m_flags |= M_BCAST; 27788e038feSJordan K. Hubbard } 278df8bae1dSRodney W. Grimes break; 27988e038feSJordan K. Hubbard #endif /* NS */ 280df8bae1dSRodney W. Grimes 281114ae644SMike Smith case pseudo_AF_HDRCMPLT: 282114ae644SMike Smith hdrcmplt = 1; 283114ae644SMike Smith eh = (struct ether_header *)dst->sa_data; 284114ae644SMike Smith (void)memcpy(esrc, eh->ether_shost, sizeof (esrc)); 285114ae644SMike Smith /* FALLTHROUGH */ 286114ae644SMike Smith 287df8bae1dSRodney W. Grimes case AF_UNSPEC: 2889d3f194dSJulian Elischer loop_copy = -1; /* if this is for us, don't do it */ 289df8bae1dSRodney W. Grimes eh = (struct ether_header *)dst->sa_data; 29094a5d9b6SDavid Greenman (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); 291df8bae1dSRodney W. Grimes type = eh->ether_type; 292df8bae1dSRodney W. Grimes break; 293df8bae1dSRodney W. Grimes 294df8bae1dSRodney W. Grimes default: 295df8bae1dSRodney W. Grimes printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 296df8bae1dSRodney W. Grimes dst->sa_family); 297df8bae1dSRodney W. Grimes senderr(EAFNOSUPPORT); 298df8bae1dSRodney W. Grimes } 299df8bae1dSRodney W. Grimes 300df8bae1dSRodney W. Grimes /* 301df8bae1dSRodney W. Grimes * Add local net header. If no space in first mbuf, 302df8bae1dSRodney W. Grimes * allocate another. 303df8bae1dSRodney W. Grimes */ 304df8bae1dSRodney W. Grimes M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); 305df8bae1dSRodney W. Grimes if (m == 0) 306df8bae1dSRodney W. Grimes senderr(ENOBUFS); 307df8bae1dSRodney W. Grimes eh = mtod(m, struct ether_header *); 30894a5d9b6SDavid Greenman (void)memcpy(&eh->ether_type, &type, 309df8bae1dSRodney W. Grimes sizeof(eh->ether_type)); 31094a5d9b6SDavid Greenman (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); 311114ae644SMike Smith if (hdrcmplt) 312114ae644SMike Smith (void)memcpy(eh->ether_shost, esrc, 313114ae644SMike Smith sizeof(eh->ether_shost)); 314114ae644SMike Smith else 31594a5d9b6SDavid Greenman (void)memcpy(eh->ether_shost, ac->ac_enaddr, 316df8bae1dSRodney W. Grimes sizeof(eh->ether_shost)); 317ed7509acSJulian Elischer 318ed7509acSJulian Elischer /* 319ed7509acSJulian Elischer * If a simplex interface, and the packet is being sent to our 320ed7509acSJulian Elischer * Ethernet address or a broadcast address, loopback a copy. 321ed7509acSJulian Elischer * XXX To make a simplex device behave exactly like a duplex 322ed7509acSJulian Elischer * device, we should copy in the case of sending to our own 323ed7509acSJulian Elischer * ethernet address (thus letting the original actually appear 324ed7509acSJulian Elischer * on the wire). However, we don't do that here for security 325ed7509acSJulian Elischer * reasons and compatibility with the original behavior. 326ed7509acSJulian Elischer */ 3274c8e8c05SJulian Elischer if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 3283cd67511SJesper Skriver int csum_flags = 0; 3293cd67511SJesper Skriver 3303cd67511SJesper Skriver if (m->m_pkthdr.csum_flags & CSUM_IP) 3313cd67511SJesper Skriver csum_flags |= (CSUM_IP_CHECKED|CSUM_IP_VALID); 3323cd67511SJesper Skriver if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) 3333cd67511SJesper Skriver csum_flags |= (CSUM_DATA_VALID|CSUM_PSEUDO_HDR); 3349d3f194dSJulian Elischer if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 335ed7509acSJulian Elischer struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 336ed7509acSJulian Elischer 3373cd67511SJesper Skriver n->m_pkthdr.csum_flags |= csum_flags; 3383cd67511SJesper Skriver if (csum_flags & CSUM_DATA_VALID) 3393cd67511SJesper Skriver n->m_pkthdr.csum_data = 0xffff; 3403cd67511SJesper Skriver 34106a429a3SArchie Cobbs (void) if_simloop(ifp, n, dst->sa_family, hlen); 342ed7509acSJulian Elischer } else if (bcmp(eh->ether_dhost, 343ed7509acSJulian Elischer eh->ether_shost, ETHER_ADDR_LEN) == 0) { 3443cd67511SJesper Skriver m->m_pkthdr.csum_flags |= csum_flags; 3453cd67511SJesper Skriver if (csum_flags & CSUM_DATA_VALID) 3463cd67511SJesper Skriver m->m_pkthdr.csum_data = 0xffff; 34706a429a3SArchie Cobbs (void) if_simloop(ifp, m, dst->sa_family, hlen); 348ed7509acSJulian Elischer return (0); /* XXX */ 349ed7509acSJulian Elischer } 350ed7509acSJulian Elischer } 3512e2de7f2SArchie Cobbs 352e1e1452dSArchie Cobbs /* Handle ng_ether(4) processing, if any */ 353e1e1452dSArchie Cobbs if (ng_ether_output_p != NULL) { 354e1e1452dSArchie Cobbs if ((error = (*ng_ether_output_p)(ifp, &m)) != 0) { 355e1e1452dSArchie Cobbs bad: if (m != NULL) 356e1e1452dSArchie Cobbs m_freem(m); 357e1e1452dSArchie Cobbs return (error); 358e1e1452dSArchie Cobbs } 359e1e1452dSArchie Cobbs if (m == NULL) 360e1e1452dSArchie Cobbs return (0); 361e1e1452dSArchie Cobbs } 362e1e1452dSArchie Cobbs 363e1e1452dSArchie Cobbs /* Continue with link-layer output */ 364e1e1452dSArchie Cobbs return ether_output_frame(ifp, m); 365e1e1452dSArchie Cobbs } 366e1e1452dSArchie Cobbs 367e1e1452dSArchie Cobbs /* 368e1e1452dSArchie Cobbs * Ethernet link layer output routine to send a raw frame to the device. 369e1e1452dSArchie Cobbs * 370e1e1452dSArchie Cobbs * This assumes that the 14 byte Ethernet header is present and contiguous 371e1e1452dSArchie Cobbs * in the first mbuf (if BRIDGE'ing). 372e1e1452dSArchie Cobbs */ 373e1e1452dSArchie Cobbs int 374e1e1452dSArchie Cobbs ether_output_frame(ifp, m) 375e1e1452dSArchie Cobbs struct ifnet *ifp; 376e1e1452dSArchie Cobbs struct mbuf *m; 377e1e1452dSArchie Cobbs { 378df5e1987SJonathan Lemon int error = 0; 379e1e1452dSArchie Cobbs 3807b109fa4SLuigi Rizzo if (BDG_ACTIVE(ifp) ) { 381507b4b54SLuigi Rizzo struct ether_header *eh; /* a ptr suffices */ 3821db59ce6SEivind Eklund 383fb5fbe46SLuigi Rizzo m->m_pkthdr.rcvif = NULL; 384507b4b54SLuigi Rizzo eh = mtod(m, struct ether_header *); 3852e2de7f2SArchie Cobbs m_adj(m, ETHER_HDR_LEN); 386db69a05dSPaul Saab m = bdg_forward_ptr(m, eh, ifp); 3872e2de7f2SArchie Cobbs if (m != NULL) 3882e2de7f2SArchie Cobbs m_freem(m); 3891db59ce6SEivind Eklund return (0); 390fb5fbe46SLuigi Rizzo } 3912e2de7f2SArchie Cobbs 392df8bae1dSRodney W. Grimes /* 393df5e1987SJonathan Lemon * Queue message on interface, update output statistics if 394df5e1987SJonathan Lemon * successful, and start output if interface not yet active. 395df8bae1dSRodney W. Grimes */ 396df5e1987SJonathan Lemon if (! IF_HANDOFF(&ifp->if_snd, m, ifp)) 397e1e1452dSArchie Cobbs return (ENOBUFS); 398df8bae1dSRodney W. Grimes return (error); 399df8bae1dSRodney W. Grimes } 400df8bae1dSRodney W. Grimes 401df8bae1dSRodney W. Grimes /* 402df8bae1dSRodney W. Grimes * Process a received Ethernet packet; 403df8bae1dSRodney W. Grimes * the packet is in the mbuf chain m without 404df8bae1dSRodney W. Grimes * the ether header, which is provided separately. 405e1e1452dSArchie Cobbs * 40602a282acSLuigi Rizzo * NOTA BENE: for many drivers "eh" is a pointer into the first mbuf or 40702a282acSLuigi Rizzo * cluster, right before m_data. So be very careful when working on m, 40802a282acSLuigi Rizzo * as you could destroy *eh !! 40902a282acSLuigi Rizzo * A (probably) more convenient and efficient interface to ether_input 41002a282acSLuigi Rizzo * is to have the whole packet (with the ethernet header) into the mbuf: 41102a282acSLuigi Rizzo * modules which do not need the ethernet header can easily drop it, while 41202a282acSLuigi Rizzo * others (most noticeably bridge and ng_ether) do not need to do additional 41302a282acSLuigi Rizzo * work to put the ethernet header back into the mbuf. 41402a282acSLuigi Rizzo * 415e1e1452dSArchie Cobbs * First we perform any link layer operations, then continue 416e1e1452dSArchie Cobbs * to the upper layers with ether_demux(). 417df8bae1dSRodney W. Grimes */ 418df8bae1dSRodney W. Grimes void 419df8bae1dSRodney W. Grimes ether_input(ifp, eh, m) 420df8bae1dSRodney W. Grimes struct ifnet *ifp; 421e1e1452dSArchie Cobbs struct ether_header *eh; 422df8bae1dSRodney W. Grimes struct mbuf *m; 423df8bae1dSRodney W. Grimes { 424507b4b54SLuigi Rizzo struct ether_header save_eh; 425df8bae1dSRodney W. Grimes 4262e2de7f2SArchie Cobbs /* Check for a BPF tap */ 4272e2de7f2SArchie Cobbs if (ifp->if_bpf != NULL) { 4282e2de7f2SArchie Cobbs struct m_hdr mh; 4292e2de7f2SArchie Cobbs 4302e2de7f2SArchie Cobbs /* This kludge is OK; BPF treats the "mbuf" as read-only */ 4312e2de7f2SArchie Cobbs mh.mh_next = m; 4322e2de7f2SArchie Cobbs mh.mh_data = (char *)eh; 4332e2de7f2SArchie Cobbs mh.mh_len = ETHER_HDR_LEN; 4342e2de7f2SArchie Cobbs bpf_mtap(ifp, (struct mbuf *)&mh); 4352e2de7f2SArchie Cobbs } 4362e2de7f2SArchie Cobbs 43705463bb5SDavid Greenman ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); 43805463bb5SDavid Greenman 439e1e1452dSArchie Cobbs /* Handle ng_ether(4) processing, if any */ 440e1e1452dSArchie Cobbs if (ng_ether_input_p != NULL) { 441e1e1452dSArchie Cobbs (*ng_ether_input_p)(ifp, &m, eh); 442e1e1452dSArchie Cobbs if (m == NULL) 443e1e1452dSArchie Cobbs return; 444e1e1452dSArchie Cobbs } 445e1e1452dSArchie Cobbs 4462e2de7f2SArchie Cobbs /* Check for bridging mode */ 4477b109fa4SLuigi Rizzo if (BDG_ACTIVE(ifp) ) { 4482e2de7f2SArchie Cobbs struct ifnet *bif; 4492e2de7f2SArchie Cobbs 4502e2de7f2SArchie Cobbs /* Check with bridging code */ 451db69a05dSPaul Saab if ((bif = bridge_in_ptr(ifp, eh)) == BDG_DROP) { 4522e2de7f2SArchie Cobbs m_freem(m); 4532e2de7f2SArchie Cobbs return; 4542e2de7f2SArchie Cobbs } 455ddacb30fSBosko Milekic if (bif != BDG_LOCAL) { 456507b4b54SLuigi Rizzo struct mbuf *oldm = m ; 457507b4b54SLuigi Rizzo 458507b4b54SLuigi Rizzo save_eh = *eh ; /* because it might change */ 459db69a05dSPaul Saab m = bdg_forward_ptr(m, eh, bif); /* needs forwarding */ 460ddacb30fSBosko Milekic /* 461db69a05dSPaul Saab * Do not continue if bdg_forward_ptr() processed our 462ddacb30fSBosko Milekic * packet (and cleared the mbuf pointer m) or if 463ddacb30fSBosko Milekic * it dropped (m_free'd) the packet itself. 464ddacb30fSBosko Milekic */ 465507b4b54SLuigi Rizzo if (m == NULL) { 466507b4b54SLuigi Rizzo if (bif == BDG_BCAST || bif == BDG_MCAST) 467507b4b54SLuigi Rizzo printf("bdg_forward drop MULTICAST PKT\n"); 468ddacb30fSBosko Milekic return; 469ddacb30fSBosko Milekic } 470507b4b54SLuigi Rizzo if (m != oldm) /* m changed! */ 471507b4b54SLuigi Rizzo eh = &save_eh ; 472507b4b54SLuigi Rizzo } 4732e2de7f2SArchie Cobbs if (bif == BDG_LOCAL 4742e2de7f2SArchie Cobbs || bif == BDG_BCAST 4752e2de7f2SArchie Cobbs || bif == BDG_MCAST) 4762e2de7f2SArchie Cobbs goto recvLocal; /* receive locally */ 4772e2de7f2SArchie Cobbs 4782e2de7f2SArchie Cobbs /* If not local and not multicast, just drop it */ 4792e2de7f2SArchie Cobbs if (m != NULL) 4802e2de7f2SArchie Cobbs m_freem(m); 4812e2de7f2SArchie Cobbs return; 4822e2de7f2SArchie Cobbs } 4832e2de7f2SArchie Cobbs 4842e2de7f2SArchie Cobbs recvLocal: 485e1e1452dSArchie Cobbs /* Continue with upper layer processing */ 486e1e1452dSArchie Cobbs ether_demux(ifp, eh, m); 48710b1fde0SMark Murray /* First chunk of an mbuf contains good junk */ 48810b1fde0SMark Murray if (harvest.ethernet) 48910b1fde0SMark Murray random_harvest(m, 16, 3, 0, RANDOM_NET); 490e1e1452dSArchie Cobbs } 491e1e1452dSArchie Cobbs 492e1e1452dSArchie Cobbs /* 493e1e1452dSArchie Cobbs * Upper layer processing for a received Ethernet packet. 494e1e1452dSArchie Cobbs */ 495e1e1452dSArchie Cobbs void 496e1e1452dSArchie Cobbs ether_demux(ifp, eh, m) 497e1e1452dSArchie Cobbs struct ifnet *ifp; 498e1e1452dSArchie Cobbs struct ether_header *eh; 499e1e1452dSArchie Cobbs struct mbuf *m; 500e1e1452dSArchie Cobbs { 501e1e1452dSArchie Cobbs struct ifqueue *inq; 502e1e1452dSArchie Cobbs u_short ether_type; 503e1e1452dSArchie Cobbs #if defined(NETATALK) 504e1e1452dSArchie Cobbs register struct llc *l; 505e1e1452dSArchie Cobbs #endif 50664b15424SJonathan Lemon 5077b109fa4SLuigi Rizzo if (! (BDG_ACTIVE(ifp) ) ) 508cb24f323SArchie Cobbs /* Discard packet if upper layers shouldn't see it because it was 509cb24f323SArchie Cobbs unicast to a different Ethernet address. If the driver is working 510cb24f323SArchie Cobbs properly, then this situation can only happen when the interface 511cb24f323SArchie Cobbs is in promiscuous mode. */ 512cb24f323SArchie Cobbs if ((ifp->if_flags & IFF_PROMISC) != 0 513cb24f323SArchie Cobbs && (eh->ether_dhost[0] & 1) == 0 514cb24f323SArchie Cobbs && bcmp(eh->ether_dhost, 515cb24f323SArchie Cobbs IFP2AC(ifp)->ac_enaddr, ETHER_ADDR_LEN) != 0) { 516cb24f323SArchie Cobbs m_freem(m); 517cb24f323SArchie Cobbs return; 518cb24f323SArchie Cobbs } 519cb24f323SArchie Cobbs 5202e2de7f2SArchie Cobbs /* Discard packet if interface is not up */ 521df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) { 522df8bae1dSRodney W. Grimes m_freem(m); 523df8bae1dSRodney W. Grimes return; 524df8bae1dSRodney W. Grimes } 5252cc2df49SGarrett Wollman if (eh->ether_dhost[0] & 1) { 526df8bae1dSRodney W. Grimes if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 527df8bae1dSRodney W. Grimes sizeof(etherbroadcastaddr)) == 0) 528df8bae1dSRodney W. Grimes m->m_flags |= M_BCAST; 5292cc2df49SGarrett Wollman else 530df8bae1dSRodney W. Grimes m->m_flags |= M_MCAST; 5312cc2df49SGarrett Wollman } 532df8bae1dSRodney W. Grimes if (m->m_flags & (M_BCAST|M_MCAST)) 533df8bae1dSRodney W. Grimes ifp->if_imcasts++; 534df8bae1dSRodney W. Grimes 535307d80beSDavid Greenman ether_type = ntohs(eh->ether_type); 536307d80beSDavid Greenman 537307d80beSDavid Greenman switch (ether_type) { 538df8bae1dSRodney W. Grimes #ifdef INET 539df8bae1dSRodney W. Grimes case ETHERTYPE_IP: 5401f91d8c5SDavid Greenman if (ipflow_fastforward(m)) 5411f91d8c5SDavid Greenman return; 542df8bae1dSRodney W. Grimes schednetisr(NETISR_IP); 543df8bae1dSRodney W. Grimes inq = &ipintrq; 544df8bae1dSRodney W. Grimes break; 545df8bae1dSRodney W. Grimes 546df8bae1dSRodney W. Grimes case ETHERTYPE_ARP: 54708aadfbbSJonathan Lemon if (ifp->if_flags & IFF_NOARP) { 54808aadfbbSJonathan Lemon /* Discard packet if ARP is disabled on interface */ 54908aadfbbSJonathan Lemon m_freem(m); 55008aadfbbSJonathan Lemon return; 55108aadfbbSJonathan Lemon } 552df8bae1dSRodney W. Grimes schednetisr(NETISR_ARP); 553df8bae1dSRodney W. Grimes inq = &arpintrq; 554df8bae1dSRodney W. Grimes break; 555df8bae1dSRodney W. Grimes #endif 556cc6a66f2SJulian Elischer #ifdef IPX 557cc6a66f2SJulian Elischer case ETHERTYPE_IPX: 5584f93599fSBoris Popov if (ef_inputp && ef_inputp(ifp, eh, m) == 0) 5594f93599fSBoris Popov return; 560cc6a66f2SJulian Elischer schednetisr(NETISR_IPX); 561cc6a66f2SJulian Elischer inq = &ipxintrq; 562cc6a66f2SJulian Elischer break; 563cc6a66f2SJulian Elischer #endif 56482cd038dSYoshinobu Inoue #ifdef INET6 56582cd038dSYoshinobu Inoue case ETHERTYPE_IPV6: 56682cd038dSYoshinobu Inoue schednetisr(NETISR_IPV6); 56782cd038dSYoshinobu Inoue inq = &ip6intrq; 56882cd038dSYoshinobu Inoue break; 56982cd038dSYoshinobu Inoue #endif 570df8bae1dSRodney W. Grimes #ifdef NS 57188e038feSJordan K. Hubbard case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ 572df8bae1dSRodney W. Grimes schednetisr(NETISR_NS); 573df8bae1dSRodney W. Grimes inq = &nsintrq; 574df8bae1dSRodney W. Grimes break; 57588e038feSJordan K. Hubbard 57688e038feSJordan K. Hubbard #endif /* NS */ 577655929bfSJulian Elischer #ifdef NETATALK 578655929bfSJulian Elischer case ETHERTYPE_AT: 579655929bfSJulian Elischer schednetisr(NETISR_ATALK); 580655929bfSJulian Elischer inq = &atintrq1; 581655929bfSJulian Elischer break; 582655929bfSJulian Elischer case ETHERTYPE_AARP: 583655929bfSJulian Elischer /* probably this should be done with a NETISR as well */ 5844c8e8c05SJulian Elischer aarpinput(IFP2AC(ifp), m); /* XXX */ 585655929bfSJulian Elischer return; 5868cdfefbdSPeter Wemm #endif /* NETATALK */ 5879d4fe4b2SBrooks Davis case ETHERTYPE_VLAN: 588437e48e9SBrooks Davis VLAN_INPUT(eh, m); 5899d4fe4b2SBrooks Davis return; 590df8bae1dSRodney W. Grimes default: 5914f93599fSBoris Popov #ifdef IPX 5924f93599fSBoris Popov if (ef_inputp && ef_inputp(ifp, eh, m) == 0) 5934f93599fSBoris Popov return; 5944f93599fSBoris Popov #endif /* IPX */ 59588e038feSJordan K. Hubbard #ifdef NS 59688e038feSJordan K. Hubbard checksum = mtod(m, ushort *); 59788e038feSJordan K. Hubbard /* Novell 802.3 */ 59888e038feSJordan K. Hubbard if ((ether_type <= ETHERMTU) && 59988e038feSJordan K. Hubbard ((*checksum == 0xffff) || (*checksum == 0xE0E0))){ 60088e038feSJordan K. Hubbard if(*checksum == 0xE0E0) { 60188e038feSJordan K. Hubbard m->m_pkthdr.len -= 3; 60288e038feSJordan K. Hubbard m->m_len -= 3; 60388e038feSJordan K. Hubbard m->m_data += 3; 60488e038feSJordan K. Hubbard } 60588e038feSJordan K. Hubbard schednetisr(NETISR_NS); 60688e038feSJordan K. Hubbard inq = &nsintrq; 60788e038feSJordan K. Hubbard break; 60888e038feSJordan K. Hubbard } 60988e038feSJordan K. Hubbard #endif /* NS */ 610242c5536SPeter Wemm #if defined(NETATALK) 611307d80beSDavid Greenman if (ether_type > ETHERMTU) 612df8bae1dSRodney W. Grimes goto dropanyway; 613df8bae1dSRodney W. Grimes l = mtod(m, struct llc *); 614df8bae1dSRodney W. Grimes switch (l->llc_dsap) { 615655929bfSJulian Elischer case LLC_SNAP_LSAP: 616655929bfSJulian Elischer switch (l->llc_control) { 617655929bfSJulian Elischer case LLC_UI: 618655929bfSJulian Elischer if (l->llc_ssap != LLC_SNAP_LSAP) 619655929bfSJulian Elischer goto dropanyway; 620655929bfSJulian Elischer 621655929bfSJulian Elischer if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, 622655929bfSJulian Elischer sizeof(at_org_code)) == 0 && 623655929bfSJulian Elischer ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { 624655929bfSJulian Elischer inq = &atintrq2; 625655929bfSJulian Elischer m_adj( m, sizeof( struct llc )); 626655929bfSJulian Elischer schednetisr(NETISR_ATALK); 627655929bfSJulian Elischer break; 628655929bfSJulian Elischer } 629655929bfSJulian Elischer 630655929bfSJulian Elischer if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, 631655929bfSJulian Elischer sizeof(aarp_org_code)) == 0 && 632655929bfSJulian Elischer ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { 633655929bfSJulian Elischer m_adj( m, sizeof( struct llc )); 6344c8e8c05SJulian Elischer aarpinput(IFP2AC(ifp), m); /* XXX */ 635655929bfSJulian Elischer return; 636655929bfSJulian Elischer } 637655929bfSJulian Elischer 638655929bfSJulian Elischer default: 639655929bfSJulian Elischer goto dropanyway; 640655929bfSJulian Elischer } 641655929bfSJulian Elischer break; 642df8bae1dSRodney W. Grimes dropanyway: 643df8bae1dSRodney W. Grimes default: 644e1e1452dSArchie Cobbs if (ng_ether_input_orphan_p != NULL) 645e1e1452dSArchie Cobbs (*ng_ether_input_orphan_p)(ifp, m, eh); 646e1e1452dSArchie Cobbs else 647df8bae1dSRodney W. Grimes m_freem(m); 648df8bae1dSRodney W. Grimes return; 649df8bae1dSRodney W. Grimes } 650242c5536SPeter Wemm #else /* NETATALK */ 651e1e1452dSArchie Cobbs if (ng_ether_input_orphan_p != NULL) 652e1e1452dSArchie Cobbs (*ng_ether_input_orphan_p)(ifp, m, eh); 653e1e1452dSArchie Cobbs else 654df8bae1dSRodney W. Grimes m_freem(m); 655df8bae1dSRodney W. Grimes return; 656242c5536SPeter Wemm #endif /* NETATALK */ 657df8bae1dSRodney W. Grimes } 658df8bae1dSRodney W. Grimes 659df5e1987SJonathan Lemon (void) IF_HANDOFF(inq, m, NULL); 660df8bae1dSRodney W. Grimes } 661df8bae1dSRodney W. Grimes 662df8bae1dSRodney W. Grimes /* 663df8bae1dSRodney W. Grimes * Perform common duties while attaching to interface list 664df8bae1dSRodney W. Grimes */ 665df8bae1dSRodney W. Grimes void 66621b8ebd9SArchie Cobbs ether_ifattach(ifp, bpf) 667df8bae1dSRodney W. Grimes register struct ifnet *ifp; 66821b8ebd9SArchie Cobbs int bpf; 669df8bae1dSRodney W. Grimes { 670df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 671df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl; 672df8bae1dSRodney W. Grimes 673df8bae1dSRodney W. Grimes ifp->if_type = IFT_ETHER; 674df8bae1dSRodney W. Grimes ifp->if_addrlen = 6; 675df8bae1dSRodney W. Grimes ifp->if_hdrlen = 14; 676cfeff1b6SJonathan Lemon if_attach(ifp); 677df8bae1dSRodney W. Grimes ifp->if_mtu = ETHERMTU; 6781158dfb7SGarrett Wollman ifp->if_resolvemulti = ether_resolvemulti; 679a330e1f1SGary Palmer if (ifp->if_baudrate == 0) 680a330e1f1SGary Palmer ifp->if_baudrate = 10000000; 681322dcb8dSMax Khon ifp->if_broadcastaddr = etherbroadcastaddr; 682f9132cebSJonathan Lemon ifa = ifaddr_byindex(ifp->if_index); 6836e551fb6SDavid E. O'Brien KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 68459562606SGarrett Wollman sdl = (struct sockaddr_dl *)ifa->ifa_addr; 685df8bae1dSRodney W. Grimes sdl->sdl_type = IFT_ETHER; 686df8bae1dSRodney W. Grimes sdl->sdl_alen = ifp->if_addrlen; 6874c8e8c05SJulian Elischer bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 68821b8ebd9SArchie Cobbs if (bpf) 68921b8ebd9SArchie Cobbs bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 690e1e1452dSArchie Cobbs if (ng_ether_attach_p != NULL) 691e1e1452dSArchie Cobbs (*ng_ether_attach_p)(ifp); 6927b109fa4SLuigi Rizzo if (BDG_LOADED) 693db69a05dSPaul Saab bdgtakeifaces_ptr(); 694e1e1452dSArchie Cobbs } 695e1e1452dSArchie Cobbs 69621b8ebd9SArchie Cobbs /* 69721b8ebd9SArchie Cobbs * Perform common duties while detaching an Ethernet interface 69821b8ebd9SArchie Cobbs */ 69921b8ebd9SArchie Cobbs void 70021b8ebd9SArchie Cobbs ether_ifdetach(ifp, bpf) 70121b8ebd9SArchie Cobbs struct ifnet *ifp; 70221b8ebd9SArchie Cobbs int bpf; 70321b8ebd9SArchie Cobbs { 70421b8ebd9SArchie Cobbs if (ng_ether_detach_p != NULL) 70521b8ebd9SArchie Cobbs (*ng_ether_detach_p)(ifp); 70621b8ebd9SArchie Cobbs if (bpf) 70721b8ebd9SArchie Cobbs bpfdetach(ifp); 70821b8ebd9SArchie Cobbs if_detach(ifp); 7097b109fa4SLuigi Rizzo if (BDG_LOADED) 710db69a05dSPaul Saab bdgtakeifaces_ptr(); 71121b8ebd9SArchie Cobbs } 71221b8ebd9SArchie Cobbs 713ce02431fSDoug Rabson SYSCTL_DECL(_net_link); 714602d513cSGarrett Wollman SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); 71530106f6aSPoul-Henning Kamp 716fb583156SDavid Greenman int 717c5a1016bSBruce Evans ether_ioctl(ifp, command, data) 718c5a1016bSBruce Evans struct ifnet *ifp; 719c5a1016bSBruce Evans int command; 720c5a1016bSBruce Evans caddr_t data; 72130106f6aSPoul-Henning Kamp { 72230106f6aSPoul-Henning Kamp struct ifaddr *ifa = (struct ifaddr *) data; 72330106f6aSPoul-Henning Kamp struct ifreq *ifr = (struct ifreq *) data; 724fb583156SDavid Greenman int error = 0; 72530106f6aSPoul-Henning Kamp 72630106f6aSPoul-Henning Kamp switch (command) { 72730106f6aSPoul-Henning Kamp case SIOCSIFADDR: 72830106f6aSPoul-Henning Kamp ifp->if_flags |= IFF_UP; 72930106f6aSPoul-Henning Kamp 73030106f6aSPoul-Henning Kamp switch (ifa->ifa_addr->sa_family) { 73130106f6aSPoul-Henning Kamp #ifdef INET 73230106f6aSPoul-Henning Kamp case AF_INET: 73330106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); /* before arpwhohas */ 734322dcb8dSMax Khon arp_ifinit(ifp, ifa); 73530106f6aSPoul-Henning Kamp break; 73630106f6aSPoul-Henning Kamp #endif 73730106f6aSPoul-Henning Kamp #ifdef IPX 73830106f6aSPoul-Henning Kamp /* 73930106f6aSPoul-Henning Kamp * XXX - This code is probably wrong 74030106f6aSPoul-Henning Kamp */ 74130106f6aSPoul-Henning Kamp case AF_IPX: 74230106f6aSPoul-Henning Kamp { 74330106f6aSPoul-Henning Kamp register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 7444c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 74530106f6aSPoul-Henning Kamp 74630106f6aSPoul-Henning Kamp if (ipx_nullhost(*ina)) 74730106f6aSPoul-Henning Kamp ina->x_host = 74886101139SPoul-Henning Kamp *(union ipx_host *) 74986101139SPoul-Henning Kamp ac->ac_enaddr; 75030106f6aSPoul-Henning Kamp else { 75130106f6aSPoul-Henning Kamp bcopy((caddr_t) ina->x_host.c_host, 75286101139SPoul-Henning Kamp (caddr_t) ac->ac_enaddr, 75386101139SPoul-Henning Kamp sizeof(ac->ac_enaddr)); 75430106f6aSPoul-Henning Kamp } 75530106f6aSPoul-Henning Kamp 75630106f6aSPoul-Henning Kamp /* 75730106f6aSPoul-Henning Kamp * Set new address 75830106f6aSPoul-Henning Kamp */ 75930106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 76030106f6aSPoul-Henning Kamp break; 76130106f6aSPoul-Henning Kamp } 76230106f6aSPoul-Henning Kamp #endif 76330106f6aSPoul-Henning Kamp #ifdef NS 76430106f6aSPoul-Henning Kamp /* 76530106f6aSPoul-Henning Kamp * XXX - This code is probably wrong 76630106f6aSPoul-Henning Kamp */ 76730106f6aSPoul-Henning Kamp case AF_NS: 76830106f6aSPoul-Henning Kamp { 76930106f6aSPoul-Henning Kamp register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 7704c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 77130106f6aSPoul-Henning Kamp 77230106f6aSPoul-Henning Kamp if (ns_nullhost(*ina)) 77330106f6aSPoul-Henning Kamp ina->x_host = 77486101139SPoul-Henning Kamp *(union ns_host *) (ac->ac_enaddr); 77530106f6aSPoul-Henning Kamp else { 77630106f6aSPoul-Henning Kamp bcopy((caddr_t) ina->x_host.c_host, 77786101139SPoul-Henning Kamp (caddr_t) ac->ac_enaddr, 77886101139SPoul-Henning Kamp sizeof(ac->ac_enaddr)); 77930106f6aSPoul-Henning Kamp } 78030106f6aSPoul-Henning Kamp 78130106f6aSPoul-Henning Kamp /* 78230106f6aSPoul-Henning Kamp * Set new address 78330106f6aSPoul-Henning Kamp */ 78430106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 78530106f6aSPoul-Henning Kamp break; 78630106f6aSPoul-Henning Kamp } 78730106f6aSPoul-Henning Kamp #endif 78830106f6aSPoul-Henning Kamp default: 78930106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 79030106f6aSPoul-Henning Kamp break; 79130106f6aSPoul-Henning Kamp } 79230106f6aSPoul-Henning Kamp break; 79330106f6aSPoul-Henning Kamp 79430106f6aSPoul-Henning Kamp case SIOCGIFADDR: 79530106f6aSPoul-Henning Kamp { 79630106f6aSPoul-Henning Kamp struct sockaddr *sa; 79730106f6aSPoul-Henning Kamp 79830106f6aSPoul-Henning Kamp sa = (struct sockaddr *) & ifr->ifr_data; 7994c8e8c05SJulian Elischer bcopy(IFP2AC(ifp)->ac_enaddr, 80030106f6aSPoul-Henning Kamp (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 80130106f6aSPoul-Henning Kamp } 80230106f6aSPoul-Henning Kamp break; 803fb583156SDavid Greenman 804fb583156SDavid Greenman case SIOCSIFMTU: 805fb583156SDavid Greenman /* 806fb583156SDavid Greenman * Set the interface MTU. 807fb583156SDavid Greenman */ 808fb583156SDavid Greenman if (ifr->ifr_mtu > ETHERMTU) { 809fb583156SDavid Greenman error = EINVAL; 810fb583156SDavid Greenman } else { 811fb583156SDavid Greenman ifp->if_mtu = ifr->ifr_mtu; 81230106f6aSPoul-Henning Kamp } 813fb583156SDavid Greenman break; 814fb583156SDavid Greenman } 815fb583156SDavid Greenman return (error); 81630106f6aSPoul-Henning Kamp } 8171158dfb7SGarrett Wollman 8181158dfb7SGarrett Wollman int 8191158dfb7SGarrett Wollman ether_resolvemulti(ifp, llsa, sa) 8201158dfb7SGarrett Wollman struct ifnet *ifp; 8211158dfb7SGarrett Wollman struct sockaddr **llsa; 8221158dfb7SGarrett Wollman struct sockaddr *sa; 8231158dfb7SGarrett Wollman { 8241158dfb7SGarrett Wollman struct sockaddr_dl *sdl; 8251158dfb7SGarrett Wollman struct sockaddr_in *sin; 82682cd038dSYoshinobu Inoue #ifdef INET6 82782cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6; 82882cd038dSYoshinobu Inoue #endif 8291158dfb7SGarrett Wollman u_char *e_addr; 8301158dfb7SGarrett Wollman 8311158dfb7SGarrett Wollman switch(sa->sa_family) { 8321158dfb7SGarrett Wollman case AF_LINK: 8337f33a738SJulian Elischer /* 8347f33a738SJulian Elischer * No mapping needed. Just check that it's a valid MC address. 8357f33a738SJulian Elischer */ 8361158dfb7SGarrett Wollman sdl = (struct sockaddr_dl *)sa; 8371158dfb7SGarrett Wollman e_addr = LLADDR(sdl); 8381158dfb7SGarrett Wollman if ((e_addr[0] & 1) != 1) 8391158dfb7SGarrett Wollman return EADDRNOTAVAIL; 8401158dfb7SGarrett Wollman *llsa = 0; 8411158dfb7SGarrett Wollman return 0; 8421158dfb7SGarrett Wollman 8431158dfb7SGarrett Wollman #ifdef INET 8441158dfb7SGarrett Wollman case AF_INET: 8451158dfb7SGarrett Wollman sin = (struct sockaddr_in *)sa; 8461158dfb7SGarrett Wollman if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 8471158dfb7SGarrett Wollman return EADDRNOTAVAIL; 8481158dfb7SGarrett Wollman MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 84926e30963SBill Fenner M_WAITOK|M_ZERO); 8501158dfb7SGarrett Wollman sdl->sdl_len = sizeof *sdl; 8511158dfb7SGarrett Wollman sdl->sdl_family = AF_LINK; 8521158dfb7SGarrett Wollman sdl->sdl_index = ifp->if_index; 8531158dfb7SGarrett Wollman sdl->sdl_type = IFT_ETHER; 8541158dfb7SGarrett Wollman sdl->sdl_alen = ETHER_ADDR_LEN; 8551158dfb7SGarrett Wollman e_addr = LLADDR(sdl); 8561158dfb7SGarrett Wollman ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 8571158dfb7SGarrett Wollman *llsa = (struct sockaddr *)sdl; 8581158dfb7SGarrett Wollman return 0; 8591158dfb7SGarrett Wollman #endif 86082cd038dSYoshinobu Inoue #ifdef INET6 86182cd038dSYoshinobu Inoue case AF_INET6: 86282cd038dSYoshinobu Inoue sin6 = (struct sockaddr_in6 *)sa; 863595b8a1cSJun-ichiro itojun Hagino if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 864595b8a1cSJun-ichiro itojun Hagino /* 865595b8a1cSJun-ichiro itojun Hagino * An IP6 address of 0 means listen to all 866595b8a1cSJun-ichiro itojun Hagino * of the Ethernet multicast address used for IP6. 867595b8a1cSJun-ichiro itojun Hagino * (This is used for multicast routers.) 868595b8a1cSJun-ichiro itojun Hagino */ 869595b8a1cSJun-ichiro itojun Hagino ifp->if_flags |= IFF_ALLMULTI; 870595b8a1cSJun-ichiro itojun Hagino *llsa = 0; 871595b8a1cSJun-ichiro itojun Hagino return 0; 872595b8a1cSJun-ichiro itojun Hagino } 87382cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 87482cd038dSYoshinobu Inoue return EADDRNOTAVAIL; 87582cd038dSYoshinobu Inoue MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 87626e30963SBill Fenner M_WAITOK|M_ZERO); 87782cd038dSYoshinobu Inoue sdl->sdl_len = sizeof *sdl; 87882cd038dSYoshinobu Inoue sdl->sdl_family = AF_LINK; 87982cd038dSYoshinobu Inoue sdl->sdl_index = ifp->if_index; 88082cd038dSYoshinobu Inoue sdl->sdl_type = IFT_ETHER; 88182cd038dSYoshinobu Inoue sdl->sdl_alen = ETHER_ADDR_LEN; 88282cd038dSYoshinobu Inoue e_addr = LLADDR(sdl); 88382cd038dSYoshinobu Inoue ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 88482cd038dSYoshinobu Inoue *llsa = (struct sockaddr *)sdl; 88582cd038dSYoshinobu Inoue return 0; 88682cd038dSYoshinobu Inoue #endif 8871158dfb7SGarrett Wollman 8881158dfb7SGarrett Wollman default: 8891158dfb7SGarrett Wollman /* 8901158dfb7SGarrett Wollman * Well, the text isn't quite right, but it's the name 8911158dfb7SGarrett Wollman * that counts... 8921158dfb7SGarrett Wollman */ 8931158dfb7SGarrett Wollman return EAFNOSUPPORT; 8941158dfb7SGarrett Wollman } 8951158dfb7SGarrett Wollman } 8964cf49a43SJulian Elischer 897