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> 49df8bae1dSRodney W. Grimes #include <sys/socket.h> 5051a53488SBruce Evans #include <sys/sockio.h> 51602d513cSGarrett Wollman #include <sys/sysctl.h> 52df8bae1dSRodney W. Grimes 53df8bae1dSRodney W. Grimes #include <net/if.h> 54df8bae1dSRodney W. Grimes #include <net/netisr.h> 55df8bae1dSRodney W. Grimes #include <net/route.h> 56df8bae1dSRodney W. Grimes #include <net/if_llc.h> 57df8bae1dSRodney W. Grimes #include <net/if_dl.h> 58df8bae1dSRodney W. Grimes #include <net/if_types.h> 592e2de7f2SArchie Cobbs #include <net/bpf.h> 60df8bae1dSRodney W. Grimes 6182cd038dSYoshinobu Inoue #if defined(INET) || defined(INET6) 62df8bae1dSRodney W. Grimes #include <netinet/in.h> 63df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 64df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 651d5e9e22SEivind Eklund #endif 6682cd038dSYoshinobu Inoue #ifdef INET6 6782cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 6882cd038dSYoshinobu Inoue #include <netinet6/in6_ifattach.h> 6982cd038dSYoshinobu Inoue #endif 70df8bae1dSRodney W. Grimes 71cc6a66f2SJulian Elischer #ifdef IPX 72cc6a66f2SJulian Elischer #include <netipx/ipx.h> 73cc6a66f2SJulian Elischer #include <netipx/ipx_if.h> 744f93599fSBoris Popov int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m); 755accfb8cSBoris Popov int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp, 764f93599fSBoris Popov struct sockaddr *dst, short *tp); 77cc6a66f2SJulian Elischer #endif 78cc6a66f2SJulian Elischer 79df8bae1dSRodney W. Grimes #ifdef NS 80df8bae1dSRodney W. Grimes #include <netns/ns.h> 81df8bae1dSRodney W. Grimes #include <netns/ns_if.h> 82d0ec898dSJordan K. Hubbard ushort ns_nettype; 8388e038feSJordan K. Hubbard int ether_outputdebug = 0; 8488e038feSJordan K. Hubbard int ether_inputdebug = 0; 85df8bae1dSRodney W. Grimes #endif 86df8bae1dSRodney W. Grimes 87655929bfSJulian Elischer #ifdef NETATALK 88655929bfSJulian Elischer #include <netatalk/at.h> 89655929bfSJulian Elischer #include <netatalk/at_var.h> 90655929bfSJulian Elischer #include <netatalk/at_extern.h> 91655929bfSJulian Elischer 92655929bfSJulian Elischer #define llc_snap_org_code llc_un.type_snap.org_code 93655929bfSJulian Elischer #define llc_snap_ether_type llc_un.type_snap.ether_type 94655929bfSJulian Elischer 95655929bfSJulian Elischer extern u_char at_org_code[3]; 96655929bfSJulian Elischer extern u_char aarp_org_code[3]; 972cc2df49SGarrett Wollman #endif /* NETATALK */ 982cc2df49SGarrett Wollman 99fb5fbe46SLuigi Rizzo #ifdef BRIDGE 100fb5fbe46SLuigi Rizzo #include <net/bridge.h> 101fb5fbe46SLuigi Rizzo #endif 102fb5fbe46SLuigi Rizzo 1032cc2df49SGarrett Wollman #include "vlan.h" 1042cc2df49SGarrett Wollman #if NVLAN > 0 1052cc2df49SGarrett Wollman #include <net/if_vlan_var.h> 1062cc2df49SGarrett Wollman #endif /* NVLAN > 0 */ 107655929bfSJulian Elischer 1081158dfb7SGarrett Wollman static int ether_resolvemulti __P((struct ifnet *, struct sockaddr **, 1091158dfb7SGarrett Wollman struct sockaddr *)); 110df8bae1dSRodney W. Grimes u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 1114c8e8c05SJulian Elischer #define senderr(e) do { error = (e); goto bad;} while (0) 1124c8e8c05SJulian Elischer #define IFP2AC(IFP) ((struct arpcom *)IFP) 113df8bae1dSRodney W. Grimes 1144cf49a43SJulian Elischer #ifdef NETGRAPH 1154cf49a43SJulian Elischer #include <netgraph/ng_ether.h> 1164cf49a43SJulian Elischer #include <netgraph/ng_message.h> 1174cf49a43SJulian Elischer #include <netgraph/netgraph.h> 1184cf49a43SJulian Elischer 1194cf49a43SJulian Elischer static void ngether_init(void* ignored); 1204cf49a43SJulian Elischer static void ngether_send(struct arpcom *ac, 1214cf49a43SJulian Elischer struct ether_header *eh, struct mbuf *m); 122ae5a83bcSJulian Elischer static ng_constructor_t ngether_constructor; 123ae5a83bcSJulian Elischer static ng_rcvmsg_t ngether_rcvmsg; 124ae5a83bcSJulian Elischer static ng_shutdown_t ngether_rmnode; 125ae5a83bcSJulian Elischer static ng_newhook_t ngether_newhook; 126ae5a83bcSJulian Elischer static ng_connect_t ngether_connect; 127ae5a83bcSJulian Elischer static ng_rcvdata_t ngether_rcvdata; 128ae5a83bcSJulian Elischer static ng_disconnect_t ngether_disconnect; 1294cf49a43SJulian Elischer 1304cf49a43SJulian Elischer static struct ng_type typestruct = { 1314cf49a43SJulian Elischer NG_VERSION, 1324cf49a43SJulian Elischer NG_ETHER_NODE_TYPE, 1334cf49a43SJulian Elischer NULL, 1344cf49a43SJulian Elischer ngether_constructor, 1354cf49a43SJulian Elischer ngether_rcvmsg, 1364cf49a43SJulian Elischer ngether_rmnode, 1374cf49a43SJulian Elischer ngether_newhook, 1384cf49a43SJulian Elischer NULL, 1394cf49a43SJulian Elischer ngether_connect, 1404cf49a43SJulian Elischer ngether_rcvdata, 1414cf49a43SJulian Elischer ngether_rcvdata, 142f8307e12SArchie Cobbs ngether_disconnect, 143f8307e12SArchie Cobbs NULL 1444cf49a43SJulian Elischer }; 1454cf49a43SJulian Elischer 1464cf49a43SJulian Elischer #define AC2NG(AC) ((node_p)((AC)->ac_ng)) 1474cf49a43SJulian Elischer #define NGEF_DIVERT NGF_TYPE1 /* all packets sent to netgraph */ 1484cf49a43SJulian Elischer #endif /* NETGRAPH */ 1494cf49a43SJulian Elischer 150df8bae1dSRodney W. Grimes /* 151df8bae1dSRodney W. Grimes * Ethernet output routine. 152df8bae1dSRodney W. Grimes * Encapsulate a packet of type family for the local net. 153df8bae1dSRodney W. Grimes * Use trailer local net encapsulation if enough data in first 154df8bae1dSRodney W. Grimes * packet leaves a multiple of 512 bytes of data in remainder. 155df8bae1dSRodney W. Grimes * Assumes that ifp is actually pointer to arpcom structure. 156df8bae1dSRodney W. Grimes */ 157df8bae1dSRodney W. Grimes int 158d25f3712SBrian Feldman ether_output(ifp, m, dst, rt0) 159df8bae1dSRodney W. Grimes register struct ifnet *ifp; 160d25f3712SBrian Feldman struct mbuf *m; 161df8bae1dSRodney W. Grimes struct sockaddr *dst; 162df8bae1dSRodney W. Grimes struct rtentry *rt0; 163df8bae1dSRodney W. Grimes { 164df8bae1dSRodney W. Grimes short type; 165114ae644SMike Smith int s, error = 0, hdrcmplt = 0; 166114ae644SMike Smith u_char esrc[6], edst[6]; 167df8bae1dSRodney W. Grimes register struct rtentry *rt; 168df8bae1dSRodney W. Grimes register struct ether_header *eh; 169ed7509acSJulian Elischer int off, len = m->m_pkthdr.len, loop_copy = 0; 17084dd0fd0SJulian Elischer int hlen; /* link layer header lenght */ 1714c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 172df8bae1dSRodney W. Grimes 173df8bae1dSRodney W. Grimes if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 174df8bae1dSRodney W. Grimes senderr(ENETDOWN); 1753bda9f9bSPoul-Henning Kamp rt = rt0; 1763bda9f9bSPoul-Henning Kamp if (rt) { 177df8bae1dSRodney W. Grimes if ((rt->rt_flags & RTF_UP) == 0) { 1783bda9f9bSPoul-Henning Kamp rt0 = rt = rtalloc1(dst, 1, 0UL); 1793bda9f9bSPoul-Henning Kamp if (rt0) 180df8bae1dSRodney W. Grimes rt->rt_refcnt--; 181df8bae1dSRodney W. Grimes else 182df8bae1dSRodney W. Grimes senderr(EHOSTUNREACH); 183df8bae1dSRodney W. Grimes } 184df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) { 185df8bae1dSRodney W. Grimes if (rt->rt_gwroute == 0) 186df8bae1dSRodney W. Grimes goto lookup; 187df8bae1dSRodney W. Grimes if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 188df8bae1dSRodney W. Grimes rtfree(rt); rt = rt0; 189995add1aSGarrett Wollman lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 190995add1aSGarrett Wollman 0UL); 191df8bae1dSRodney W. Grimes if ((rt = rt->rt_gwroute) == 0) 192df8bae1dSRodney W. Grimes senderr(EHOSTUNREACH); 193df8bae1dSRodney W. Grimes } 194df8bae1dSRodney W. Grimes } 195df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_REJECT) 196df8bae1dSRodney W. Grimes if (rt->rt_rmx.rmx_expire == 0 || 197227ee8a1SPoul-Henning Kamp time_second < rt->rt_rmx.rmx_expire) 198df8bae1dSRodney W. Grimes senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 199df8bae1dSRodney W. Grimes } 20084dd0fd0SJulian Elischer hlen = ETHER_HDR_LEN; 201df8bae1dSRodney W. Grimes switch (dst->sa_family) { 202df8bae1dSRodney W. Grimes #ifdef INET 203df8bae1dSRodney W. Grimes case AF_INET: 2045df72964SGarrett Wollman if (!arpresolve(ac, rt, m, dst, edst, rt0)) 205df8bae1dSRodney W. Grimes return (0); /* if not yet resolved */ 206df8bae1dSRodney W. Grimes off = m->m_pkthdr.len - m->m_len; 20734bed8b0SDavid Greenman type = htons(ETHERTYPE_IP); 208df8bae1dSRodney W. Grimes break; 209df8bae1dSRodney W. Grimes #endif 21082cd038dSYoshinobu Inoue #ifdef INET6 21182cd038dSYoshinobu Inoue case AF_INET6: 21282cd038dSYoshinobu Inoue if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { 21382cd038dSYoshinobu Inoue /* this must be impossible, so we bark */ 21482cd038dSYoshinobu Inoue printf("nd6_storelladdr failed\n"); 21582cd038dSYoshinobu Inoue return(0); 21682cd038dSYoshinobu Inoue } 21782cd038dSYoshinobu Inoue off = m->m_pkthdr.len - m->m_len; 21882cd038dSYoshinobu Inoue type = htons(ETHERTYPE_IPV6); 21982cd038dSYoshinobu Inoue break; 22082cd038dSYoshinobu Inoue #endif 221cc6a66f2SJulian Elischer #ifdef IPX 222cc6a66f2SJulian Elischer case AF_IPX: 2234f93599fSBoris Popov if (ef_outputp) { 2245accfb8cSBoris Popov error = ef_outputp(ifp, &m, dst, &type); 2255accfb8cSBoris Popov if (error) 2265accfb8cSBoris Popov goto bad; 2274f93599fSBoris Popov } else 22834bed8b0SDavid Greenman type = htons(ETHERTYPE_IPX); 229cc6a66f2SJulian Elischer bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 230cc6a66f2SJulian Elischer (caddr_t)edst, sizeof (edst)); 231cc6a66f2SJulian Elischer break; 232cc6a66f2SJulian Elischer #endif 233655929bfSJulian Elischer #ifdef NETATALK 234655929bfSJulian Elischer case AF_APPLETALK: 2351d0eab59SJulian Elischer { 236ed7509acSJulian Elischer struct at_ifaddr *aa; 2371d0eab59SJulian Elischer 238ed7509acSJulian Elischer if ((aa = at_ifawithnet((struct sockaddr_at *)dst)) == NULL) { 2391d0eab59SJulian Elischer goto bad; 2401d0eab59SJulian Elischer } 241ed7509acSJulian Elischer if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) 2421d0eab59SJulian Elischer return (0); 243655929bfSJulian Elischer /* 244ed7509acSJulian Elischer * In the phase 2 case, need to prepend an mbuf for the llc header. 245655929bfSJulian Elischer * Since we must preserve the value of m, which is passed to us by 246655929bfSJulian Elischer * value, we m_copy() the first mbuf, and use it for our llc header. 247655929bfSJulian Elischer */ 248655929bfSJulian Elischer if ( aa->aa_flags & AFA_PHASE2 ) { 249655929bfSJulian Elischer struct llc llc; 250655929bfSJulian Elischer 251655929bfSJulian Elischer M_PREPEND(m, sizeof(struct llc), M_WAIT); 252655929bfSJulian Elischer len += sizeof(struct llc); 253655929bfSJulian Elischer llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 254655929bfSJulian Elischer llc.llc_control = LLC_UI; 255655929bfSJulian Elischer bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); 256655929bfSJulian Elischer llc.llc_snap_ether_type = htons( ETHERTYPE_AT ); 257655929bfSJulian Elischer bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); 25834bed8b0SDavid Greenman type = htons(m->m_pkthdr.len); 25984dd0fd0SJulian Elischer hlen = sizeof(struct llc) + ETHER_HDR_LEN; 260655929bfSJulian Elischer } else { 26134bed8b0SDavid Greenman type = htons(ETHERTYPE_AT); 262655929bfSJulian Elischer } 263655929bfSJulian Elischer break; 264ed7509acSJulian Elischer } 265655929bfSJulian Elischer #endif NETATALK 266df8bae1dSRodney W. Grimes #ifdef NS 267df8bae1dSRodney W. Grimes case AF_NS: 26888e038feSJordan K. Hubbard switch(ns_nettype){ 26988e038feSJordan K. Hubbard default: 27088e038feSJordan K. Hubbard case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ 27188e038feSJordan K. Hubbard type = 0x8137; 27288e038feSJordan K. Hubbard break; 27388e038feSJordan K. Hubbard case 0x0: /* Novell 802.3 */ 27488e038feSJordan K. Hubbard type = htons( m->m_pkthdr.len); 27588e038feSJordan K. Hubbard break; 27688e038feSJordan K. Hubbard case 0xe0e0: /* Novell 802.2 and Token-Ring */ 27788e038feSJordan K. Hubbard M_PREPEND(m, 3, M_WAIT); 27888e038feSJordan K. Hubbard type = htons( m->m_pkthdr.len); 27988e038feSJordan K. Hubbard cp = mtod(m, u_char *); 28088e038feSJordan K. Hubbard *cp++ = 0xE0; 28188e038feSJordan K. Hubbard *cp++ = 0xE0; 28288e038feSJordan K. Hubbard *cp++ = 0x03; 28388e038feSJordan K. Hubbard break; 28488e038feSJordan K. Hubbard } 285df8bae1dSRodney W. Grimes bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 286df8bae1dSRodney W. Grimes (caddr_t)edst, sizeof (edst)); 2874c8e8c05SJulian Elischer /* 2884c8e8c05SJulian Elischer * XXX if ns_thishost is the same as the node's ethernet 2894c8e8c05SJulian Elischer * address then just the default code will catch this anyhow. 2904c8e8c05SJulian Elischer * So I'm not sure if this next clause should be here at all? 2914c8e8c05SJulian Elischer * [JRE] 2924c8e8c05SJulian Elischer */ 29388e038feSJordan K. Hubbard if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))){ 29488e038feSJordan K. Hubbard m->m_pkthdr.rcvif = ifp; 29588e038feSJordan K. Hubbard schednetisr(NETISR_NS); 29688e038feSJordan K. Hubbard inq = &nsintrq; 29788e038feSJordan K. Hubbard s = splimp(); 29888e038feSJordan K. Hubbard if (IF_QFULL(inq)) { 29988e038feSJordan K. Hubbard IF_DROP(inq); 30088e038feSJordan K. Hubbard m_freem(m); 30188e038feSJordan K. Hubbard } else 30288e038feSJordan K. Hubbard IF_ENQUEUE(inq, m); 30388e038feSJordan K. Hubbard splx(s); 30488e038feSJordan K. Hubbard return (error); 30588e038feSJordan K. Hubbard } 30688e038feSJordan K. Hubbard if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof(edst))){ 3074c8e8c05SJulian Elischer m->m_flags |= M_BCAST; 30888e038feSJordan K. Hubbard } 309df8bae1dSRodney W. Grimes break; 31088e038feSJordan K. Hubbard #endif /* NS */ 311df8bae1dSRodney W. Grimes 312114ae644SMike Smith case pseudo_AF_HDRCMPLT: 313114ae644SMike Smith hdrcmplt = 1; 314114ae644SMike Smith eh = (struct ether_header *)dst->sa_data; 315114ae644SMike Smith (void)memcpy(esrc, eh->ether_shost, sizeof (esrc)); 316114ae644SMike Smith /* FALLTHROUGH */ 317114ae644SMike Smith 318df8bae1dSRodney W. Grimes case AF_UNSPEC: 3199d3f194dSJulian Elischer loop_copy = -1; /* if this is for us, don't do it */ 320df8bae1dSRodney W. Grimes eh = (struct ether_header *)dst->sa_data; 32194a5d9b6SDavid Greenman (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); 322df8bae1dSRodney W. Grimes type = eh->ether_type; 323df8bae1dSRodney W. Grimes break; 324df8bae1dSRodney W. Grimes 325df8bae1dSRodney W. Grimes default: 326df8bae1dSRodney W. Grimes printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 327df8bae1dSRodney W. Grimes dst->sa_family); 328df8bae1dSRodney W. Grimes senderr(EAFNOSUPPORT); 329df8bae1dSRodney W. Grimes } 330df8bae1dSRodney W. Grimes 331df8bae1dSRodney W. Grimes /* 332df8bae1dSRodney W. Grimes * Add local net header. If no space in first mbuf, 333df8bae1dSRodney W. Grimes * allocate another. 334df8bae1dSRodney W. Grimes */ 335df8bae1dSRodney W. Grimes M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); 336df8bae1dSRodney W. Grimes if (m == 0) 337df8bae1dSRodney W. Grimes senderr(ENOBUFS); 338df8bae1dSRodney W. Grimes eh = mtod(m, struct ether_header *); 33994a5d9b6SDavid Greenman (void)memcpy(&eh->ether_type, &type, 340df8bae1dSRodney W. Grimes sizeof(eh->ether_type)); 34194a5d9b6SDavid Greenman (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); 342114ae644SMike Smith if (hdrcmplt) 343114ae644SMike Smith (void)memcpy(eh->ether_shost, esrc, 344114ae644SMike Smith sizeof(eh->ether_shost)); 345114ae644SMike Smith else 34694a5d9b6SDavid Greenman (void)memcpy(eh->ether_shost, ac->ac_enaddr, 347df8bae1dSRodney W. Grimes sizeof(eh->ether_shost)); 348ed7509acSJulian Elischer 349ed7509acSJulian Elischer /* 350ed7509acSJulian Elischer * If a simplex interface, and the packet is being sent to our 351ed7509acSJulian Elischer * Ethernet address or a broadcast address, loopback a copy. 352ed7509acSJulian Elischer * XXX To make a simplex device behave exactly like a duplex 353ed7509acSJulian Elischer * device, we should copy in the case of sending to our own 354ed7509acSJulian Elischer * ethernet address (thus letting the original actually appear 355ed7509acSJulian Elischer * on the wire). However, we don't do that here for security 356ed7509acSJulian Elischer * reasons and compatibility with the original behavior. 357ed7509acSJulian Elischer */ 3584c8e8c05SJulian Elischer if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 3599d3f194dSJulian Elischer if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 360ed7509acSJulian Elischer struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 361ed7509acSJulian Elischer 36284dd0fd0SJulian Elischer (void) if_simloop(ifp, n, dst, hlen); 363ed7509acSJulian Elischer } else if (bcmp(eh->ether_dhost, 364ed7509acSJulian Elischer eh->ether_shost, ETHER_ADDR_LEN) == 0) { 36584dd0fd0SJulian Elischer (void) if_simloop(ifp, m, dst, hlen); 366ed7509acSJulian Elischer return (0); /* XXX */ 367ed7509acSJulian Elischer } 368ed7509acSJulian Elischer } 3692e2de7f2SArchie Cobbs 370fb5fbe46SLuigi Rizzo #ifdef BRIDGE 371fb5fbe46SLuigi Rizzo if (do_bridge) { 3722e2de7f2SArchie Cobbs struct ether_header hdr; 3731db59ce6SEivind Eklund 374fb5fbe46SLuigi Rizzo m->m_pkthdr.rcvif = NULL; 3752e2de7f2SArchie Cobbs bcopy(mtod(m, struct ether_header *), &hdr, ETHER_HDR_LEN); 3762e2de7f2SArchie Cobbs m_adj(m, ETHER_HDR_LEN); 3772e2de7f2SArchie Cobbs ifp = bridge_dst_lookup(&hdr); 3782e2de7f2SArchie Cobbs bdg_forward(&m, &hdr, ifp); 3792e2de7f2SArchie Cobbs if (m != NULL) 3802e2de7f2SArchie Cobbs m_freem(m); 3811db59ce6SEivind Eklund return (0); 382fb5fbe46SLuigi Rizzo } 383fb5fbe46SLuigi Rizzo #endif 3842e2de7f2SArchie Cobbs 385df8bae1dSRodney W. Grimes s = splimp(); 386df8bae1dSRodney W. Grimes /* 387df8bae1dSRodney W. Grimes * Queue message on interface, and start output if interface 388df8bae1dSRodney W. Grimes * not yet active. 389df8bae1dSRodney W. Grimes */ 390df8bae1dSRodney W. Grimes if (IF_QFULL(&ifp->if_snd)) { 391df8bae1dSRodney W. Grimes IF_DROP(&ifp->if_snd); 392df8bae1dSRodney W. Grimes splx(s); 393df8bae1dSRodney W. Grimes senderr(ENOBUFS); 394df8bae1dSRodney W. Grimes } 395df8bae1dSRodney W. Grimes IF_ENQUEUE(&ifp->if_snd, m); 396df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_OACTIVE) == 0) 397df8bae1dSRodney W. Grimes (*ifp->if_start)(ifp); 398df8bae1dSRodney W. Grimes splx(s); 399df8bae1dSRodney W. Grimes ifp->if_obytes += len + sizeof (struct ether_header); 400df8bae1dSRodney W. Grimes if (m->m_flags & M_MCAST) 401df8bae1dSRodney W. Grimes ifp->if_omcasts++; 402df8bae1dSRodney W. Grimes return (error); 403df8bae1dSRodney W. Grimes 404df8bae1dSRodney W. Grimes bad: 405df8bae1dSRodney W. Grimes if (m) 406df8bae1dSRodney W. Grimes m_freem(m); 407df8bae1dSRodney W. Grimes return (error); 408df8bae1dSRodney W. Grimes } 409df8bae1dSRodney W. Grimes 410df8bae1dSRodney W. Grimes /* 411df8bae1dSRodney W. Grimes * Process a received Ethernet packet; 412df8bae1dSRodney W. Grimes * the packet is in the mbuf chain m without 413df8bae1dSRodney W. Grimes * the ether header, which is provided separately. 414df8bae1dSRodney W. Grimes */ 415df8bae1dSRodney W. Grimes void 416df8bae1dSRodney W. Grimes ether_input(ifp, eh, m) 417df8bae1dSRodney W. Grimes struct ifnet *ifp; 418df8bae1dSRodney W. Grimes register struct ether_header *eh; 419df8bae1dSRodney W. Grimes struct mbuf *m; 420df8bae1dSRodney W. Grimes { 421df8bae1dSRodney W. Grimes register struct ifqueue *inq; 4224a11ca4eSPoul-Henning Kamp u_short ether_type; 423df8bae1dSRodney W. Grimes int s; 424242c5536SPeter Wemm #if defined(NETATALK) 425c23670e2SGary Palmer register struct llc *l; 426c23670e2SGary Palmer #endif 427df8bae1dSRodney W. Grimes 4282e2de7f2SArchie Cobbs /* Check for a BPF tap */ 4292e2de7f2SArchie Cobbs if (ifp->if_bpf != NULL) { 4302e2de7f2SArchie Cobbs struct m_hdr mh; 4312e2de7f2SArchie Cobbs 4322e2de7f2SArchie Cobbs /* This kludge is OK; BPF treats the "mbuf" as read-only */ 4332e2de7f2SArchie Cobbs mh.mh_next = m; 4342e2de7f2SArchie Cobbs mh.mh_data = (char *)eh; 4352e2de7f2SArchie Cobbs mh.mh_len = ETHER_HDR_LEN; 4362e2de7f2SArchie Cobbs bpf_mtap(ifp, (struct mbuf *)&mh); 4372e2de7f2SArchie Cobbs } 4382e2de7f2SArchie Cobbs 4392e2de7f2SArchie Cobbs #ifdef BRIDGE 4402e2de7f2SArchie Cobbs /* Check for bridging mode */ 4412e2de7f2SArchie Cobbs if (do_bridge) { 4422e2de7f2SArchie Cobbs struct ifnet *bif; 4432e2de7f2SArchie Cobbs 4442e2de7f2SArchie Cobbs /* Check with bridging code */ 4452e2de7f2SArchie Cobbs if ((bif = bridge_in(ifp, eh)) == BDG_DROP) { 4462e2de7f2SArchie Cobbs m_freem(m); 4472e2de7f2SArchie Cobbs return; 4482e2de7f2SArchie Cobbs } 4492e2de7f2SArchie Cobbs if (bif != BDG_LOCAL) 4502e2de7f2SArchie Cobbs bdg_forward(&m, eh, bif); /* needs forwarding */ 4512e2de7f2SArchie Cobbs if (bif == BDG_LOCAL 4522e2de7f2SArchie Cobbs || bif == BDG_BCAST 4532e2de7f2SArchie Cobbs || bif == BDG_MCAST) 4542e2de7f2SArchie Cobbs goto recvLocal; /* receive locally */ 4552e2de7f2SArchie Cobbs 4562e2de7f2SArchie Cobbs /* If not local and not multicast, just drop it */ 4572e2de7f2SArchie Cobbs if (m != NULL) 4582e2de7f2SArchie Cobbs m_freem(m); 4592e2de7f2SArchie Cobbs return; 4602e2de7f2SArchie Cobbs } 4612e2de7f2SArchie Cobbs #endif 4622e2de7f2SArchie Cobbs 4632e2de7f2SArchie Cobbs /* Discard packet if upper layers shouldn't see it. This should 4642e2de7f2SArchie Cobbs only happen when the interface is in promiscuous mode. */ 4652e2de7f2SArchie Cobbs if ((ifp->if_flags & IFF_PROMISC) != 0 4662e2de7f2SArchie Cobbs && (eh->ether_dhost[0] & 1) == 0 4672e2de7f2SArchie Cobbs && bcmp(eh->ether_dhost, 4682e2de7f2SArchie Cobbs IFP2AC(ifp)->ac_enaddr, ETHER_ADDR_LEN) != 0) { 4692e2de7f2SArchie Cobbs m_freem(m); 4702e2de7f2SArchie Cobbs return; 4712e2de7f2SArchie Cobbs } 4722e2de7f2SArchie Cobbs 4732e2de7f2SArchie Cobbs #ifdef BRIDGE 4742e2de7f2SArchie Cobbs recvLocal: 4752e2de7f2SArchie Cobbs #endif 4762e2de7f2SArchie Cobbs /* Discard packet if interface is not up */ 477df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) { 478df8bae1dSRodney W. Grimes m_freem(m); 479df8bae1dSRodney W. Grimes return; 480df8bae1dSRodney W. Grimes } 481df8bae1dSRodney W. Grimes ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); 4822cc2df49SGarrett Wollman if (eh->ether_dhost[0] & 1) { 483df8bae1dSRodney W. Grimes if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 484df8bae1dSRodney W. Grimes sizeof(etherbroadcastaddr)) == 0) 485df8bae1dSRodney W. Grimes m->m_flags |= M_BCAST; 4862cc2df49SGarrett Wollman else 487df8bae1dSRodney W. Grimes m->m_flags |= M_MCAST; 4882cc2df49SGarrett Wollman } 489df8bae1dSRodney W. Grimes if (m->m_flags & (M_BCAST|M_MCAST)) 490df8bae1dSRodney W. Grimes ifp->if_imcasts++; 491df8bae1dSRodney W. Grimes 492307d80beSDavid Greenman ether_type = ntohs(eh->ether_type); 493307d80beSDavid Greenman 4944cf49a43SJulian Elischer #ifdef NETGRAPH 4954cf49a43SJulian Elischer { 4964cf49a43SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 4974cf49a43SJulian Elischer if (AC2NG(ac) && (AC2NG(ac)->flags & NGEF_DIVERT)) { 4984cf49a43SJulian Elischer ngether_send(ac, eh, m); 4994cf49a43SJulian Elischer return; 5004cf49a43SJulian Elischer } 5014cf49a43SJulian Elischer } 5024cf49a43SJulian Elischer #endif /* NETGRAPH */ 5034cf49a43SJulian Elischer 5042cc2df49SGarrett Wollman #if NVLAN > 0 5052cc2df49SGarrett Wollman if (ether_type == vlan_proto) { 5062cc2df49SGarrett Wollman if (vlan_input(eh, m) < 0) 5072cc2df49SGarrett Wollman ifp->if_data.ifi_noproto++; 5082cc2df49SGarrett Wollman return; 5092cc2df49SGarrett Wollman } 5102cc2df49SGarrett Wollman #endif /* NVLAN > 0 */ 5112cc2df49SGarrett Wollman 512307d80beSDavid Greenman switch (ether_type) { 513df8bae1dSRodney W. Grimes #ifdef INET 514df8bae1dSRodney W. Grimes case ETHERTYPE_IP: 5151f91d8c5SDavid Greenman if (ipflow_fastforward(m)) 5161f91d8c5SDavid Greenman return; 517df8bae1dSRodney W. Grimes schednetisr(NETISR_IP); 518df8bae1dSRodney W. Grimes inq = &ipintrq; 519df8bae1dSRodney W. Grimes break; 520df8bae1dSRodney W. Grimes 521df8bae1dSRodney W. Grimes case ETHERTYPE_ARP: 522df8bae1dSRodney W. Grimes schednetisr(NETISR_ARP); 523df8bae1dSRodney W. Grimes inq = &arpintrq; 524df8bae1dSRodney W. Grimes break; 525df8bae1dSRodney W. Grimes #endif 526cc6a66f2SJulian Elischer #ifdef IPX 527cc6a66f2SJulian Elischer case ETHERTYPE_IPX: 5284f93599fSBoris Popov if (ef_inputp && ef_inputp(ifp, eh, m) == 0) 5294f93599fSBoris Popov return; 530cc6a66f2SJulian Elischer schednetisr(NETISR_IPX); 531cc6a66f2SJulian Elischer inq = &ipxintrq; 532cc6a66f2SJulian Elischer break; 533cc6a66f2SJulian Elischer #endif 53482cd038dSYoshinobu Inoue #ifdef INET6 53582cd038dSYoshinobu Inoue case ETHERTYPE_IPV6: 53682cd038dSYoshinobu Inoue schednetisr(NETISR_IPV6); 53782cd038dSYoshinobu Inoue inq = &ip6intrq; 53882cd038dSYoshinobu Inoue break; 53982cd038dSYoshinobu Inoue #endif 540df8bae1dSRodney W. Grimes #ifdef NS 54188e038feSJordan K. Hubbard case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ 542df8bae1dSRodney W. Grimes schednetisr(NETISR_NS); 543df8bae1dSRodney W. Grimes inq = &nsintrq; 544df8bae1dSRodney W. Grimes break; 54588e038feSJordan K. Hubbard 54688e038feSJordan K. Hubbard #endif /* NS */ 547655929bfSJulian Elischer #ifdef NETATALK 548655929bfSJulian Elischer case ETHERTYPE_AT: 549655929bfSJulian Elischer schednetisr(NETISR_ATALK); 550655929bfSJulian Elischer inq = &atintrq1; 551655929bfSJulian Elischer break; 552655929bfSJulian Elischer case ETHERTYPE_AARP: 553655929bfSJulian Elischer /* probably this should be done with a NETISR as well */ 5544c8e8c05SJulian Elischer aarpinput(IFP2AC(ifp), m); /* XXX */ 555655929bfSJulian Elischer return; 556655929bfSJulian Elischer #endif NETATALK 557df8bae1dSRodney W. Grimes default: 5584f93599fSBoris Popov #ifdef IPX 5594f93599fSBoris Popov if (ef_inputp && ef_inputp(ifp, eh, m) == 0) 5604f93599fSBoris Popov return; 5614f93599fSBoris Popov #endif /* IPX */ 56288e038feSJordan K. Hubbard #ifdef NS 56388e038feSJordan K. Hubbard checksum = mtod(m, ushort *); 56488e038feSJordan K. Hubbard /* Novell 802.3 */ 56588e038feSJordan K. Hubbard if ((ether_type <= ETHERMTU) && 56688e038feSJordan K. Hubbard ((*checksum == 0xffff) || (*checksum == 0xE0E0))){ 56788e038feSJordan K. Hubbard if(*checksum == 0xE0E0) { 56888e038feSJordan K. Hubbard m->m_pkthdr.len -= 3; 56988e038feSJordan K. Hubbard m->m_len -= 3; 57088e038feSJordan K. Hubbard m->m_data += 3; 57188e038feSJordan K. Hubbard } 57288e038feSJordan K. Hubbard schednetisr(NETISR_NS); 57388e038feSJordan K. Hubbard inq = &nsintrq; 57488e038feSJordan K. Hubbard break; 57588e038feSJordan K. Hubbard } 57688e038feSJordan K. Hubbard #endif /* NS */ 577242c5536SPeter Wemm #if defined(NETATALK) 578307d80beSDavid Greenman if (ether_type > ETHERMTU) 579df8bae1dSRodney W. Grimes goto dropanyway; 580df8bae1dSRodney W. Grimes l = mtod(m, struct llc *); 581df8bae1dSRodney W. Grimes switch (l->llc_dsap) { 582655929bfSJulian Elischer case LLC_SNAP_LSAP: 583655929bfSJulian Elischer switch (l->llc_control) { 584655929bfSJulian Elischer case LLC_UI: 585655929bfSJulian Elischer if (l->llc_ssap != LLC_SNAP_LSAP) 586655929bfSJulian Elischer goto dropanyway; 587655929bfSJulian Elischer 588655929bfSJulian Elischer if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, 589655929bfSJulian Elischer sizeof(at_org_code)) == 0 && 590655929bfSJulian Elischer ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { 591655929bfSJulian Elischer inq = &atintrq2; 592655929bfSJulian Elischer m_adj( m, sizeof( struct llc )); 593655929bfSJulian Elischer schednetisr(NETISR_ATALK); 594655929bfSJulian Elischer break; 595655929bfSJulian Elischer } 596655929bfSJulian Elischer 597655929bfSJulian Elischer if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, 598655929bfSJulian Elischer sizeof(aarp_org_code)) == 0 && 599655929bfSJulian Elischer ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { 600655929bfSJulian Elischer m_adj( m, sizeof( struct llc )); 6014c8e8c05SJulian Elischer aarpinput(IFP2AC(ifp), m); /* XXX */ 602655929bfSJulian Elischer return; 603655929bfSJulian Elischer } 604655929bfSJulian Elischer 605655929bfSJulian Elischer default: 606655929bfSJulian Elischer goto dropanyway; 607655929bfSJulian Elischer } 608655929bfSJulian Elischer break; 609df8bae1dSRodney W. Grimes dropanyway: 610df8bae1dSRodney W. Grimes default: 6114cf49a43SJulian Elischer #ifdef NETGRAPH 6124cf49a43SJulian Elischer ngether_send(IFP2AC(ifp), eh, m); 6134cf49a43SJulian Elischer #else /* NETGRAPH */ 614df8bae1dSRodney W. Grimes m_freem(m); 6154cf49a43SJulian Elischer #endif /* NETGRAPH */ 616df8bae1dSRodney W. Grimes return; 617df8bae1dSRodney W. Grimes } 618242c5536SPeter Wemm #else /* NETATALK */ 6194cf49a43SJulian Elischer #ifdef NETGRAPH 6204cf49a43SJulian Elischer ngether_send(IFP2AC(ifp), eh, m); 6214cf49a43SJulian Elischer #else /* NETGRAPH */ 622df8bae1dSRodney W. Grimes m_freem(m); 6234cf49a43SJulian Elischer #endif /* NETGRAPH */ 624df8bae1dSRodney W. Grimes return; 625242c5536SPeter Wemm #endif /* NETATALK */ 626df8bae1dSRodney W. Grimes } 627df8bae1dSRodney W. Grimes 628df8bae1dSRodney W. Grimes s = splimp(); 629df8bae1dSRodney W. Grimes if (IF_QFULL(inq)) { 630df8bae1dSRodney W. Grimes IF_DROP(inq); 631df8bae1dSRodney W. Grimes m_freem(m); 632df8bae1dSRodney W. Grimes } else 633df8bae1dSRodney W. Grimes IF_ENQUEUE(inq, m); 634df8bae1dSRodney W. Grimes splx(s); 635df8bae1dSRodney W. Grimes } 636df8bae1dSRodney W. Grimes 637df8bae1dSRodney W. Grimes /* 638df8bae1dSRodney W. Grimes * Perform common duties while attaching to interface list 639df8bae1dSRodney W. Grimes */ 640df8bae1dSRodney W. Grimes void 641df8bae1dSRodney W. Grimes ether_ifattach(ifp) 642df8bae1dSRodney W. Grimes register struct ifnet *ifp; 643df8bae1dSRodney W. Grimes { 644df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 645df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl; 646df8bae1dSRodney W. Grimes 647df8bae1dSRodney W. Grimes ifp->if_type = IFT_ETHER; 648df8bae1dSRodney W. Grimes ifp->if_addrlen = 6; 649df8bae1dSRodney W. Grimes ifp->if_hdrlen = 14; 650df8bae1dSRodney W. Grimes ifp->if_mtu = ETHERMTU; 6511158dfb7SGarrett Wollman ifp->if_resolvemulti = ether_resolvemulti; 652a330e1f1SGary Palmer if (ifp->if_baudrate == 0) 653a330e1f1SGary Palmer ifp->if_baudrate = 10000000; 65459562606SGarrett Wollman ifa = ifnet_addrs[ifp->if_index - 1]; 65559562606SGarrett Wollman if (ifa == 0) { 65659562606SGarrett Wollman printf("ether_ifattach: no lladdr!\n"); 65759562606SGarrett Wollman return; 65859562606SGarrett Wollman } 65959562606SGarrett Wollman sdl = (struct sockaddr_dl *)ifa->ifa_addr; 660df8bae1dSRodney W. Grimes sdl->sdl_type = IFT_ETHER; 661df8bae1dSRodney W. Grimes sdl->sdl_alen = ifp->if_addrlen; 6624c8e8c05SJulian Elischer bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 6634c8e8c05SJulian Elischer #ifdef NETGRAPH 6644c8e8c05SJulian Elischer ngether_init(ifp); 6654c8e8c05SJulian Elischer #endif /* NETGRAPH */ 66682cd038dSYoshinobu Inoue #ifdef INET6 66782cd038dSYoshinobu Inoue in6_ifattach_getifid(ifp); 66882cd038dSYoshinobu Inoue #endif 669df8bae1dSRodney W. Grimes } 670df8bae1dSRodney W. Grimes 671ce02431fSDoug Rabson SYSCTL_DECL(_net_link); 672602d513cSGarrett Wollman SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); 67330106f6aSPoul-Henning Kamp 674fb583156SDavid Greenman int 675c5a1016bSBruce Evans ether_ioctl(ifp, command, data) 676c5a1016bSBruce Evans struct ifnet *ifp; 677c5a1016bSBruce Evans int command; 678c5a1016bSBruce Evans caddr_t data; 67930106f6aSPoul-Henning Kamp { 68030106f6aSPoul-Henning Kamp struct ifaddr *ifa = (struct ifaddr *) data; 68130106f6aSPoul-Henning Kamp struct ifreq *ifr = (struct ifreq *) data; 682fb583156SDavid Greenman int error = 0; 68330106f6aSPoul-Henning Kamp 68430106f6aSPoul-Henning Kamp switch (command) { 68530106f6aSPoul-Henning Kamp case SIOCSIFADDR: 68630106f6aSPoul-Henning Kamp ifp->if_flags |= IFF_UP; 68730106f6aSPoul-Henning Kamp 68830106f6aSPoul-Henning Kamp switch (ifa->ifa_addr->sa_family) { 68930106f6aSPoul-Henning Kamp #ifdef INET 69030106f6aSPoul-Henning Kamp case AF_INET: 69130106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); /* before arpwhohas */ 6924c8e8c05SJulian Elischer arp_ifinit(IFP2AC(ifp), ifa); 69330106f6aSPoul-Henning Kamp break; 69430106f6aSPoul-Henning Kamp #endif 69530106f6aSPoul-Henning Kamp #ifdef IPX 69630106f6aSPoul-Henning Kamp /* 69730106f6aSPoul-Henning Kamp * XXX - This code is probably wrong 69830106f6aSPoul-Henning Kamp */ 69930106f6aSPoul-Henning Kamp case AF_IPX: 70030106f6aSPoul-Henning Kamp { 70130106f6aSPoul-Henning Kamp register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 7024c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 70330106f6aSPoul-Henning Kamp 70430106f6aSPoul-Henning Kamp if (ipx_nullhost(*ina)) 70530106f6aSPoul-Henning Kamp ina->x_host = 70686101139SPoul-Henning Kamp *(union ipx_host *) 70786101139SPoul-Henning Kamp ac->ac_enaddr; 70830106f6aSPoul-Henning Kamp else { 70930106f6aSPoul-Henning Kamp bcopy((caddr_t) ina->x_host.c_host, 71086101139SPoul-Henning Kamp (caddr_t) ac->ac_enaddr, 71186101139SPoul-Henning Kamp sizeof(ac->ac_enaddr)); 71230106f6aSPoul-Henning Kamp } 71330106f6aSPoul-Henning Kamp 71430106f6aSPoul-Henning Kamp /* 71530106f6aSPoul-Henning Kamp * Set new address 71630106f6aSPoul-Henning Kamp */ 71730106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 71830106f6aSPoul-Henning Kamp break; 71930106f6aSPoul-Henning Kamp } 72030106f6aSPoul-Henning Kamp #endif 72130106f6aSPoul-Henning Kamp #ifdef NS 72230106f6aSPoul-Henning Kamp /* 72330106f6aSPoul-Henning Kamp * XXX - This code is probably wrong 72430106f6aSPoul-Henning Kamp */ 72530106f6aSPoul-Henning Kamp case AF_NS: 72630106f6aSPoul-Henning Kamp { 72730106f6aSPoul-Henning Kamp register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 7284c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 72930106f6aSPoul-Henning Kamp 73030106f6aSPoul-Henning Kamp if (ns_nullhost(*ina)) 73130106f6aSPoul-Henning Kamp ina->x_host = 73286101139SPoul-Henning Kamp *(union ns_host *) (ac->ac_enaddr); 73330106f6aSPoul-Henning Kamp else { 73430106f6aSPoul-Henning Kamp bcopy((caddr_t) ina->x_host.c_host, 73586101139SPoul-Henning Kamp (caddr_t) ac->ac_enaddr, 73686101139SPoul-Henning Kamp sizeof(ac->ac_enaddr)); 73730106f6aSPoul-Henning Kamp } 73830106f6aSPoul-Henning Kamp 73930106f6aSPoul-Henning Kamp /* 74030106f6aSPoul-Henning Kamp * Set new address 74130106f6aSPoul-Henning Kamp */ 74230106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 74330106f6aSPoul-Henning Kamp break; 74430106f6aSPoul-Henning Kamp } 74530106f6aSPoul-Henning Kamp #endif 74630106f6aSPoul-Henning Kamp default: 74730106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 74830106f6aSPoul-Henning Kamp break; 74930106f6aSPoul-Henning Kamp } 75030106f6aSPoul-Henning Kamp break; 75130106f6aSPoul-Henning Kamp 75230106f6aSPoul-Henning Kamp case SIOCGIFADDR: 75330106f6aSPoul-Henning Kamp { 75430106f6aSPoul-Henning Kamp struct sockaddr *sa; 75530106f6aSPoul-Henning Kamp 75630106f6aSPoul-Henning Kamp sa = (struct sockaddr *) & ifr->ifr_data; 7574c8e8c05SJulian Elischer bcopy(IFP2AC(ifp)->ac_enaddr, 75830106f6aSPoul-Henning Kamp (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 75930106f6aSPoul-Henning Kamp } 76030106f6aSPoul-Henning Kamp break; 761fb583156SDavid Greenman 762fb583156SDavid Greenman case SIOCSIFMTU: 763fb583156SDavid Greenman /* 764fb583156SDavid Greenman * Set the interface MTU. 765fb583156SDavid Greenman */ 766fb583156SDavid Greenman if (ifr->ifr_mtu > ETHERMTU) { 767fb583156SDavid Greenman error = EINVAL; 768fb583156SDavid Greenman } else { 769fb583156SDavid Greenman ifp->if_mtu = ifr->ifr_mtu; 77030106f6aSPoul-Henning Kamp } 771fb583156SDavid Greenman break; 772fb583156SDavid Greenman } 773fb583156SDavid Greenman return (error); 77430106f6aSPoul-Henning Kamp } 7751158dfb7SGarrett Wollman 7761158dfb7SGarrett Wollman int 7771158dfb7SGarrett Wollman ether_resolvemulti(ifp, llsa, sa) 7781158dfb7SGarrett Wollman struct ifnet *ifp; 7791158dfb7SGarrett Wollman struct sockaddr **llsa; 7801158dfb7SGarrett Wollman struct sockaddr *sa; 7811158dfb7SGarrett Wollman { 7821158dfb7SGarrett Wollman struct sockaddr_dl *sdl; 7831158dfb7SGarrett Wollman struct sockaddr_in *sin; 78482cd038dSYoshinobu Inoue #ifdef INET6 78582cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6; 78682cd038dSYoshinobu Inoue #endif 7871158dfb7SGarrett Wollman u_char *e_addr; 7881158dfb7SGarrett Wollman 7891158dfb7SGarrett Wollman switch(sa->sa_family) { 7901158dfb7SGarrett Wollman case AF_LINK: 7917f33a738SJulian Elischer /* 7927f33a738SJulian Elischer * No mapping needed. Just check that it's a valid MC address. 7937f33a738SJulian Elischer */ 7941158dfb7SGarrett Wollman sdl = (struct sockaddr_dl *)sa; 7951158dfb7SGarrett Wollman e_addr = LLADDR(sdl); 7961158dfb7SGarrett Wollman if ((e_addr[0] & 1) != 1) 7971158dfb7SGarrett Wollman return EADDRNOTAVAIL; 7981158dfb7SGarrett Wollman *llsa = 0; 7991158dfb7SGarrett Wollman return 0; 8001158dfb7SGarrett Wollman 8011158dfb7SGarrett Wollman #ifdef INET 8021158dfb7SGarrett Wollman case AF_INET: 8031158dfb7SGarrett Wollman sin = (struct sockaddr_in *)sa; 8041158dfb7SGarrett Wollman if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 8051158dfb7SGarrett Wollman return EADDRNOTAVAIL; 8061158dfb7SGarrett Wollman MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 8071158dfb7SGarrett Wollman M_WAITOK); 8081158dfb7SGarrett Wollman sdl->sdl_len = sizeof *sdl; 8091158dfb7SGarrett Wollman sdl->sdl_family = AF_LINK; 8101158dfb7SGarrett Wollman sdl->sdl_index = ifp->if_index; 8111158dfb7SGarrett Wollman sdl->sdl_type = IFT_ETHER; 8121158dfb7SGarrett Wollman sdl->sdl_nlen = 0; 8131158dfb7SGarrett Wollman sdl->sdl_alen = ETHER_ADDR_LEN; 8141158dfb7SGarrett Wollman sdl->sdl_slen = 0; 8151158dfb7SGarrett Wollman e_addr = LLADDR(sdl); 8161158dfb7SGarrett Wollman ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 8171158dfb7SGarrett Wollman *llsa = (struct sockaddr *)sdl; 8181158dfb7SGarrett Wollman return 0; 8191158dfb7SGarrett Wollman #endif 82082cd038dSYoshinobu Inoue #ifdef INET6 82182cd038dSYoshinobu Inoue case AF_INET6: 82282cd038dSYoshinobu Inoue sin6 = (struct sockaddr_in6 *)sa; 82382cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 82482cd038dSYoshinobu Inoue return EADDRNOTAVAIL; 82582cd038dSYoshinobu Inoue MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 82682cd038dSYoshinobu Inoue M_WAITOK); 82782cd038dSYoshinobu Inoue sdl->sdl_len = sizeof *sdl; 82882cd038dSYoshinobu Inoue sdl->sdl_family = AF_LINK; 82982cd038dSYoshinobu Inoue sdl->sdl_index = ifp->if_index; 83082cd038dSYoshinobu Inoue sdl->sdl_type = IFT_ETHER; 83182cd038dSYoshinobu Inoue sdl->sdl_nlen = 0; 83282cd038dSYoshinobu Inoue sdl->sdl_alen = ETHER_ADDR_LEN; 83382cd038dSYoshinobu Inoue sdl->sdl_slen = 0; 83482cd038dSYoshinobu Inoue e_addr = LLADDR(sdl); 83582cd038dSYoshinobu Inoue ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 83682cd038dSYoshinobu Inoue *llsa = (struct sockaddr *)sdl; 83782cd038dSYoshinobu Inoue return 0; 83882cd038dSYoshinobu Inoue #endif 8391158dfb7SGarrett Wollman 8401158dfb7SGarrett Wollman default: 8411158dfb7SGarrett Wollman /* 8421158dfb7SGarrett Wollman * Well, the text isn't quite right, but it's the name 8431158dfb7SGarrett Wollman * that counts... 8441158dfb7SGarrett Wollman */ 8451158dfb7SGarrett Wollman return EAFNOSUPPORT; 8461158dfb7SGarrett Wollman } 8471158dfb7SGarrett Wollman } 8484cf49a43SJulian Elischer 8494cf49a43SJulian Elischer #ifdef NETGRAPH 8504cf49a43SJulian Elischer 8514cf49a43SJulian Elischer /*********************************************************************** 8524cf49a43SJulian Elischer * This section contains the methods for the Netgraph interface 8534cf49a43SJulian Elischer ***********************************************************************/ 8544cf49a43SJulian Elischer /* It's Ascii-art time! 8554cf49a43SJulian Elischer * The ifnet is the first part of the arpcom which must be 8564cf49a43SJulian Elischer * the first part of the device's softc.. yuk. 8574cf49a43SJulian Elischer * 8584cf49a43SJulian Elischer * +--------------------------+-----+---------+ 8594cf49a43SJulian Elischer * | struct ifnet (*ifp) | | | 8604cf49a43SJulian Elischer * | | | | 8614cf49a43SJulian Elischer * +--------------------------+ | | 8624cf49a43SJulian Elischer * +--|[ac_ng] struct arpcom (*ac) | | 8634cf49a43SJulian Elischer * | +--------------------------------+ | 8644cf49a43SJulian Elischer * | | struct softc (*ifp->if_softc) (device) | 8654cf49a43SJulian Elischer * | +------------------------------------------+ 8664cf49a43SJulian Elischer * | ^ 8674cf49a43SJulian Elischer * AC2NG() | 8684cf49a43SJulian Elischer * | v 8694cf49a43SJulian Elischer * | +----------------------+ 8704cf49a43SJulian Elischer * | | [private] [flags] | 8714cf49a43SJulian Elischer * +------>| struct ng_node | 8724cf49a43SJulian Elischer * | [hooks] | ** we only allow one hook 8734cf49a43SJulian Elischer * +----------------------+ 8744cf49a43SJulian Elischer * ^ 8754cf49a43SJulian Elischer * | 8764cf49a43SJulian Elischer * v 8774cf49a43SJulian Elischer * +-------------+ 8784cf49a43SJulian Elischer * | [node] | 8794cf49a43SJulian Elischer * | hook | 8804cf49a43SJulian Elischer * | [private]|-- *unused* 8814cf49a43SJulian Elischer * +-------------+ 8824cf49a43SJulian Elischer */ 8834cf49a43SJulian Elischer 8844cf49a43SJulian Elischer /* 8854cf49a43SJulian Elischer * called during interface attaching 8864cf49a43SJulian Elischer */ 8874cf49a43SJulian Elischer static void 8884cf49a43SJulian Elischer ngether_init(void *ifpvoid) 8894cf49a43SJulian Elischer { 8904cf49a43SJulian Elischer struct ifnet *ifp = ifpvoid; 8914cf49a43SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 8924cf49a43SJulian Elischer static int ngether_done_init; 8934cf49a43SJulian Elischer char namebuf[32]; 8944cf49a43SJulian Elischer node_p node; 8954cf49a43SJulian Elischer 8964cf49a43SJulian Elischer /* 8974cf49a43SJulian Elischer * we have found a node, make sure our 'type' is availabe. 8984cf49a43SJulian Elischer */ 8994cf49a43SJulian Elischer if (ngether_done_init == 0) { 9004cf49a43SJulian Elischer if (ng_newtype(&typestruct)) { 9014cf49a43SJulian Elischer printf("ngether install failed\n"); 9024cf49a43SJulian Elischer return; 9034cf49a43SJulian Elischer } 9044cf49a43SJulian Elischer ngether_done_init = 1; 9054cf49a43SJulian Elischer } 9064cf49a43SJulian Elischer if (ng_make_node_common(&typestruct, &node) != 0) 9074cf49a43SJulian Elischer return; 9084cf49a43SJulian Elischer ac->ac_ng = node; 9094cf49a43SJulian Elischer node->private = ifp; 9104cf49a43SJulian Elischer sprintf(namebuf, "%s%d", ifp->if_name, ifp->if_unit); 9114cf49a43SJulian Elischer ng_name_node(AC2NG(ac), namebuf); 9124cf49a43SJulian Elischer } 9134cf49a43SJulian Elischer 9144cf49a43SJulian Elischer /* 9154cf49a43SJulian Elischer * It is not possible or allowable to create a node of this type. 9164cf49a43SJulian Elischer * If the hardware exists, it will already have created it. 9174cf49a43SJulian Elischer */ 9184cf49a43SJulian Elischer static int 9194cf49a43SJulian Elischer ngether_constructor(node_p *nodep) 9204cf49a43SJulian Elischer { 9214cf49a43SJulian Elischer return (EINVAL); 9224cf49a43SJulian Elischer } 9234cf49a43SJulian Elischer 9244cf49a43SJulian Elischer /* 9254cf49a43SJulian Elischer * Give our ok for a hook to be added... 9264cf49a43SJulian Elischer * 9274cf49a43SJulian Elischer * Allow one hook at a time (rawdata). 9284cf49a43SJulian Elischer * It can eiteh rdivert everything or only unclaimed packets. 9294cf49a43SJulian Elischer */ 9304cf49a43SJulian Elischer static int 9314cf49a43SJulian Elischer ngether_newhook(node_p node, hook_p hook, const char *name) 9324cf49a43SJulian Elischer { 9334cf49a43SJulian Elischer 9344cf49a43SJulian Elischer /* check if there is already a hook */ 9354cf49a43SJulian Elischer if (LIST_FIRST(&(node->hooks))) 9364cf49a43SJulian Elischer return(EISCONN); 9374cf49a43SJulian Elischer /* 9384cf49a43SJulian Elischer * Check for which mode hook we want. 9394cf49a43SJulian Elischer */ 9404cf49a43SJulian Elischer if (strcmp(name, NG_ETHER_HOOK_ORPHAN) != 0) { 9414cf49a43SJulian Elischer if (strcmp(name, NG_ETHER_HOOK_DIVERT) != 0) { 9424cf49a43SJulian Elischer return (EINVAL); 9434cf49a43SJulian Elischer } 9444cf49a43SJulian Elischer node->flags |= NGEF_DIVERT; 9454cf49a43SJulian Elischer } else { 9464cf49a43SJulian Elischer node->flags &= ~NGEF_DIVERT; 9474cf49a43SJulian Elischer } 9484cf49a43SJulian Elischer return (0); 9494cf49a43SJulian Elischer } 9504cf49a43SJulian Elischer 9514cf49a43SJulian Elischer /* 9524cf49a43SJulian Elischer * incoming messages. 9534cf49a43SJulian Elischer * Just respond to the generic TEXT_STATUS message 9544cf49a43SJulian Elischer */ 9554cf49a43SJulian Elischer static int 9560beebe3aSJulian Elischer ngether_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 9570beebe3aSJulian Elischer struct ng_mesg **resp, hook_p lasthook) 9584cf49a43SJulian Elischer { 9594cf49a43SJulian Elischer struct ifnet *ifp; 9604cf49a43SJulian Elischer int error = 0; 9614cf49a43SJulian Elischer 9624cf49a43SJulian Elischer ifp = node->private; 9634cf49a43SJulian Elischer switch (msg->header.typecookie) { 9644cf49a43SJulian Elischer case NGM_ETHER_COOKIE: 9654cf49a43SJulian Elischer error = EINVAL; 9664cf49a43SJulian Elischer break; 9674cf49a43SJulian Elischer case NGM_GENERIC_COOKIE: 9684cf49a43SJulian Elischer switch(msg->header.cmd) { 9694cf49a43SJulian Elischer case NGM_TEXT_STATUS: { 9704cf49a43SJulian Elischer char *arg; 9714cf49a43SJulian Elischer int pos = 0; 9724cf49a43SJulian Elischer int resplen = sizeof(struct ng_mesg) + 512; 9734cf49a43SJulian Elischer MALLOC(*resp, struct ng_mesg *, resplen, 9744cf49a43SJulian Elischer M_NETGRAPH, M_NOWAIT); 9754cf49a43SJulian Elischer if (*resp == NULL) { 9764cf49a43SJulian Elischer error = ENOMEM; 9774cf49a43SJulian Elischer break; 9784cf49a43SJulian Elischer } 9794cf49a43SJulian Elischer bzero(*resp, resplen); 9804cf49a43SJulian Elischer arg = (*resp)->data; 9814cf49a43SJulian Elischer 9824cf49a43SJulian Elischer /* 9834cf49a43SJulian Elischer * Put in the throughput information. 9844cf49a43SJulian Elischer */ 9854cf49a43SJulian Elischer pos = sprintf(arg, "%ld bytes in, %ld bytes out\n", 9864cf49a43SJulian Elischer ifp->if_ibytes, ifp->if_obytes); 9874cf49a43SJulian Elischer pos += sprintf(arg + pos, 9884cf49a43SJulian Elischer "%ld output errors\n", 9894cf49a43SJulian Elischer ifp->if_oerrors); 9904cf49a43SJulian Elischer pos += sprintf(arg + pos, 9914cf49a43SJulian Elischer "ierrors = %ld\n", 9924cf49a43SJulian Elischer ifp->if_ierrors); 9934cf49a43SJulian Elischer 9944cf49a43SJulian Elischer (*resp)->header.version = NG_VERSION; 9954cf49a43SJulian Elischer (*resp)->header.arglen = strlen(arg) + 1; 9964cf49a43SJulian Elischer (*resp)->header.token = msg->header.token; 9974cf49a43SJulian Elischer (*resp)->header.typecookie = NGM_ETHER_COOKIE; 9984cf49a43SJulian Elischer (*resp)->header.cmd = msg->header.cmd; 9994cf49a43SJulian Elischer strncpy((*resp)->header.cmdstr, "status", 10004cf49a43SJulian Elischer NG_CMDSTRLEN); 10014cf49a43SJulian Elischer } 10024cf49a43SJulian Elischer break; 10034cf49a43SJulian Elischer default: 10044cf49a43SJulian Elischer error = EINVAL; 10054cf49a43SJulian Elischer break; 10064cf49a43SJulian Elischer } 10074cf49a43SJulian Elischer break; 10084cf49a43SJulian Elischer default: 10094cf49a43SJulian Elischer error = EINVAL; 10104cf49a43SJulian Elischer break; 10114cf49a43SJulian Elischer } 10124cf49a43SJulian Elischer free(msg, M_NETGRAPH); 10134cf49a43SJulian Elischer return (error); 10144cf49a43SJulian Elischer } 10154cf49a43SJulian Elischer 10164cf49a43SJulian Elischer /* 10174cf49a43SJulian Elischer * Receive a completed ethernet packet. 10184cf49a43SJulian Elischer * Queue it for output. 10194cf49a43SJulian Elischer */ 10204cf49a43SJulian Elischer static int 10210beebe3aSJulian Elischer ngether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 10220beebe3aSJulian Elischer struct mbuf **ret_m, meta_p *ret_meta) 10234cf49a43SJulian Elischer { 10244cf49a43SJulian Elischer struct ifnet *ifp; 10254cf49a43SJulian Elischer int error = 0; 10264cf49a43SJulian Elischer int s; 10274cf49a43SJulian Elischer struct ether_header *eh; 10284cf49a43SJulian Elischer 10294cf49a43SJulian Elischer ifp = hook->node->private; 10304cf49a43SJulian Elischer 10314cf49a43SJulian Elischer if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 10324cf49a43SJulian Elischer senderr(ENETDOWN); 1033e03b02a3SJulian Elischer /* drop in the MAC address */ 1034e03b02a3SJulian Elischer eh = mtod(m, struct ether_header *); 1035e03b02a3SJulian Elischer bcopy(IFP2AC(ifp)->ac_enaddr, eh->ether_shost, 6); 10364cf49a43SJulian Elischer /* 10374cf49a43SJulian Elischer * If a simplex interface, and the packet is being sent to our 10384cf49a43SJulian Elischer * Ethernet address or a broadcast address, loopback a copy. 10394cf49a43SJulian Elischer * XXX To make a simplex device behave exactly like a duplex 10404cf49a43SJulian Elischer * device, we should copy in the case of sending to our own 10414cf49a43SJulian Elischer * ethernet address (thus letting the original actually appear 10424cf49a43SJulian Elischer * on the wire). However, we don't do that here for security 10434cf49a43SJulian Elischer * reasons and compatibility with the original behavior. 10444cf49a43SJulian Elischer */ 10454cf49a43SJulian Elischer if (ifp->if_flags & IFF_SIMPLEX) { 10464cf49a43SJulian Elischer if (m->m_flags & M_BCAST) { 10474cf49a43SJulian Elischer struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 10484cf49a43SJulian Elischer 10494cf49a43SJulian Elischer ng_queue_data(hook, n, meta); 10504cf49a43SJulian Elischer } else if (bcmp(eh->ether_dhost, 10514cf49a43SJulian Elischer eh->ether_shost, ETHER_ADDR_LEN) == 0) { 10524cf49a43SJulian Elischer ng_queue_data(hook, m, meta); 10534cf49a43SJulian Elischer return (0); /* XXX */ 10544cf49a43SJulian Elischer } 10554cf49a43SJulian Elischer } 10564cf49a43SJulian Elischer s = splimp(); 10574cf49a43SJulian Elischer /* 10584cf49a43SJulian Elischer * Queue message on interface, and start output if interface 10594cf49a43SJulian Elischer * not yet active. 10604cf49a43SJulian Elischer * XXX if we lookead at the priority in the meta data we could 10614cf49a43SJulian Elischer * queue high priority items at the head. 10624cf49a43SJulian Elischer */ 10634cf49a43SJulian Elischer if (IF_QFULL(&ifp->if_snd)) { 10644cf49a43SJulian Elischer IF_DROP(&ifp->if_snd); 10654cf49a43SJulian Elischer splx(s); 10664cf49a43SJulian Elischer senderr(ENOBUFS); 10674cf49a43SJulian Elischer } 10684cf49a43SJulian Elischer IF_ENQUEUE(&ifp->if_snd, m); 10694cf49a43SJulian Elischer if ((ifp->if_flags & IFF_OACTIVE) == 0) 10704cf49a43SJulian Elischer (*ifp->if_start)(ifp); 10714cf49a43SJulian Elischer splx(s); 10724cf49a43SJulian Elischer ifp->if_obytes += m->m_pkthdr.len; 10734cf49a43SJulian Elischer if (m->m_flags & M_MCAST) 10744cf49a43SJulian Elischer ifp->if_omcasts++; 10754cf49a43SJulian Elischer return (error); 10764cf49a43SJulian Elischer 10774cf49a43SJulian Elischer bad: 10784cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 10794cf49a43SJulian Elischer return (error); 10804cf49a43SJulian Elischer } 10814cf49a43SJulian Elischer 10824cf49a43SJulian Elischer /* 10834cf49a43SJulian Elischer * pass an mbuf out to the connected hook 1084021823c3SJulian Elischer * More complicated than just an m_prepend, as it tries to save later nodes 1085021823c3SJulian Elischer * from needing to do lots of m_pullups. 10864cf49a43SJulian Elischer */ 10874cf49a43SJulian Elischer static void 10884cf49a43SJulian Elischer ngether_send(struct arpcom *ac, struct ether_header *eh, struct mbuf *m) 10894cf49a43SJulian Elischer { 1090021823c3SJulian Elischer int room; 10914cf49a43SJulian Elischer node_p node = AC2NG(ac); 10924cf49a43SJulian Elischer struct ether_header *eh2; 10934cf49a43SJulian Elischer 10944cf49a43SJulian Elischer if (node && LIST_FIRST(&(node->hooks))) { 10954cf49a43SJulian Elischer /* 1096021823c3SJulian Elischer * Possibly the header is already on the front, 10974cf49a43SJulian Elischer */ 1098021823c3SJulian Elischer eh2 = mtod(m, struct ether_header *) - 1; 1099021823c3SJulian Elischer if ( eh == eh2) { 1100021823c3SJulian Elischer /* 1101021823c3SJulian Elischer * This is the case so just move the markers back to 1102021823c3SJulian Elischer * re-include it. We lucked out. 1103021823c3SJulian Elischer * This allows us to avoid a yucky m_pullup 1104021823c3SJulian Elischer * in later nodes if it works. 1105021823c3SJulian Elischer */ 1106021823c3SJulian Elischer m->m_len += sizeof(*eh); 1107021823c3SJulian Elischer m->m_data -= sizeof(*eh); 1108021823c3SJulian Elischer m->m_pkthdr.len += sizeof(*eh); 1109021823c3SJulian Elischer } else { 1110021823c3SJulian Elischer /* 1111021823c3SJulian Elischer * Alternatively there may be room even though 1112021823c3SJulian Elischer * it is stored somewhere else. If so, copy it in. 1113021823c3SJulian Elischer * This only safe because we KNOW that this packet has 1114021823c3SJulian Elischer * just been generated by an ethernet card, so there 1115021823c3SJulian Elischer * are no aliases to the buffer. (unlike in outgoing 1116021823c3SJulian Elischer * packets). 1117021823c3SJulian Elischer * Nearly all ethernet cards will end up producing mbufs 1118021823c3SJulian Elischer * that fall into these cases. So we are not optimising 1119021823c3SJulian Elischer * contorted cases. 1120021823c3SJulian Elischer */ 1121021823c3SJulian Elischer 1122021823c3SJulian Elischer if (m->m_flags & M_EXT) { 1123021823c3SJulian Elischer room = (mtod(m, caddr_t) - m->m_ext.ext_buf); 1124021823c3SJulian Elischer if (room > m->m_ext.ext_size) /* garbage */ 1125021823c3SJulian Elischer room = 0; /* fail immediatly */ 1126021823c3SJulian Elischer } else { 1127021823c3SJulian Elischer room = (mtod(m, caddr_t) - m->m_pktdat); 1128021823c3SJulian Elischer } 1129021823c3SJulian Elischer if (room > sizeof (*eh)) { 1130021823c3SJulian Elischer /* we have room, just copy it and adjust */ 1131021823c3SJulian Elischer m->m_len += sizeof(*eh); 1132021823c3SJulian Elischer m->m_data -= sizeof(*eh); 1133021823c3SJulian Elischer m->m_pkthdr.len += sizeof(*eh); 1134021823c3SJulian Elischer } else { 1135021823c3SJulian Elischer /* 1136021823c3SJulian Elischer * Doing anything more is likely to get more 1137021823c3SJulian Elischer * expensive than it's worth.. 1138021823c3SJulian Elischer * it's probable that everything else is in one 1139021823c3SJulian Elischer * big lump. The next node will do an m_pullup() 1140021823c3SJulian Elischer * for exactly the amount of data it needs and 1141021823c3SJulian Elischer * hopefully everything after that will not 1142ecf33d87SJulian Elischer * need one. So let's just use M_PREPEND. 1143021823c3SJulian Elischer */ 1144ecf33d87SJulian Elischer M_PREPEND(m, sizeof (*eh), M_DONTWAIT); 1145021823c3SJulian Elischer if (m == NULL) 1146021823c3SJulian Elischer return; 1147021823c3SJulian Elischer } 11482b75f795SJulian Elischer bcopy ((caddr_t)eh, mtod(m, struct ether_header *), 11492b75f795SJulian Elischer sizeof(*eh)); 1150021823c3SJulian Elischer } 11514cf49a43SJulian Elischer ng_queue_data(LIST_FIRST(&(node->hooks)), m, NULL); 11524cf49a43SJulian Elischer } else { 11534cf49a43SJulian Elischer m_freem(m); 11544cf49a43SJulian Elischer } 11554cf49a43SJulian Elischer } 1156021823c3SJulian Elischer 11574cf49a43SJulian Elischer /* 11584cf49a43SJulian Elischer * do local shutdown processing.. 11594cf49a43SJulian Elischer * This node will refuse to go away, unless the hardware says to.. 11604cf49a43SJulian Elischer * don't unref the node, or remove our name. just clear our links up. 11614cf49a43SJulian Elischer */ 11624cf49a43SJulian Elischer static int 11634cf49a43SJulian Elischer ngether_rmnode(node_p node) 11644cf49a43SJulian Elischer { 11654cf49a43SJulian Elischer ng_cutlinks(node); 11664cf49a43SJulian Elischer node->flags &= ~NG_INVALID; /* bounce back to life */ 11674cf49a43SJulian Elischer return (0); 11684cf49a43SJulian Elischer } 11694cf49a43SJulian Elischer 11704cf49a43SJulian Elischer /* already linked */ 11714cf49a43SJulian Elischer static int 11724cf49a43SJulian Elischer ngether_connect(hook_p hook) 11734cf49a43SJulian Elischer { 11744cf49a43SJulian Elischer /* be really amiable and just say "YUP that's OK by me! " */ 11754cf49a43SJulian Elischer return (0); 11764cf49a43SJulian Elischer } 11774cf49a43SJulian Elischer 11784cf49a43SJulian Elischer /* 11794cf49a43SJulian Elischer * notify on hook disconnection (destruction) 11804cf49a43SJulian Elischer * 11814cf49a43SJulian Elischer * For this type, removal of the last lins no effect. The interface can run 11824cf49a43SJulian Elischer * independently. 11834cf49a43SJulian Elischer * Since we have no per-hook information, this is rather simple. 11844cf49a43SJulian Elischer */ 11854cf49a43SJulian Elischer static int 11864cf49a43SJulian Elischer ngether_disconnect(hook_p hook) 11874cf49a43SJulian Elischer { 11884cf49a43SJulian Elischer hook->node->flags &= ~NGEF_DIVERT; 11894cf49a43SJulian Elischer return (0); 11904cf49a43SJulian Elischer } 11914cf49a43SJulian Elischer #endif /* NETGRAPH */ 11924cf49a43SJulian Elischer 11934cf49a43SJulian Elischer /********************************** END *************************************/ 1194