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" 39430df5f4SEivind Eklund #include "opt_ipx.h" 40fb5fbe46SLuigi Rizzo #include "opt_bdg.h" 414cf49a43SJulian Elischer #include "opt_netgraph.h" 42430df5f4SEivind Eklund 43df8bae1dSRodney W. Grimes #include <sys/param.h> 44df8bae1dSRodney W. Grimes #include <sys/systm.h> 45df8bae1dSRodney W. Grimes #include <sys/kernel.h> 46df8bae1dSRodney W. Grimes #include <sys/malloc.h> 47df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 48df8bae1dSRodney W. Grimes #include <sys/socket.h> 4951a53488SBruce Evans #include <sys/sockio.h> 50602d513cSGarrett Wollman #include <sys/sysctl.h> 51df8bae1dSRodney W. Grimes 52df8bae1dSRodney W. Grimes #include <net/if.h> 53df8bae1dSRodney W. Grimes #include <net/netisr.h> 54df8bae1dSRodney W. Grimes #include <net/route.h> 55df8bae1dSRodney W. Grimes #include <net/if_llc.h> 56df8bae1dSRodney W. Grimes #include <net/if_dl.h> 57df8bae1dSRodney W. Grimes #include <net/if_types.h> 58df8bae1dSRodney W. Grimes 5982cd038dSYoshinobu Inoue #if defined(INET) || defined(INET6) 60df8bae1dSRodney W. Grimes #include <netinet/in.h> 61df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 62df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 631d5e9e22SEivind Eklund #endif 6482cd038dSYoshinobu Inoue #ifdef INET6 6582cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 6682cd038dSYoshinobu Inoue #include <netinet6/in6_ifattach.h> 6782cd038dSYoshinobu Inoue #endif 68df8bae1dSRodney W. Grimes 69cc6a66f2SJulian Elischer #ifdef IPX 70cc6a66f2SJulian Elischer #include <netipx/ipx.h> 71cc6a66f2SJulian Elischer #include <netipx/ipx_if.h> 72cc6a66f2SJulian Elischer #endif 73cc6a66f2SJulian Elischer 74df8bae1dSRodney W. Grimes #ifdef NS 75df8bae1dSRodney W. Grimes #include <netns/ns.h> 76df8bae1dSRodney W. Grimes #include <netns/ns_if.h> 77d0ec898dSJordan K. Hubbard ushort ns_nettype; 7888e038feSJordan K. Hubbard int ether_outputdebug = 0; 7988e038feSJordan K. Hubbard int ether_inputdebug = 0; 80df8bae1dSRodney W. Grimes #endif 81df8bae1dSRodney W. Grimes 82df8bae1dSRodney W. Grimes #ifdef ISO 83df8bae1dSRodney W. Grimes #include <netiso/argo_debug.h> 84df8bae1dSRodney W. Grimes #include <netiso/iso.h> 85df8bae1dSRodney W. Grimes #include <netiso/iso_var.h> 86df8bae1dSRodney W. Grimes #include <netiso/iso_snpac.h> 87df8bae1dSRodney W. Grimes #endif 88df8bae1dSRodney W. Grimes 89655929bfSJulian Elischer /*#ifdef LLC 90df8bae1dSRodney W. Grimes #include <netccitt/dll.h> 91df8bae1dSRodney W. Grimes #include <netccitt/llc_var.h> 92655929bfSJulian Elischer #endif*/ 93df8bae1dSRodney W. Grimes 94df8bae1dSRodney W. Grimes #if defined(LLC) && defined(CCITT) 95df8bae1dSRodney W. Grimes extern struct ifqueue pkintrq; 96df8bae1dSRodney W. Grimes #endif 97df8bae1dSRodney W. Grimes 98655929bfSJulian Elischer #ifdef NETATALK 99655929bfSJulian Elischer #include <netatalk/at.h> 100655929bfSJulian Elischer #include <netatalk/at_var.h> 101655929bfSJulian Elischer #include <netatalk/at_extern.h> 102655929bfSJulian Elischer 103655929bfSJulian Elischer #define llc_snap_org_code llc_un.type_snap.org_code 104655929bfSJulian Elischer #define llc_snap_ether_type llc_un.type_snap.ether_type 105655929bfSJulian Elischer 106655929bfSJulian Elischer extern u_char at_org_code[3]; 107655929bfSJulian Elischer extern u_char aarp_org_code[3]; 1082cc2df49SGarrett Wollman #endif /* NETATALK */ 1092cc2df49SGarrett Wollman 110fb5fbe46SLuigi Rizzo #ifdef BRIDGE 111fb5fbe46SLuigi Rizzo #include <net/bridge.h> 112fb5fbe46SLuigi Rizzo #endif 113fb5fbe46SLuigi Rizzo 1142cc2df49SGarrett Wollman #include "vlan.h" 1152cc2df49SGarrett Wollman #if NVLAN > 0 1162cc2df49SGarrett Wollman #include <net/if_vlan_var.h> 1172cc2df49SGarrett Wollman #endif /* NVLAN > 0 */ 118655929bfSJulian Elischer 1191158dfb7SGarrett Wollman static int ether_resolvemulti __P((struct ifnet *, struct sockaddr **, 1201158dfb7SGarrett Wollman struct sockaddr *)); 121df8bae1dSRodney W. Grimes u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 1224c8e8c05SJulian Elischer #define senderr(e) do { error = (e); goto bad;} while (0) 1234c8e8c05SJulian Elischer #define IFP2AC(IFP) ((struct arpcom *)IFP) 124df8bae1dSRodney W. Grimes 1254cf49a43SJulian Elischer #ifdef NETGRAPH 1264cf49a43SJulian Elischer #include <netgraph/ng_ether.h> 1274cf49a43SJulian Elischer #include <netgraph/ng_message.h> 1284cf49a43SJulian Elischer #include <netgraph/netgraph.h> 1294cf49a43SJulian Elischer 1304cf49a43SJulian Elischer static void ngether_init(void* ignored); 1314cf49a43SJulian Elischer static void ngether_send(struct arpcom *ac, 1324cf49a43SJulian Elischer struct ether_header *eh, struct mbuf *m); 133ae5a83bcSJulian Elischer static ng_constructor_t ngether_constructor; 134ae5a83bcSJulian Elischer static ng_rcvmsg_t ngether_rcvmsg; 135ae5a83bcSJulian Elischer static ng_shutdown_t ngether_rmnode; 136ae5a83bcSJulian Elischer static ng_newhook_t ngether_newhook; 137ae5a83bcSJulian Elischer static ng_connect_t ngether_connect; 138ae5a83bcSJulian Elischer static ng_rcvdata_t ngether_rcvdata; 139ae5a83bcSJulian Elischer static ng_disconnect_t ngether_disconnect; 1404cf49a43SJulian Elischer 1414cf49a43SJulian Elischer static struct ng_type typestruct = { 1424cf49a43SJulian Elischer NG_VERSION, 1434cf49a43SJulian Elischer NG_ETHER_NODE_TYPE, 1444cf49a43SJulian Elischer NULL, 1454cf49a43SJulian Elischer ngether_constructor, 1464cf49a43SJulian Elischer ngether_rcvmsg, 1474cf49a43SJulian Elischer ngether_rmnode, 1484cf49a43SJulian Elischer ngether_newhook, 1494cf49a43SJulian Elischer NULL, 1504cf49a43SJulian Elischer ngether_connect, 1514cf49a43SJulian Elischer ngether_rcvdata, 1524cf49a43SJulian Elischer ngether_rcvdata, 1534cf49a43SJulian Elischer ngether_disconnect 1544cf49a43SJulian Elischer }; 1554cf49a43SJulian Elischer 1564cf49a43SJulian Elischer #define AC2NG(AC) ((node_p)((AC)->ac_ng)) 1574cf49a43SJulian Elischer #define NGEF_DIVERT NGF_TYPE1 /* all packets sent to netgraph */ 1584cf49a43SJulian Elischer #endif /* NETGRAPH */ 1594cf49a43SJulian Elischer 160df8bae1dSRodney W. Grimes /* 161df8bae1dSRodney W. Grimes * Ethernet output routine. 162df8bae1dSRodney W. Grimes * Encapsulate a packet of type family for the local net. 163df8bae1dSRodney W. Grimes * Use trailer local net encapsulation if enough data in first 164df8bae1dSRodney W. Grimes * packet leaves a multiple of 512 bytes of data in remainder. 165df8bae1dSRodney W. Grimes * Assumes that ifp is actually pointer to arpcom structure. 166df8bae1dSRodney W. Grimes */ 167df8bae1dSRodney W. Grimes int 168df8bae1dSRodney W. Grimes ether_output(ifp, m0, dst, rt0) 169df8bae1dSRodney W. Grimes register struct ifnet *ifp; 170df8bae1dSRodney W. Grimes struct mbuf *m0; 171df8bae1dSRodney W. Grimes struct sockaddr *dst; 172df8bae1dSRodney W. Grimes struct rtentry *rt0; 173df8bae1dSRodney W. Grimes { 174df8bae1dSRodney W. Grimes short type; 175114ae644SMike Smith int s, error = 0, hdrcmplt = 0; 176114ae644SMike Smith u_char esrc[6], edst[6]; 1774a11ca4eSPoul-Henning Kamp register struct mbuf *m = m0; 178df8bae1dSRodney W. Grimes register struct rtentry *rt; 179df8bae1dSRodney W. Grimes register struct ether_header *eh; 180ed7509acSJulian Elischer int off, len = m->m_pkthdr.len, loop_copy = 0; 18184dd0fd0SJulian Elischer int hlen; /* link layer header lenght */ 1824c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 183df8bae1dSRodney W. Grimes 184df8bae1dSRodney W. Grimes if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 185df8bae1dSRodney W. Grimes senderr(ENETDOWN); 1863bda9f9bSPoul-Henning Kamp rt = rt0; 1873bda9f9bSPoul-Henning Kamp if (rt) { 188df8bae1dSRodney W. Grimes if ((rt->rt_flags & RTF_UP) == 0) { 1893bda9f9bSPoul-Henning Kamp rt0 = rt = rtalloc1(dst, 1, 0UL); 1903bda9f9bSPoul-Henning Kamp if (rt0) 191df8bae1dSRodney W. Grimes rt->rt_refcnt--; 192df8bae1dSRodney W. Grimes else 193df8bae1dSRodney W. Grimes senderr(EHOSTUNREACH); 194df8bae1dSRodney W. Grimes } 195df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) { 196df8bae1dSRodney W. Grimes if (rt->rt_gwroute == 0) 197df8bae1dSRodney W. Grimes goto lookup; 198df8bae1dSRodney W. Grimes if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 199df8bae1dSRodney W. Grimes rtfree(rt); rt = rt0; 200995add1aSGarrett Wollman lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 201995add1aSGarrett Wollman 0UL); 202df8bae1dSRodney W. Grimes if ((rt = rt->rt_gwroute) == 0) 203df8bae1dSRodney W. Grimes senderr(EHOSTUNREACH); 204df8bae1dSRodney W. Grimes } 205df8bae1dSRodney W. Grimes } 206df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_REJECT) 207df8bae1dSRodney W. Grimes if (rt->rt_rmx.rmx_expire == 0 || 208227ee8a1SPoul-Henning Kamp time_second < rt->rt_rmx.rmx_expire) 209df8bae1dSRodney W. Grimes senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 210df8bae1dSRodney W. Grimes } 21184dd0fd0SJulian Elischer hlen = ETHER_HDR_LEN; 212df8bae1dSRodney W. Grimes switch (dst->sa_family) { 213df8bae1dSRodney W. Grimes #ifdef INET 214df8bae1dSRodney W. Grimes case AF_INET: 2155df72964SGarrett Wollman if (!arpresolve(ac, rt, m, dst, edst, rt0)) 216df8bae1dSRodney W. Grimes return (0); /* if not yet resolved */ 217df8bae1dSRodney W. Grimes off = m->m_pkthdr.len - m->m_len; 21834bed8b0SDavid Greenman type = htons(ETHERTYPE_IP); 219df8bae1dSRodney W. Grimes break; 220df8bae1dSRodney W. Grimes #endif 22182cd038dSYoshinobu Inoue #ifdef INET6 22282cd038dSYoshinobu Inoue case AF_INET6: 22382cd038dSYoshinobu Inoue if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { 22482cd038dSYoshinobu Inoue /* this must be impossible, so we bark */ 22582cd038dSYoshinobu Inoue printf("nd6_storelladdr failed\n"); 22682cd038dSYoshinobu Inoue return(0); 22782cd038dSYoshinobu Inoue } 22882cd038dSYoshinobu Inoue off = m->m_pkthdr.len - m->m_len; 22982cd038dSYoshinobu Inoue type = htons(ETHERTYPE_IPV6); 23082cd038dSYoshinobu Inoue break; 23182cd038dSYoshinobu Inoue #endif 232cc6a66f2SJulian Elischer #ifdef IPX 233cc6a66f2SJulian Elischer case AF_IPX: 23434bed8b0SDavid Greenman type = htons(ETHERTYPE_IPX); 235cc6a66f2SJulian Elischer bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 236cc6a66f2SJulian Elischer (caddr_t)edst, sizeof (edst)); 237cc6a66f2SJulian Elischer break; 238cc6a66f2SJulian Elischer #endif 239655929bfSJulian Elischer #ifdef NETATALK 240655929bfSJulian Elischer case AF_APPLETALK: 2411d0eab59SJulian Elischer { 242ed7509acSJulian Elischer struct at_ifaddr *aa; 2431d0eab59SJulian Elischer 244ed7509acSJulian Elischer if ((aa = at_ifawithnet((struct sockaddr_at *)dst)) == NULL) { 2451d0eab59SJulian Elischer goto bad; 2461d0eab59SJulian Elischer } 247ed7509acSJulian Elischer if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) 2481d0eab59SJulian Elischer return (0); 249655929bfSJulian Elischer /* 250ed7509acSJulian Elischer * In the phase 2 case, need to prepend an mbuf for the llc header. 251655929bfSJulian Elischer * Since we must preserve the value of m, which is passed to us by 252655929bfSJulian Elischer * value, we m_copy() the first mbuf, and use it for our llc header. 253655929bfSJulian Elischer */ 254655929bfSJulian Elischer if ( aa->aa_flags & AFA_PHASE2 ) { 255655929bfSJulian Elischer struct llc llc; 256655929bfSJulian Elischer 257655929bfSJulian Elischer M_PREPEND(m, sizeof(struct llc), M_WAIT); 258655929bfSJulian Elischer len += sizeof(struct llc); 259655929bfSJulian Elischer llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 260655929bfSJulian Elischer llc.llc_control = LLC_UI; 261655929bfSJulian Elischer bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); 262655929bfSJulian Elischer llc.llc_snap_ether_type = htons( ETHERTYPE_AT ); 263655929bfSJulian Elischer bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); 26434bed8b0SDavid Greenman type = htons(m->m_pkthdr.len); 26584dd0fd0SJulian Elischer hlen = sizeof(struct llc) + ETHER_HDR_LEN; 266655929bfSJulian Elischer } else { 26734bed8b0SDavid Greenman type = htons(ETHERTYPE_AT); 268655929bfSJulian Elischer } 269655929bfSJulian Elischer break; 270ed7509acSJulian Elischer } 271655929bfSJulian Elischer #endif NETATALK 272df8bae1dSRodney W. Grimes #ifdef NS 273df8bae1dSRodney W. Grimes case AF_NS: 27488e038feSJordan K. Hubbard switch(ns_nettype){ 27588e038feSJordan K. Hubbard default: 27688e038feSJordan K. Hubbard case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ 27788e038feSJordan K. Hubbard type = 0x8137; 27888e038feSJordan K. Hubbard break; 27988e038feSJordan K. Hubbard case 0x0: /* Novell 802.3 */ 28088e038feSJordan K. Hubbard type = htons( m->m_pkthdr.len); 28188e038feSJordan K. Hubbard break; 28288e038feSJordan K. Hubbard case 0xe0e0: /* Novell 802.2 and Token-Ring */ 28388e038feSJordan K. Hubbard M_PREPEND(m, 3, M_WAIT); 28488e038feSJordan K. Hubbard type = htons( m->m_pkthdr.len); 28588e038feSJordan K. Hubbard cp = mtod(m, u_char *); 28688e038feSJordan K. Hubbard *cp++ = 0xE0; 28788e038feSJordan K. Hubbard *cp++ = 0xE0; 28888e038feSJordan K. Hubbard *cp++ = 0x03; 28988e038feSJordan K. Hubbard break; 29088e038feSJordan K. Hubbard } 291df8bae1dSRodney W. Grimes bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 292df8bae1dSRodney W. Grimes (caddr_t)edst, sizeof (edst)); 2934c8e8c05SJulian Elischer /* 2944c8e8c05SJulian Elischer * XXX if ns_thishost is the same as the node's ethernet 2954c8e8c05SJulian Elischer * address then just the default code will catch this anyhow. 2964c8e8c05SJulian Elischer * So I'm not sure if this next clause should be here at all? 2974c8e8c05SJulian Elischer * [JRE] 2984c8e8c05SJulian Elischer */ 29988e038feSJordan K. Hubbard if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))){ 30088e038feSJordan K. Hubbard m->m_pkthdr.rcvif = ifp; 30188e038feSJordan K. Hubbard schednetisr(NETISR_NS); 30288e038feSJordan K. Hubbard inq = &nsintrq; 30388e038feSJordan K. Hubbard s = splimp(); 30488e038feSJordan K. Hubbard if (IF_QFULL(inq)) { 30588e038feSJordan K. Hubbard IF_DROP(inq); 30688e038feSJordan K. Hubbard m_freem(m); 30788e038feSJordan K. Hubbard } else 30888e038feSJordan K. Hubbard IF_ENQUEUE(inq, m); 30988e038feSJordan K. Hubbard splx(s); 31088e038feSJordan K. Hubbard return (error); 31188e038feSJordan K. Hubbard } 31288e038feSJordan K. Hubbard if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof(edst))){ 3134c8e8c05SJulian Elischer m->m_flags |= M_BCAST; 31488e038feSJordan K. Hubbard } 315df8bae1dSRodney W. Grimes break; 31688e038feSJordan K. Hubbard #endif /* NS */ 317df8bae1dSRodney W. Grimes #ifdef ISO 318df8bae1dSRodney W. Grimes case AF_ISO: { 319df8bae1dSRodney W. Grimes int snpalen; 320df8bae1dSRodney W. Grimes struct llc *l; 321df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl; 322df8bae1dSRodney W. Grimes 323df8bae1dSRodney W. Grimes if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) && 324df8bae1dSRodney W. Grimes sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { 325df8bae1dSRodney W. Grimes bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst)); 326df8bae1dSRodney W. Grimes } else if (error = 327df8bae1dSRodney W. Grimes iso_snparesolve(ifp, (struct sockaddr_iso *)dst, 328df8bae1dSRodney W. Grimes (char *)edst, &snpalen)) 329df8bae1dSRodney W. Grimes goto bad; /* Not Resolved */ 330df8bae1dSRodney W. Grimes /* If broadcasting on a simplex interface, loopback a copy */ 331df8bae1dSRodney W. Grimes if (*edst & 1) 332df8bae1dSRodney W. Grimes m->m_flags |= (M_BCAST|M_MCAST); 333df8bae1dSRodney W. Grimes M_PREPEND(m, 3, M_DONTWAIT); 334df8bae1dSRodney W. Grimes if (m == NULL) 335df8bae1dSRodney W. Grimes return (0); 33634bed8b0SDavid Greenman type = htons(m->m_pkthdr.len); 337df8bae1dSRodney W. Grimes l = mtod(m, struct llc *); 338df8bae1dSRodney W. Grimes l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; 339df8bae1dSRodney W. Grimes l->llc_control = LLC_UI; 340df8bae1dSRodney W. Grimes len += 3; 341df8bae1dSRodney W. Grimes IFDEBUG(D_ETHER) 342df8bae1dSRodney W. Grimes int i; 343df8bae1dSRodney W. Grimes printf("unoutput: sending pkt to: "); 344df8bae1dSRodney W. Grimes for (i=0; i<6; i++) 345df8bae1dSRodney W. Grimes printf("%x ", edst[i] & 0xff); 346df8bae1dSRodney W. Grimes printf("\n"); 347df8bae1dSRodney W. Grimes ENDDEBUG 348df8bae1dSRodney W. Grimes } break; 349df8bae1dSRodney W. Grimes #endif /* ISO */ 350df8bae1dSRodney W. Grimes #ifdef LLC 351df8bae1dSRodney W. Grimes /* case AF_NSAP: */ 352df8bae1dSRodney W. Grimes case AF_CCITT: { 353df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl = 354df8bae1dSRodney W. Grimes (struct sockaddr_dl *) rt -> rt_gateway; 355df8bae1dSRodney W. Grimes 356df8bae1dSRodney W. Grimes if (sdl && sdl->sdl_family == AF_LINK 357df8bae1dSRodney W. Grimes && sdl->sdl_alen > 0) { 358ed7509acSJulian Elischer bcopy(LLADDR(sdl), (char *)edst, sizeof(edst)); 359df8bae1dSRodney W. Grimes } else goto bad; /* Not a link interface ? Funny ... */ 360ed7509acSJulian Elischer if (*edst & 1) 361ed7509acSJulian Elischer loop_copy = 1; 36234bed8b0SDavid Greenman type = htons(m->m_pkthdr.len); 363df8bae1dSRodney W. Grimes #ifdef LLC_DEBUG 364df8bae1dSRodney W. Grimes { 365df8bae1dSRodney W. Grimes int i; 366df8bae1dSRodney W. Grimes register struct llc *l = mtod(m, struct llc *); 367df8bae1dSRodney W. Grimes 368df8bae1dSRodney W. Grimes printf("ether_output: sending LLC2 pkt to: "); 369df8bae1dSRodney W. Grimes for (i=0; i<6; i++) 370df8bae1dSRodney W. Grimes printf("%x ", edst[i] & 0xff); 371df8bae1dSRodney W. Grimes printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n", 372df8bae1dSRodney W. Grimes type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff, 373df8bae1dSRodney W. Grimes l->llc_control & 0xff); 374df8bae1dSRodney W. Grimes 375df8bae1dSRodney W. Grimes } 376df8bae1dSRodney W. Grimes #endif /* LLC_DEBUG */ 377df8bae1dSRodney W. Grimes } break; 378df8bae1dSRodney W. Grimes #endif /* LLC */ 379df8bae1dSRodney W. Grimes 380114ae644SMike Smith case pseudo_AF_HDRCMPLT: 381114ae644SMike Smith hdrcmplt = 1; 382114ae644SMike Smith eh = (struct ether_header *)dst->sa_data; 383114ae644SMike Smith (void)memcpy(esrc, eh->ether_shost, sizeof (esrc)); 384114ae644SMike Smith /* FALLTHROUGH */ 385114ae644SMike Smith 386df8bae1dSRodney W. Grimes case AF_UNSPEC: 3879d3f194dSJulian Elischer loop_copy = -1; /* if this is for us, don't do it */ 388df8bae1dSRodney W. Grimes eh = (struct ether_header *)dst->sa_data; 38994a5d9b6SDavid Greenman (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); 390df8bae1dSRodney W. Grimes type = eh->ether_type; 391df8bae1dSRodney W. Grimes break; 392df8bae1dSRodney W. Grimes 393df8bae1dSRodney W. Grimes default: 394df8bae1dSRodney W. Grimes printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 395df8bae1dSRodney W. Grimes dst->sa_family); 396df8bae1dSRodney W. Grimes senderr(EAFNOSUPPORT); 397df8bae1dSRodney W. Grimes } 398df8bae1dSRodney W. Grimes 399df8bae1dSRodney W. Grimes /* 400df8bae1dSRodney W. Grimes * Add local net header. If no space in first mbuf, 401df8bae1dSRodney W. Grimes * allocate another. 402df8bae1dSRodney W. Grimes */ 403df8bae1dSRodney W. Grimes M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); 404df8bae1dSRodney W. Grimes if (m == 0) 405df8bae1dSRodney W. Grimes senderr(ENOBUFS); 406df8bae1dSRodney W. Grimes eh = mtod(m, struct ether_header *); 40794a5d9b6SDavid Greenman (void)memcpy(&eh->ether_type, &type, 408df8bae1dSRodney W. Grimes sizeof(eh->ether_type)); 40994a5d9b6SDavid Greenman (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); 410114ae644SMike Smith if (hdrcmplt) 411114ae644SMike Smith (void)memcpy(eh->ether_shost, esrc, 412114ae644SMike Smith sizeof(eh->ether_shost)); 413114ae644SMike Smith else 41494a5d9b6SDavid Greenman (void)memcpy(eh->ether_shost, ac->ac_enaddr, 415df8bae1dSRodney W. Grimes sizeof(eh->ether_shost)); 416ed7509acSJulian Elischer 417ed7509acSJulian Elischer /* 418ed7509acSJulian Elischer * If a simplex interface, and the packet is being sent to our 419ed7509acSJulian Elischer * Ethernet address or a broadcast address, loopback a copy. 420ed7509acSJulian Elischer * XXX To make a simplex device behave exactly like a duplex 421ed7509acSJulian Elischer * device, we should copy in the case of sending to our own 422ed7509acSJulian Elischer * ethernet address (thus letting the original actually appear 423ed7509acSJulian Elischer * on the wire). However, we don't do that here for security 424ed7509acSJulian Elischer * reasons and compatibility with the original behavior. 425ed7509acSJulian Elischer */ 4264c8e8c05SJulian Elischer if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 4279d3f194dSJulian Elischer if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 428ed7509acSJulian Elischer struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 429ed7509acSJulian Elischer 43084dd0fd0SJulian Elischer (void) if_simloop(ifp, n, dst, hlen); 431ed7509acSJulian Elischer } else if (bcmp(eh->ether_dhost, 432ed7509acSJulian Elischer eh->ether_shost, ETHER_ADDR_LEN) == 0) { 43384dd0fd0SJulian Elischer (void) if_simloop(ifp, m, dst, hlen); 434ed7509acSJulian Elischer return (0); /* XXX */ 435ed7509acSJulian Elischer } 436ed7509acSJulian Elischer } 437fb5fbe46SLuigi Rizzo #ifdef BRIDGE 438fb5fbe46SLuigi Rizzo if (do_bridge) { 439fb5fbe46SLuigi Rizzo struct mbuf *m0 = m ; 4401db59ce6SEivind Eklund 441fb5fbe46SLuigi Rizzo if (m->m_pkthdr.rcvif) 442fb5fbe46SLuigi Rizzo m->m_pkthdr.rcvif = NULL ; 443fb5fbe46SLuigi Rizzo ifp = bridge_dst_lookup(m); 444fb5fbe46SLuigi Rizzo bdg_forward(&m0, ifp); 445fb5fbe46SLuigi Rizzo if (m0) 446fb5fbe46SLuigi Rizzo m_freem(m0); 4471db59ce6SEivind Eklund return (0); 448fb5fbe46SLuigi Rizzo } 449fb5fbe46SLuigi Rizzo #endif 450df8bae1dSRodney W. Grimes s = splimp(); 451df8bae1dSRodney W. Grimes /* 452df8bae1dSRodney W. Grimes * Queue message on interface, and start output if interface 453df8bae1dSRodney W. Grimes * not yet active. 454df8bae1dSRodney W. Grimes */ 455df8bae1dSRodney W. Grimes if (IF_QFULL(&ifp->if_snd)) { 456df8bae1dSRodney W. Grimes IF_DROP(&ifp->if_snd); 457df8bae1dSRodney W. Grimes splx(s); 458df8bae1dSRodney W. Grimes senderr(ENOBUFS); 459df8bae1dSRodney W. Grimes } 460df8bae1dSRodney W. Grimes IF_ENQUEUE(&ifp->if_snd, m); 461df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_OACTIVE) == 0) 462df8bae1dSRodney W. Grimes (*ifp->if_start)(ifp); 463df8bae1dSRodney W. Grimes splx(s); 464df8bae1dSRodney W. Grimes ifp->if_obytes += len + sizeof (struct ether_header); 465df8bae1dSRodney W. Grimes if (m->m_flags & M_MCAST) 466df8bae1dSRodney W. Grimes ifp->if_omcasts++; 467df8bae1dSRodney W. Grimes return (error); 468df8bae1dSRodney W. Grimes 469df8bae1dSRodney W. Grimes bad: 470df8bae1dSRodney W. Grimes if (m) 471df8bae1dSRodney W. Grimes m_freem(m); 472df8bae1dSRodney W. Grimes return (error); 473df8bae1dSRodney W. Grimes } 474df8bae1dSRodney W. Grimes 475df8bae1dSRodney W. Grimes /* 476df8bae1dSRodney W. Grimes * Process a received Ethernet packet; 477df8bae1dSRodney W. Grimes * the packet is in the mbuf chain m without 478df8bae1dSRodney W. Grimes * the ether header, which is provided separately. 479df8bae1dSRodney W. Grimes */ 480df8bae1dSRodney W. Grimes void 481df8bae1dSRodney W. Grimes ether_input(ifp, eh, m) 482df8bae1dSRodney W. Grimes struct ifnet *ifp; 483df8bae1dSRodney W. Grimes register struct ether_header *eh; 484df8bae1dSRodney W. Grimes struct mbuf *m; 485df8bae1dSRodney W. Grimes { 486df8bae1dSRodney W. Grimes register struct ifqueue *inq; 4874a11ca4eSPoul-Henning Kamp u_short ether_type; 488df8bae1dSRodney W. Grimes int s; 4898e3bda06SJulian Elischer #if defined (ISO) || defined (LLC) || defined(NETATALK) 490c23670e2SGary Palmer register struct llc *l; 491c23670e2SGary Palmer #endif 492df8bae1dSRodney W. Grimes 493df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) { 494df8bae1dSRodney W. Grimes m_freem(m); 495df8bae1dSRodney W. Grimes return; 496df8bae1dSRodney W. Grimes } 497df8bae1dSRodney W. Grimes ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); 4982cc2df49SGarrett Wollman if (eh->ether_dhost[0] & 1) { 499df8bae1dSRodney W. Grimes if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 500df8bae1dSRodney W. Grimes sizeof(etherbroadcastaddr)) == 0) 501df8bae1dSRodney W. Grimes m->m_flags |= M_BCAST; 5022cc2df49SGarrett Wollman else 503df8bae1dSRodney W. Grimes m->m_flags |= M_MCAST; 5042cc2df49SGarrett Wollman } 505df8bae1dSRodney W. Grimes if (m->m_flags & (M_BCAST|M_MCAST)) 506df8bae1dSRodney W. Grimes ifp->if_imcasts++; 507df8bae1dSRodney W. Grimes 508307d80beSDavid Greenman ether_type = ntohs(eh->ether_type); 509307d80beSDavid Greenman 5104cf49a43SJulian Elischer #ifdef NETGRAPH 5114cf49a43SJulian Elischer { 5124cf49a43SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 5134cf49a43SJulian Elischer if (AC2NG(ac) && (AC2NG(ac)->flags & NGEF_DIVERT)) { 5144cf49a43SJulian Elischer ngether_send(ac, eh, m); 5154cf49a43SJulian Elischer return; 5164cf49a43SJulian Elischer } 5174cf49a43SJulian Elischer } 5184cf49a43SJulian Elischer #endif /* NETGRAPH */ 5194cf49a43SJulian Elischer 5202cc2df49SGarrett Wollman #if NVLAN > 0 5212cc2df49SGarrett Wollman if (ether_type == vlan_proto) { 5222cc2df49SGarrett Wollman if (vlan_input(eh, m) < 0) 5232cc2df49SGarrett Wollman ifp->if_data.ifi_noproto++; 5242cc2df49SGarrett Wollman return; 5252cc2df49SGarrett Wollman } 5262cc2df49SGarrett Wollman #endif /* NVLAN > 0 */ 5272cc2df49SGarrett Wollman 528307d80beSDavid Greenman switch (ether_type) { 529df8bae1dSRodney W. Grimes #ifdef INET 530df8bae1dSRodney W. Grimes case ETHERTYPE_IP: 5311f91d8c5SDavid Greenman if (ipflow_fastforward(m)) 5321f91d8c5SDavid Greenman return; 533df8bae1dSRodney W. Grimes schednetisr(NETISR_IP); 534df8bae1dSRodney W. Grimes inq = &ipintrq; 535df8bae1dSRodney W. Grimes break; 536df8bae1dSRodney W. Grimes 537df8bae1dSRodney W. Grimes case ETHERTYPE_ARP: 538df8bae1dSRodney W. Grimes schednetisr(NETISR_ARP); 539df8bae1dSRodney W. Grimes inq = &arpintrq; 540df8bae1dSRodney W. Grimes break; 541df8bae1dSRodney W. Grimes #endif 542cc6a66f2SJulian Elischer #ifdef IPX 543cc6a66f2SJulian Elischer case ETHERTYPE_IPX: 544cc6a66f2SJulian Elischer schednetisr(NETISR_IPX); 545cc6a66f2SJulian Elischer inq = &ipxintrq; 546cc6a66f2SJulian Elischer break; 547cc6a66f2SJulian Elischer #endif 54882cd038dSYoshinobu Inoue #ifdef INET6 54982cd038dSYoshinobu Inoue case ETHERTYPE_IPV6: 55082cd038dSYoshinobu Inoue schednetisr(NETISR_IPV6); 55182cd038dSYoshinobu Inoue inq = &ip6intrq; 55282cd038dSYoshinobu Inoue break; 55382cd038dSYoshinobu Inoue #endif 554df8bae1dSRodney W. Grimes #ifdef NS 55588e038feSJordan K. Hubbard case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ 556df8bae1dSRodney W. Grimes schednetisr(NETISR_NS); 557df8bae1dSRodney W. Grimes inq = &nsintrq; 558df8bae1dSRodney W. Grimes break; 55988e038feSJordan K. Hubbard 56088e038feSJordan K. Hubbard #endif /* NS */ 561655929bfSJulian Elischer #ifdef NETATALK 562655929bfSJulian Elischer case ETHERTYPE_AT: 563655929bfSJulian Elischer schednetisr(NETISR_ATALK); 564655929bfSJulian Elischer inq = &atintrq1; 565655929bfSJulian Elischer break; 566655929bfSJulian Elischer case ETHERTYPE_AARP: 567655929bfSJulian Elischer /* probably this should be done with a NETISR as well */ 5684c8e8c05SJulian Elischer aarpinput(IFP2AC(ifp), m); /* XXX */ 569655929bfSJulian Elischer return; 570655929bfSJulian Elischer #endif NETATALK 571df8bae1dSRodney W. Grimes default: 57288e038feSJordan K. Hubbard #ifdef NS 57388e038feSJordan K. Hubbard checksum = mtod(m, ushort *); 57488e038feSJordan K. Hubbard /* Novell 802.3 */ 57588e038feSJordan K. Hubbard if ((ether_type <= ETHERMTU) && 57688e038feSJordan K. Hubbard ((*checksum == 0xffff) || (*checksum == 0xE0E0))){ 57788e038feSJordan K. Hubbard if(*checksum == 0xE0E0) { 57888e038feSJordan K. Hubbard m->m_pkthdr.len -= 3; 57988e038feSJordan K. Hubbard m->m_len -= 3; 58088e038feSJordan K. Hubbard m->m_data += 3; 58188e038feSJordan K. Hubbard } 58288e038feSJordan K. Hubbard schednetisr(NETISR_NS); 58388e038feSJordan K. Hubbard inq = &nsintrq; 58488e038feSJordan K. Hubbard break; 58588e038feSJordan K. Hubbard } 58688e038feSJordan K. Hubbard #endif /* NS */ 587655929bfSJulian Elischer #if defined (ISO) || defined (LLC) || defined(NETATALK) 588307d80beSDavid Greenman if (ether_type > ETHERMTU) 589df8bae1dSRodney W. Grimes goto dropanyway; 590df8bae1dSRodney W. Grimes l = mtod(m, struct llc *); 591df8bae1dSRodney W. Grimes switch (l->llc_dsap) { 592655929bfSJulian Elischer #ifdef NETATALK 593655929bfSJulian Elischer case LLC_SNAP_LSAP: 594655929bfSJulian Elischer switch (l->llc_control) { 595655929bfSJulian Elischer case LLC_UI: 596655929bfSJulian Elischer if (l->llc_ssap != LLC_SNAP_LSAP) 597655929bfSJulian Elischer goto dropanyway; 598655929bfSJulian Elischer 599655929bfSJulian Elischer if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, 600655929bfSJulian Elischer sizeof(at_org_code)) == 0 && 601655929bfSJulian Elischer ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { 602655929bfSJulian Elischer inq = &atintrq2; 603655929bfSJulian Elischer m_adj( m, sizeof( struct llc )); 604655929bfSJulian Elischer schednetisr(NETISR_ATALK); 605655929bfSJulian Elischer break; 606655929bfSJulian Elischer } 607655929bfSJulian Elischer 608655929bfSJulian Elischer if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, 609655929bfSJulian Elischer sizeof(aarp_org_code)) == 0 && 610655929bfSJulian Elischer ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { 611655929bfSJulian Elischer m_adj( m, sizeof( struct llc )); 6124c8e8c05SJulian Elischer aarpinput(IFP2AC(ifp), m); /* XXX */ 613655929bfSJulian Elischer return; 614655929bfSJulian Elischer } 615655929bfSJulian Elischer 616655929bfSJulian Elischer default: 617655929bfSJulian Elischer goto dropanyway; 618655929bfSJulian Elischer } 619655929bfSJulian Elischer break; 620655929bfSJulian Elischer #endif NETATALK 621df8bae1dSRodney W. Grimes #ifdef ISO 622df8bae1dSRodney W. Grimes case LLC_ISO_LSAP: 623df8bae1dSRodney W. Grimes switch (l->llc_control) { 624df8bae1dSRodney W. Grimes case LLC_UI: 625df8bae1dSRodney W. Grimes /* LLC_UI_P forbidden in class 1 service */ 626df8bae1dSRodney W. Grimes if ((l->llc_dsap == LLC_ISO_LSAP) && 627df8bae1dSRodney W. Grimes (l->llc_ssap == LLC_ISO_LSAP)) { 628df8bae1dSRodney W. Grimes /* LSAP for ISO */ 629307d80beSDavid Greenman if (m->m_pkthdr.len > ether_type) 630307d80beSDavid Greenman m_adj(m, ether_type - m->m_pkthdr.len); 631df8bae1dSRodney W. Grimes m->m_data += 3; /* XXX */ 632df8bae1dSRodney W. Grimes m->m_len -= 3; /* XXX */ 633df8bae1dSRodney W. Grimes m->m_pkthdr.len -= 3; /* XXX */ 634df8bae1dSRodney W. Grimes M_PREPEND(m, sizeof *eh, M_DONTWAIT); 635df8bae1dSRodney W. Grimes if (m == 0) 636df8bae1dSRodney W. Grimes return; 637df8bae1dSRodney W. Grimes *mtod(m, struct ether_header *) = *eh; 638df8bae1dSRodney W. Grimes IFDEBUG(D_ETHER) 639df8bae1dSRodney W. Grimes printf("clnp packet"); 640df8bae1dSRodney W. Grimes ENDDEBUG 641df8bae1dSRodney W. Grimes schednetisr(NETISR_ISO); 642df8bae1dSRodney W. Grimes inq = &clnlintrq; 643df8bae1dSRodney W. Grimes break; 644df8bae1dSRodney W. Grimes } 645df8bae1dSRodney W. Grimes goto dropanyway; 646df8bae1dSRodney W. Grimes 647df8bae1dSRodney W. Grimes case LLC_XID: 648df8bae1dSRodney W. Grimes case LLC_XID_P: 649df8bae1dSRodney W. Grimes if(m->m_len < 6) 650df8bae1dSRodney W. Grimes goto dropanyway; 651df8bae1dSRodney W. Grimes l->llc_window = 0; 652df8bae1dSRodney W. Grimes l->llc_fid = 9; 653df8bae1dSRodney W. Grimes l->llc_class = 1; 654df8bae1dSRodney W. Grimes l->llc_dsap = l->llc_ssap = 0; 655df8bae1dSRodney W. Grimes /* Fall through to */ 656df8bae1dSRodney W. Grimes case LLC_TEST: 657df8bae1dSRodney W. Grimes case LLC_TEST_P: 658df8bae1dSRodney W. Grimes { 659df8bae1dSRodney W. Grimes struct sockaddr sa; 660df8bae1dSRodney W. Grimes register struct ether_header *eh2; 661df8bae1dSRodney W. Grimes int i; 662df8bae1dSRodney W. Grimes u_char c = l->llc_dsap; 663df8bae1dSRodney W. Grimes 664df8bae1dSRodney W. Grimes l->llc_dsap = l->llc_ssap; 665df8bae1dSRodney W. Grimes l->llc_ssap = c; 666df8bae1dSRodney W. Grimes if (m->m_flags & (M_BCAST | M_MCAST)) 667df8bae1dSRodney W. Grimes bcopy((caddr_t)ac->ac_enaddr, 668df8bae1dSRodney W. Grimes (caddr_t)eh->ether_dhost, 6); 669df8bae1dSRodney W. Grimes sa.sa_family = AF_UNSPEC; 670df8bae1dSRodney W. Grimes sa.sa_len = sizeof(sa); 671df8bae1dSRodney W. Grimes eh2 = (struct ether_header *)sa.sa_data; 672df8bae1dSRodney W. Grimes for (i = 0; i < 6; i++) { 673df8bae1dSRodney W. Grimes eh2->ether_shost[i] = c = eh->ether_dhost[i]; 674df8bae1dSRodney W. Grimes eh2->ether_dhost[i] = 675df8bae1dSRodney W. Grimes eh->ether_dhost[i] = eh->ether_shost[i]; 676df8bae1dSRodney W. Grimes eh->ether_shost[i] = c; 677df8bae1dSRodney W. Grimes } 678df8bae1dSRodney W. Grimes ifp->if_output(ifp, m, &sa, NULL); 679df8bae1dSRodney W. Grimes return; 680df8bae1dSRodney W. Grimes } 681df8bae1dSRodney W. Grimes default: 682df8bae1dSRodney W. Grimes m_freem(m); 683df8bae1dSRodney W. Grimes return; 684df8bae1dSRodney W. Grimes } 685df8bae1dSRodney W. Grimes break; 686df8bae1dSRodney W. Grimes #endif /* ISO */ 687df8bae1dSRodney W. Grimes #ifdef LLC 688df8bae1dSRodney W. Grimes case LLC_X25_LSAP: 689df8bae1dSRodney W. Grimes { 690307d80beSDavid Greenman if (m->m_pkthdr.len > ether_type) 691307d80beSDavid Greenman m_adj(m, ether_type - m->m_pkthdr.len); 692df8bae1dSRodney W. Grimes M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); 693df8bae1dSRodney W. Grimes if (m == 0) 694df8bae1dSRodney W. Grimes return; 695df8bae1dSRodney W. Grimes if ( !sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP, 696df8bae1dSRodney W. Grimes eh->ether_dhost, LLC_X25_LSAP, 6, 697df8bae1dSRodney W. Grimes mtod(m, struct sdl_hdr *))) 698df8bae1dSRodney W. Grimes panic("ETHER cons addr failure"); 699307d80beSDavid Greenman mtod(m, struct sdl_hdr *)->sdlhdr_len = ether_type; 700df8bae1dSRodney W. Grimes #ifdef LLC_DEBUG 701df8bae1dSRodney W. Grimes printf("llc packet\n"); 702df8bae1dSRodney W. Grimes #endif /* LLC_DEBUG */ 703df8bae1dSRodney W. Grimes schednetisr(NETISR_CCITT); 704df8bae1dSRodney W. Grimes inq = &llcintrq; 705df8bae1dSRodney W. Grimes break; 706df8bae1dSRodney W. Grimes } 707df8bae1dSRodney W. Grimes #endif /* LLC */ 708df8bae1dSRodney W. Grimes dropanyway: 709df8bae1dSRodney W. Grimes default: 7104cf49a43SJulian Elischer #ifdef NETGRAPH 7114cf49a43SJulian Elischer ngether_send(IFP2AC(ifp), eh, m); 7124cf49a43SJulian Elischer #else /* NETGRAPH */ 713df8bae1dSRodney W. Grimes m_freem(m); 7144cf49a43SJulian Elischer #endif /* NETGRAPH */ 715df8bae1dSRodney W. Grimes return; 716df8bae1dSRodney W. Grimes } 717655929bfSJulian Elischer #else /* ISO || LLC || NETATALK */ 7184cf49a43SJulian Elischer #ifdef NETGRAPH 7194cf49a43SJulian Elischer ngether_send(IFP2AC(ifp), eh, m); 7204cf49a43SJulian Elischer #else /* NETGRAPH */ 721df8bae1dSRodney W. Grimes m_freem(m); 7224cf49a43SJulian Elischer #endif /* NETGRAPH */ 723df8bae1dSRodney W. Grimes return; 724655929bfSJulian Elischer #endif /* ISO || LLC || NETATALK */ 725df8bae1dSRodney W. Grimes } 726df8bae1dSRodney W. Grimes 727df8bae1dSRodney W. Grimes s = splimp(); 728df8bae1dSRodney W. Grimes if (IF_QFULL(inq)) { 729df8bae1dSRodney W. Grimes IF_DROP(inq); 730df8bae1dSRodney W. Grimes m_freem(m); 731df8bae1dSRodney W. Grimes } else 732df8bae1dSRodney W. Grimes IF_ENQUEUE(inq, m); 733df8bae1dSRodney W. Grimes splx(s); 734df8bae1dSRodney W. Grimes } 735df8bae1dSRodney W. Grimes 736df8bae1dSRodney W. Grimes /* 737df8bae1dSRodney W. Grimes * Perform common duties while attaching to interface list 738df8bae1dSRodney W. Grimes */ 739df8bae1dSRodney W. Grimes void 740df8bae1dSRodney W. Grimes ether_ifattach(ifp) 741df8bae1dSRodney W. Grimes register struct ifnet *ifp; 742df8bae1dSRodney W. Grimes { 743df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 744df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl; 745df8bae1dSRodney W. Grimes 746df8bae1dSRodney W. Grimes ifp->if_type = IFT_ETHER; 747df8bae1dSRodney W. Grimes ifp->if_addrlen = 6; 748df8bae1dSRodney W. Grimes ifp->if_hdrlen = 14; 749df8bae1dSRodney W. Grimes ifp->if_mtu = ETHERMTU; 7501158dfb7SGarrett Wollman ifp->if_resolvemulti = ether_resolvemulti; 751a330e1f1SGary Palmer if (ifp->if_baudrate == 0) 752a330e1f1SGary Palmer ifp->if_baudrate = 10000000; 75359562606SGarrett Wollman ifa = ifnet_addrs[ifp->if_index - 1]; 75459562606SGarrett Wollman if (ifa == 0) { 75559562606SGarrett Wollman printf("ether_ifattach: no lladdr!\n"); 75659562606SGarrett Wollman return; 75759562606SGarrett Wollman } 75859562606SGarrett Wollman sdl = (struct sockaddr_dl *)ifa->ifa_addr; 759df8bae1dSRodney W. Grimes sdl->sdl_type = IFT_ETHER; 760df8bae1dSRodney W. Grimes sdl->sdl_alen = ifp->if_addrlen; 7614c8e8c05SJulian Elischer bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 7624c8e8c05SJulian Elischer #ifdef NETGRAPH 7634c8e8c05SJulian Elischer ngether_init(ifp); 7644c8e8c05SJulian Elischer #endif /* NETGRAPH */ 76582cd038dSYoshinobu Inoue #ifdef INET6 76682cd038dSYoshinobu Inoue in6_ifattach_getifid(ifp); 76782cd038dSYoshinobu Inoue #endif 768df8bae1dSRodney W. Grimes } 769df8bae1dSRodney W. Grimes 770ce02431fSDoug Rabson SYSCTL_DECL(_net_link); 771602d513cSGarrett Wollman SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); 77230106f6aSPoul-Henning Kamp 773fb583156SDavid Greenman int 774c5a1016bSBruce Evans ether_ioctl(ifp, command, data) 775c5a1016bSBruce Evans struct ifnet *ifp; 776c5a1016bSBruce Evans int command; 777c5a1016bSBruce Evans caddr_t data; 77830106f6aSPoul-Henning Kamp { 77930106f6aSPoul-Henning Kamp struct ifaddr *ifa = (struct ifaddr *) data; 78030106f6aSPoul-Henning Kamp struct ifreq *ifr = (struct ifreq *) data; 781fb583156SDavid Greenman int error = 0; 78230106f6aSPoul-Henning Kamp 78330106f6aSPoul-Henning Kamp switch (command) { 78430106f6aSPoul-Henning Kamp case SIOCSIFADDR: 78530106f6aSPoul-Henning Kamp ifp->if_flags |= IFF_UP; 78630106f6aSPoul-Henning Kamp 78730106f6aSPoul-Henning Kamp switch (ifa->ifa_addr->sa_family) { 78830106f6aSPoul-Henning Kamp #ifdef INET 78930106f6aSPoul-Henning Kamp case AF_INET: 79030106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); /* before arpwhohas */ 7914c8e8c05SJulian Elischer arp_ifinit(IFP2AC(ifp), ifa); 79230106f6aSPoul-Henning Kamp break; 79330106f6aSPoul-Henning Kamp #endif 79430106f6aSPoul-Henning Kamp #ifdef IPX 79530106f6aSPoul-Henning Kamp /* 79630106f6aSPoul-Henning Kamp * XXX - This code is probably wrong 79730106f6aSPoul-Henning Kamp */ 79830106f6aSPoul-Henning Kamp case AF_IPX: 79930106f6aSPoul-Henning Kamp { 80030106f6aSPoul-Henning Kamp register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 8014c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 80230106f6aSPoul-Henning Kamp 80330106f6aSPoul-Henning Kamp if (ipx_nullhost(*ina)) 80430106f6aSPoul-Henning Kamp ina->x_host = 80586101139SPoul-Henning Kamp *(union ipx_host *) 80686101139SPoul-Henning Kamp ac->ac_enaddr; 80730106f6aSPoul-Henning Kamp else { 80830106f6aSPoul-Henning Kamp bcopy((caddr_t) ina->x_host.c_host, 80986101139SPoul-Henning Kamp (caddr_t) ac->ac_enaddr, 81086101139SPoul-Henning Kamp sizeof(ac->ac_enaddr)); 81130106f6aSPoul-Henning Kamp } 81230106f6aSPoul-Henning Kamp 81330106f6aSPoul-Henning Kamp /* 81430106f6aSPoul-Henning Kamp * Set new address 81530106f6aSPoul-Henning Kamp */ 81630106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 81730106f6aSPoul-Henning Kamp break; 81830106f6aSPoul-Henning Kamp } 81930106f6aSPoul-Henning Kamp #endif 82030106f6aSPoul-Henning Kamp #ifdef NS 82130106f6aSPoul-Henning Kamp /* 82230106f6aSPoul-Henning Kamp * XXX - This code is probably wrong 82330106f6aSPoul-Henning Kamp */ 82430106f6aSPoul-Henning Kamp case AF_NS: 82530106f6aSPoul-Henning Kamp { 82630106f6aSPoul-Henning Kamp register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 8274c8e8c05SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 82830106f6aSPoul-Henning Kamp 82930106f6aSPoul-Henning Kamp if (ns_nullhost(*ina)) 83030106f6aSPoul-Henning Kamp ina->x_host = 83186101139SPoul-Henning Kamp *(union ns_host *) (ac->ac_enaddr); 83230106f6aSPoul-Henning Kamp else { 83330106f6aSPoul-Henning Kamp bcopy((caddr_t) ina->x_host.c_host, 83486101139SPoul-Henning Kamp (caddr_t) ac->ac_enaddr, 83586101139SPoul-Henning Kamp sizeof(ac->ac_enaddr)); 83630106f6aSPoul-Henning Kamp } 83730106f6aSPoul-Henning Kamp 83830106f6aSPoul-Henning Kamp /* 83930106f6aSPoul-Henning Kamp * Set new address 84030106f6aSPoul-Henning Kamp */ 84130106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 84230106f6aSPoul-Henning Kamp break; 84330106f6aSPoul-Henning Kamp } 84430106f6aSPoul-Henning Kamp #endif 84530106f6aSPoul-Henning Kamp default: 84630106f6aSPoul-Henning Kamp ifp->if_init(ifp->if_softc); 84730106f6aSPoul-Henning Kamp break; 84830106f6aSPoul-Henning Kamp } 84930106f6aSPoul-Henning Kamp break; 85030106f6aSPoul-Henning Kamp 85130106f6aSPoul-Henning Kamp case SIOCGIFADDR: 85230106f6aSPoul-Henning Kamp { 85330106f6aSPoul-Henning Kamp struct sockaddr *sa; 85430106f6aSPoul-Henning Kamp 85530106f6aSPoul-Henning Kamp sa = (struct sockaddr *) & ifr->ifr_data; 8564c8e8c05SJulian Elischer bcopy(IFP2AC(ifp)->ac_enaddr, 85730106f6aSPoul-Henning Kamp (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 85830106f6aSPoul-Henning Kamp } 85930106f6aSPoul-Henning Kamp break; 860fb583156SDavid Greenman 861fb583156SDavid Greenman case SIOCSIFMTU: 862fb583156SDavid Greenman /* 863fb583156SDavid Greenman * Set the interface MTU. 864fb583156SDavid Greenman */ 865fb583156SDavid Greenman if (ifr->ifr_mtu > ETHERMTU) { 866fb583156SDavid Greenman error = EINVAL; 867fb583156SDavid Greenman } else { 868fb583156SDavid Greenman ifp->if_mtu = ifr->ifr_mtu; 86930106f6aSPoul-Henning Kamp } 870fb583156SDavid Greenman break; 871fb583156SDavid Greenman } 872fb583156SDavid Greenman return (error); 87330106f6aSPoul-Henning Kamp } 8741158dfb7SGarrett Wollman 8751158dfb7SGarrett Wollman int 8761158dfb7SGarrett Wollman ether_resolvemulti(ifp, llsa, sa) 8771158dfb7SGarrett Wollman struct ifnet *ifp; 8781158dfb7SGarrett Wollman struct sockaddr **llsa; 8791158dfb7SGarrett Wollman struct sockaddr *sa; 8801158dfb7SGarrett Wollman { 8811158dfb7SGarrett Wollman struct sockaddr_dl *sdl; 8821158dfb7SGarrett Wollman struct sockaddr_in *sin; 88382cd038dSYoshinobu Inoue #ifdef INET6 88482cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6; 88582cd038dSYoshinobu Inoue #endif 8861158dfb7SGarrett Wollman u_char *e_addr; 8871158dfb7SGarrett Wollman 8881158dfb7SGarrett Wollman switch(sa->sa_family) { 8891158dfb7SGarrett Wollman case AF_LINK: 8907f33a738SJulian Elischer /* 8917f33a738SJulian Elischer * No mapping needed. Just check that it's a valid MC address. 8927f33a738SJulian Elischer */ 8931158dfb7SGarrett Wollman sdl = (struct sockaddr_dl *)sa; 8941158dfb7SGarrett Wollman e_addr = LLADDR(sdl); 8951158dfb7SGarrett Wollman if ((e_addr[0] & 1) != 1) 8961158dfb7SGarrett Wollman return EADDRNOTAVAIL; 8971158dfb7SGarrett Wollman *llsa = 0; 8981158dfb7SGarrett Wollman return 0; 8991158dfb7SGarrett Wollman 9001158dfb7SGarrett Wollman #ifdef INET 9011158dfb7SGarrett Wollman case AF_INET: 9021158dfb7SGarrett Wollman sin = (struct sockaddr_in *)sa; 9031158dfb7SGarrett Wollman if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 9041158dfb7SGarrett Wollman return EADDRNOTAVAIL; 9051158dfb7SGarrett Wollman MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 9061158dfb7SGarrett Wollman M_WAITOK); 9071158dfb7SGarrett Wollman sdl->sdl_len = sizeof *sdl; 9081158dfb7SGarrett Wollman sdl->sdl_family = AF_LINK; 9091158dfb7SGarrett Wollman sdl->sdl_index = ifp->if_index; 9101158dfb7SGarrett Wollman sdl->sdl_type = IFT_ETHER; 9111158dfb7SGarrett Wollman sdl->sdl_nlen = 0; 9121158dfb7SGarrett Wollman sdl->sdl_alen = ETHER_ADDR_LEN; 9131158dfb7SGarrett Wollman sdl->sdl_slen = 0; 9141158dfb7SGarrett Wollman e_addr = LLADDR(sdl); 9151158dfb7SGarrett Wollman ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 9161158dfb7SGarrett Wollman *llsa = (struct sockaddr *)sdl; 9171158dfb7SGarrett Wollman return 0; 9181158dfb7SGarrett Wollman #endif 91982cd038dSYoshinobu Inoue #ifdef INET6 92082cd038dSYoshinobu Inoue case AF_INET6: 92182cd038dSYoshinobu Inoue sin6 = (struct sockaddr_in6 *)sa; 92282cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 92382cd038dSYoshinobu Inoue return EADDRNOTAVAIL; 92482cd038dSYoshinobu Inoue MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 92582cd038dSYoshinobu Inoue M_WAITOK); 92682cd038dSYoshinobu Inoue sdl->sdl_len = sizeof *sdl; 92782cd038dSYoshinobu Inoue sdl->sdl_family = AF_LINK; 92882cd038dSYoshinobu Inoue sdl->sdl_index = ifp->if_index; 92982cd038dSYoshinobu Inoue sdl->sdl_type = IFT_ETHER; 93082cd038dSYoshinobu Inoue sdl->sdl_nlen = 0; 93182cd038dSYoshinobu Inoue sdl->sdl_alen = ETHER_ADDR_LEN; 93282cd038dSYoshinobu Inoue sdl->sdl_slen = 0; 93382cd038dSYoshinobu Inoue e_addr = LLADDR(sdl); 93482cd038dSYoshinobu Inoue ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 93582cd038dSYoshinobu Inoue *llsa = (struct sockaddr *)sdl; 93682cd038dSYoshinobu Inoue return 0; 93782cd038dSYoshinobu Inoue #endif 9381158dfb7SGarrett Wollman 9391158dfb7SGarrett Wollman default: 9401158dfb7SGarrett Wollman /* 9411158dfb7SGarrett Wollman * Well, the text isn't quite right, but it's the name 9421158dfb7SGarrett Wollman * that counts... 9431158dfb7SGarrett Wollman */ 9441158dfb7SGarrett Wollman return EAFNOSUPPORT; 9451158dfb7SGarrett Wollman } 9461158dfb7SGarrett Wollman } 9474cf49a43SJulian Elischer 9484cf49a43SJulian Elischer #ifdef NETGRAPH 9494cf49a43SJulian Elischer 9504cf49a43SJulian Elischer /*********************************************************************** 9514cf49a43SJulian Elischer * This section contains the methods for the Netgraph interface 9524cf49a43SJulian Elischer ***********************************************************************/ 9534cf49a43SJulian Elischer /* It's Ascii-art time! 9544cf49a43SJulian Elischer * The ifnet is the first part of the arpcom which must be 9554cf49a43SJulian Elischer * the first part of the device's softc.. yuk. 9564cf49a43SJulian Elischer * 9574cf49a43SJulian Elischer * +--------------------------+-----+---------+ 9584cf49a43SJulian Elischer * | struct ifnet (*ifp) | | | 9594cf49a43SJulian Elischer * | | | | 9604cf49a43SJulian Elischer * +--------------------------+ | | 9614cf49a43SJulian Elischer * +--|[ac_ng] struct arpcom (*ac) | | 9624cf49a43SJulian Elischer * | +--------------------------------+ | 9634cf49a43SJulian Elischer * | | struct softc (*ifp->if_softc) (device) | 9644cf49a43SJulian Elischer * | +------------------------------------------+ 9654cf49a43SJulian Elischer * | ^ 9664cf49a43SJulian Elischer * AC2NG() | 9674cf49a43SJulian Elischer * | v 9684cf49a43SJulian Elischer * | +----------------------+ 9694cf49a43SJulian Elischer * | | [private] [flags] | 9704cf49a43SJulian Elischer * +------>| struct ng_node | 9714cf49a43SJulian Elischer * | [hooks] | ** we only allow one hook 9724cf49a43SJulian Elischer * +----------------------+ 9734cf49a43SJulian Elischer * ^ 9744cf49a43SJulian Elischer * | 9754cf49a43SJulian Elischer * v 9764cf49a43SJulian Elischer * +-------------+ 9774cf49a43SJulian Elischer * | [node] | 9784cf49a43SJulian Elischer * | hook | 9794cf49a43SJulian Elischer * | [private]|-- *unused* 9804cf49a43SJulian Elischer * +-------------+ 9814cf49a43SJulian Elischer */ 9824cf49a43SJulian Elischer 9834cf49a43SJulian Elischer /* 9844cf49a43SJulian Elischer * called during interface attaching 9854cf49a43SJulian Elischer */ 9864cf49a43SJulian Elischer static void 9874cf49a43SJulian Elischer ngether_init(void *ifpvoid) 9884cf49a43SJulian Elischer { 9894cf49a43SJulian Elischer struct ifnet *ifp = ifpvoid; 9904cf49a43SJulian Elischer struct arpcom *ac = IFP2AC(ifp); 9914cf49a43SJulian Elischer static int ngether_done_init; 9924cf49a43SJulian Elischer char namebuf[32]; 9934cf49a43SJulian Elischer node_p node; 9944cf49a43SJulian Elischer 9954cf49a43SJulian Elischer /* 9964cf49a43SJulian Elischer * we have found a node, make sure our 'type' is availabe. 9974cf49a43SJulian Elischer */ 9984cf49a43SJulian Elischer if (ngether_done_init == 0) { 9994cf49a43SJulian Elischer if (ng_newtype(&typestruct)) { 10004cf49a43SJulian Elischer printf("ngether install failed\n"); 10014cf49a43SJulian Elischer return; 10024cf49a43SJulian Elischer } 10034cf49a43SJulian Elischer ngether_done_init = 1; 10044cf49a43SJulian Elischer } 10054cf49a43SJulian Elischer if (ng_make_node_common(&typestruct, &node) != 0) 10064cf49a43SJulian Elischer return; 10074cf49a43SJulian Elischer ac->ac_ng = node; 10084cf49a43SJulian Elischer node->private = ifp; 10094cf49a43SJulian Elischer sprintf(namebuf, "%s%d", ifp->if_name, ifp->if_unit); 10104cf49a43SJulian Elischer ng_name_node(AC2NG(ac), namebuf); 10114cf49a43SJulian Elischer } 10124cf49a43SJulian Elischer 10134cf49a43SJulian Elischer /* 10144cf49a43SJulian Elischer * It is not possible or allowable to create a node of this type. 10154cf49a43SJulian Elischer * If the hardware exists, it will already have created it. 10164cf49a43SJulian Elischer */ 10174cf49a43SJulian Elischer static int 10184cf49a43SJulian Elischer ngether_constructor(node_p *nodep) 10194cf49a43SJulian Elischer { 10204cf49a43SJulian Elischer return (EINVAL); 10214cf49a43SJulian Elischer } 10224cf49a43SJulian Elischer 10234cf49a43SJulian Elischer /* 10244cf49a43SJulian Elischer * Give our ok for a hook to be added... 10254cf49a43SJulian Elischer * 10264cf49a43SJulian Elischer * Allow one hook at a time (rawdata). 10274cf49a43SJulian Elischer * It can eiteh rdivert everything or only unclaimed packets. 10284cf49a43SJulian Elischer */ 10294cf49a43SJulian Elischer static int 10304cf49a43SJulian Elischer ngether_newhook(node_p node, hook_p hook, const char *name) 10314cf49a43SJulian Elischer { 10324cf49a43SJulian Elischer 10334cf49a43SJulian Elischer /* check if there is already a hook */ 10344cf49a43SJulian Elischer if (LIST_FIRST(&(node->hooks))) 10354cf49a43SJulian Elischer return(EISCONN); 10364cf49a43SJulian Elischer /* 10374cf49a43SJulian Elischer * Check for which mode hook we want. 10384cf49a43SJulian Elischer */ 10394cf49a43SJulian Elischer if (strcmp(name, NG_ETHER_HOOK_ORPHAN) != 0) { 10404cf49a43SJulian Elischer if (strcmp(name, NG_ETHER_HOOK_DIVERT) != 0) { 10414cf49a43SJulian Elischer return (EINVAL); 10424cf49a43SJulian Elischer } 10434cf49a43SJulian Elischer node->flags |= NGEF_DIVERT; 10444cf49a43SJulian Elischer } else { 10454cf49a43SJulian Elischer node->flags &= ~NGEF_DIVERT; 10464cf49a43SJulian Elischer } 10474cf49a43SJulian Elischer return (0); 10484cf49a43SJulian Elischer } 10494cf49a43SJulian Elischer 10504cf49a43SJulian Elischer /* 10514cf49a43SJulian Elischer * incoming messages. 10524cf49a43SJulian Elischer * Just respond to the generic TEXT_STATUS message 10534cf49a43SJulian Elischer */ 10544cf49a43SJulian Elischer static int 10554cf49a43SJulian Elischer ngether_rcvmsg(node_p node, 10564cf49a43SJulian Elischer struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp) 10574cf49a43SJulian Elischer { 10584cf49a43SJulian Elischer struct ifnet *ifp; 10594cf49a43SJulian Elischer int error = 0; 10604cf49a43SJulian Elischer 10614cf49a43SJulian Elischer ifp = node->private; 10624cf49a43SJulian Elischer switch (msg->header.typecookie) { 10634cf49a43SJulian Elischer case NGM_ETHER_COOKIE: 10644cf49a43SJulian Elischer error = EINVAL; 10654cf49a43SJulian Elischer break; 10664cf49a43SJulian Elischer case NGM_GENERIC_COOKIE: 10674cf49a43SJulian Elischer switch(msg->header.cmd) { 10684cf49a43SJulian Elischer case NGM_TEXT_STATUS: { 10694cf49a43SJulian Elischer char *arg; 10704cf49a43SJulian Elischer int pos = 0; 10714cf49a43SJulian Elischer int resplen = sizeof(struct ng_mesg) + 512; 10724cf49a43SJulian Elischer MALLOC(*resp, struct ng_mesg *, resplen, 10734cf49a43SJulian Elischer M_NETGRAPH, M_NOWAIT); 10744cf49a43SJulian Elischer if (*resp == NULL) { 10754cf49a43SJulian Elischer error = ENOMEM; 10764cf49a43SJulian Elischer break; 10774cf49a43SJulian Elischer } 10784cf49a43SJulian Elischer bzero(*resp, resplen); 10794cf49a43SJulian Elischer arg = (*resp)->data; 10804cf49a43SJulian Elischer 10814cf49a43SJulian Elischer /* 10824cf49a43SJulian Elischer * Put in the throughput information. 10834cf49a43SJulian Elischer */ 10844cf49a43SJulian Elischer pos = sprintf(arg, "%ld bytes in, %ld bytes out\n", 10854cf49a43SJulian Elischer ifp->if_ibytes, ifp->if_obytes); 10864cf49a43SJulian Elischer pos += sprintf(arg + pos, 10874cf49a43SJulian Elischer "%ld output errors\n", 10884cf49a43SJulian Elischer ifp->if_oerrors); 10894cf49a43SJulian Elischer pos += sprintf(arg + pos, 10904cf49a43SJulian Elischer "ierrors = %ld\n", 10914cf49a43SJulian Elischer ifp->if_ierrors); 10924cf49a43SJulian Elischer 10934cf49a43SJulian Elischer (*resp)->header.version = NG_VERSION; 10944cf49a43SJulian Elischer (*resp)->header.arglen = strlen(arg) + 1; 10954cf49a43SJulian Elischer (*resp)->header.token = msg->header.token; 10964cf49a43SJulian Elischer (*resp)->header.typecookie = NGM_ETHER_COOKIE; 10974cf49a43SJulian Elischer (*resp)->header.cmd = msg->header.cmd; 10984cf49a43SJulian Elischer strncpy((*resp)->header.cmdstr, "status", 10994cf49a43SJulian Elischer NG_CMDSTRLEN); 11004cf49a43SJulian Elischer } 11014cf49a43SJulian Elischer break; 11024cf49a43SJulian Elischer default: 11034cf49a43SJulian Elischer error = EINVAL; 11044cf49a43SJulian Elischer break; 11054cf49a43SJulian Elischer } 11064cf49a43SJulian Elischer break; 11074cf49a43SJulian Elischer default: 11084cf49a43SJulian Elischer error = EINVAL; 11094cf49a43SJulian Elischer break; 11104cf49a43SJulian Elischer } 11114cf49a43SJulian Elischer free(msg, M_NETGRAPH); 11124cf49a43SJulian Elischer return (error); 11134cf49a43SJulian Elischer } 11144cf49a43SJulian Elischer 11154cf49a43SJulian Elischer /* 11164cf49a43SJulian Elischer * Receive a completed ethernet packet. 11174cf49a43SJulian Elischer * Queue it for output. 11184cf49a43SJulian Elischer */ 11194cf49a43SJulian Elischer static int 11204cf49a43SJulian Elischer ngether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 11214cf49a43SJulian Elischer { 11224cf49a43SJulian Elischer struct ifnet *ifp; 11234cf49a43SJulian Elischer int error = 0; 11244cf49a43SJulian Elischer int s; 11254cf49a43SJulian Elischer struct ether_header *eh; 11264cf49a43SJulian Elischer 11274cf49a43SJulian Elischer ifp = hook->node->private; 11284cf49a43SJulian Elischer 11294cf49a43SJulian Elischer if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 11304cf49a43SJulian Elischer senderr(ENETDOWN); 1131e03b02a3SJulian Elischer /* drop in the MAC address */ 1132e03b02a3SJulian Elischer eh = mtod(m, struct ether_header *); 1133e03b02a3SJulian Elischer bcopy(IFP2AC(ifp)->ac_enaddr, eh->ether_shost, 6); 11344cf49a43SJulian Elischer /* 11354cf49a43SJulian Elischer * If a simplex interface, and the packet is being sent to our 11364cf49a43SJulian Elischer * Ethernet address or a broadcast address, loopback a copy. 11374cf49a43SJulian Elischer * XXX To make a simplex device behave exactly like a duplex 11384cf49a43SJulian Elischer * device, we should copy in the case of sending to our own 11394cf49a43SJulian Elischer * ethernet address (thus letting the original actually appear 11404cf49a43SJulian Elischer * on the wire). However, we don't do that here for security 11414cf49a43SJulian Elischer * reasons and compatibility with the original behavior. 11424cf49a43SJulian Elischer */ 11434cf49a43SJulian Elischer if (ifp->if_flags & IFF_SIMPLEX) { 11444cf49a43SJulian Elischer if (m->m_flags & M_BCAST) { 11454cf49a43SJulian Elischer struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 11464cf49a43SJulian Elischer 11474cf49a43SJulian Elischer ng_queue_data(hook, n, meta); 11484cf49a43SJulian Elischer } else if (bcmp(eh->ether_dhost, 11494cf49a43SJulian Elischer eh->ether_shost, ETHER_ADDR_LEN) == 0) { 11504cf49a43SJulian Elischer ng_queue_data(hook, m, meta); 11514cf49a43SJulian Elischer return (0); /* XXX */ 11524cf49a43SJulian Elischer } 11534cf49a43SJulian Elischer } 11544cf49a43SJulian Elischer s = splimp(); 11554cf49a43SJulian Elischer /* 11564cf49a43SJulian Elischer * Queue message on interface, and start output if interface 11574cf49a43SJulian Elischer * not yet active. 11584cf49a43SJulian Elischer * XXX if we lookead at the priority in the meta data we could 11594cf49a43SJulian Elischer * queue high priority items at the head. 11604cf49a43SJulian Elischer */ 11614cf49a43SJulian Elischer if (IF_QFULL(&ifp->if_snd)) { 11624cf49a43SJulian Elischer IF_DROP(&ifp->if_snd); 11634cf49a43SJulian Elischer splx(s); 11644cf49a43SJulian Elischer senderr(ENOBUFS); 11654cf49a43SJulian Elischer } 11664cf49a43SJulian Elischer IF_ENQUEUE(&ifp->if_snd, m); 11674cf49a43SJulian Elischer if ((ifp->if_flags & IFF_OACTIVE) == 0) 11684cf49a43SJulian Elischer (*ifp->if_start)(ifp); 11694cf49a43SJulian Elischer splx(s); 11704cf49a43SJulian Elischer ifp->if_obytes += m->m_pkthdr.len; 11714cf49a43SJulian Elischer if (m->m_flags & M_MCAST) 11724cf49a43SJulian Elischer ifp->if_omcasts++; 11734cf49a43SJulian Elischer return (error); 11744cf49a43SJulian Elischer 11754cf49a43SJulian Elischer bad: 11764cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 11774cf49a43SJulian Elischer return (error); 11784cf49a43SJulian Elischer } 11794cf49a43SJulian Elischer 11804cf49a43SJulian Elischer /* 11814cf49a43SJulian Elischer * pass an mbuf out to the connected hook 1182021823c3SJulian Elischer * More complicated than just an m_prepend, as it tries to save later nodes 1183021823c3SJulian Elischer * from needing to do lots of m_pullups. 11844cf49a43SJulian Elischer */ 11854cf49a43SJulian Elischer static void 11864cf49a43SJulian Elischer ngether_send(struct arpcom *ac, struct ether_header *eh, struct mbuf *m) 11874cf49a43SJulian Elischer { 1188021823c3SJulian Elischer int room; 11894cf49a43SJulian Elischer node_p node = AC2NG(ac); 11904cf49a43SJulian Elischer struct ether_header *eh2; 11914cf49a43SJulian Elischer 11924cf49a43SJulian Elischer if (node && LIST_FIRST(&(node->hooks))) { 11934cf49a43SJulian Elischer /* 1194021823c3SJulian Elischer * Possibly the header is already on the front, 11954cf49a43SJulian Elischer */ 1196021823c3SJulian Elischer eh2 = mtod(m, struct ether_header *) - 1; 1197021823c3SJulian Elischer if ( eh == eh2) { 1198021823c3SJulian Elischer /* 1199021823c3SJulian Elischer * This is the case so just move the markers back to 1200021823c3SJulian Elischer * re-include it. We lucked out. 1201021823c3SJulian Elischer * This allows us to avoid a yucky m_pullup 1202021823c3SJulian Elischer * in later nodes if it works. 1203021823c3SJulian Elischer */ 1204021823c3SJulian Elischer m->m_len += sizeof(*eh); 1205021823c3SJulian Elischer m->m_data -= sizeof(*eh); 1206021823c3SJulian Elischer m->m_pkthdr.len += sizeof(*eh); 1207021823c3SJulian Elischer } else { 1208021823c3SJulian Elischer /* 1209021823c3SJulian Elischer * Alternatively there may be room even though 1210021823c3SJulian Elischer * it is stored somewhere else. If so, copy it in. 1211021823c3SJulian Elischer * This only safe because we KNOW that this packet has 1212021823c3SJulian Elischer * just been generated by an ethernet card, so there 1213021823c3SJulian Elischer * are no aliases to the buffer. (unlike in outgoing 1214021823c3SJulian Elischer * packets). 1215021823c3SJulian Elischer * Nearly all ethernet cards will end up producing mbufs 1216021823c3SJulian Elischer * that fall into these cases. So we are not optimising 1217021823c3SJulian Elischer * contorted cases. 1218021823c3SJulian Elischer */ 1219021823c3SJulian Elischer 1220021823c3SJulian Elischer if (m->m_flags & M_EXT) { 1221021823c3SJulian Elischer room = (mtod(m, caddr_t) - m->m_ext.ext_buf); 1222021823c3SJulian Elischer if (room > m->m_ext.ext_size) /* garbage */ 1223021823c3SJulian Elischer room = 0; /* fail immediatly */ 1224021823c3SJulian Elischer } else { 1225021823c3SJulian Elischer room = (mtod(m, caddr_t) - m->m_pktdat); 1226021823c3SJulian Elischer } 1227021823c3SJulian Elischer if (room > sizeof (*eh)) { 1228021823c3SJulian Elischer /* we have room, just copy it and adjust */ 1229021823c3SJulian Elischer m->m_len += sizeof(*eh); 1230021823c3SJulian Elischer m->m_data -= sizeof(*eh); 1231021823c3SJulian Elischer m->m_pkthdr.len += sizeof(*eh); 1232021823c3SJulian Elischer } else { 1233021823c3SJulian Elischer /* 1234021823c3SJulian Elischer * Doing anything more is likely to get more 1235021823c3SJulian Elischer * expensive than it's worth.. 1236021823c3SJulian Elischer * it's probable that everything else is in one 1237021823c3SJulian Elischer * big lump. The next node will do an m_pullup() 1238021823c3SJulian Elischer * for exactly the amount of data it needs and 1239021823c3SJulian Elischer * hopefully everything after that will not 1240ecf33d87SJulian Elischer * need one. So let's just use M_PREPEND. 1241021823c3SJulian Elischer */ 1242ecf33d87SJulian Elischer M_PREPEND(m, sizeof (*eh), M_DONTWAIT); 1243021823c3SJulian Elischer if (m == NULL) 1244021823c3SJulian Elischer return; 1245021823c3SJulian Elischer } 12462b75f795SJulian Elischer bcopy ((caddr_t)eh, mtod(m, struct ether_header *), 12472b75f795SJulian Elischer sizeof(*eh)); 1248021823c3SJulian Elischer } 12494cf49a43SJulian Elischer ng_queue_data(LIST_FIRST(&(node->hooks)), m, NULL); 12504cf49a43SJulian Elischer } else { 12514cf49a43SJulian Elischer m_freem(m); 12524cf49a43SJulian Elischer } 12534cf49a43SJulian Elischer } 1254021823c3SJulian Elischer 12554cf49a43SJulian Elischer /* 12564cf49a43SJulian Elischer * do local shutdown processing.. 12574cf49a43SJulian Elischer * This node will refuse to go away, unless the hardware says to.. 12584cf49a43SJulian Elischer * don't unref the node, or remove our name. just clear our links up. 12594cf49a43SJulian Elischer */ 12604cf49a43SJulian Elischer static int 12614cf49a43SJulian Elischer ngether_rmnode(node_p node) 12624cf49a43SJulian Elischer { 12634cf49a43SJulian Elischer ng_cutlinks(node); 12644cf49a43SJulian Elischer node->flags &= ~NG_INVALID; /* bounce back to life */ 12654cf49a43SJulian Elischer return (0); 12664cf49a43SJulian Elischer } 12674cf49a43SJulian Elischer 12684cf49a43SJulian Elischer /* already linked */ 12694cf49a43SJulian Elischer static int 12704cf49a43SJulian Elischer ngether_connect(hook_p hook) 12714cf49a43SJulian Elischer { 12724cf49a43SJulian Elischer /* be really amiable and just say "YUP that's OK by me! " */ 12734cf49a43SJulian Elischer return (0); 12744cf49a43SJulian Elischer } 12754cf49a43SJulian Elischer 12764cf49a43SJulian Elischer /* 12774cf49a43SJulian Elischer * notify on hook disconnection (destruction) 12784cf49a43SJulian Elischer * 12794cf49a43SJulian Elischer * For this type, removal of the last lins no effect. The interface can run 12804cf49a43SJulian Elischer * independently. 12814cf49a43SJulian Elischer * Since we have no per-hook information, this is rather simple. 12824cf49a43SJulian Elischer */ 12834cf49a43SJulian Elischer static int 12844cf49a43SJulian Elischer ngether_disconnect(hook_p hook) 12854cf49a43SJulian Elischer { 12864cf49a43SJulian Elischer hook->node->flags &= ~NGEF_DIVERT; 12874cf49a43SJulian Elischer return (0); 12884cf49a43SJulian Elischer } 12894cf49a43SJulian Elischer #endif /* NETGRAPH */ 12904cf49a43SJulian Elischer 12914cf49a43SJulian Elischer /********************************** END *************************************/ 1292