152419Sjulian/* 252419Sjulian * ng_iface.c 3139823Simp */ 4139823Simp 5139823Simp/*- 652419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 752419Sjulian * All rights reserved. 852419Sjulian * 952419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 1052419Sjulian * redistribution of this software, in source or object code forms, with or 1152419Sjulian * without modifications are expressly permitted by Whistle Communications; 1252419Sjulian * provided, however, that: 1352419Sjulian * 1. Any and all reproductions of the source or object code must include the 1452419Sjulian * copyright notice above and the following disclaimer of warranties; and 1552419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1652419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1752419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1852419Sjulian * such appears in the above copyright notice or in the software. 1952419Sjulian * 2052419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2152419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2252419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2352419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2452419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2552419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2652419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2752419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2852419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2952419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3052419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3152419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3252419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3352419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3452419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3552419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3652419Sjulian * OF SUCH DAMAGE. 3752419Sjulian * 3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 3952419Sjulian * 4052419Sjulian * $FreeBSD$ 4152752Sjulian * $Whistle: ng_iface.c,v 1.33 1999/11/01 09:24:51 julian Exp $ 4252419Sjulian */ 4352419Sjulian 4452419Sjulian/* 4552419Sjulian * This node is also a system networking interface. It has 4652419Sjulian * a hook for each protocol (IP, AppleTalk, IPX, etc). Packets 4752419Sjulian * are simply relayed between the interface and the hooks. 4852419Sjulian * 4958015Sarchie * Interfaces are named ng0, ng1, etc. New nodes take the 5058015Sarchie * first available interface name. 5152419Sjulian * 5252419Sjulian * This node also includes Berkeley packet filter support. 5352419Sjulian */ 5452419Sjulian 55111997Sjlemon#include "opt_atalk.h" 56111997Sjlemon#include "opt_inet.h" 57111997Sjlemon#include "opt_inet6.h" 58111997Sjlemon#include "opt_ipx.h" 59111997Sjlemon 6052419Sjulian#include <sys/param.h> 6152419Sjulian#include <sys/systm.h> 6252419Sjulian#include <sys/errno.h> 6352419Sjulian#include <sys/kernel.h> 6452419Sjulian#include <sys/malloc.h> 6552419Sjulian#include <sys/mbuf.h> 6652419Sjulian#include <sys/errno.h> 67196019Srwatson#include <sys/proc.h> 68111888Sjlemon#include <sys/random.h> 6952419Sjulian#include <sys/sockio.h> 7052419Sjulian#include <sys/socket.h> 7152419Sjulian#include <sys/syslog.h> 7258015Sarchie#include <sys/libkern.h> 7352419Sjulian 7452419Sjulian#include <net/if.h> 7552419Sjulian#include <net/if_types.h> 7658015Sarchie#include <net/bpf.h> 77111888Sjlemon#include <net/netisr.h> 78191148Skmacy#include <net/route.h> 79195837Srwatson#include <net/vnet.h> 8052419Sjulian 8153913Sarchie#include <netinet/in.h> 8253913Sarchie 8352419Sjulian#include <netgraph/ng_message.h> 8452419Sjulian#include <netgraph/netgraph.h> 8558015Sarchie#include <netgraph/ng_parse.h> 8652419Sjulian#include <netgraph/ng_iface.h> 8752419Sjulian#include <netgraph/ng_cisco.h> 8852419Sjulian 8970870Sjulian#ifdef NG_SEPARATE_MALLOC 90227293Sedstatic MALLOC_DEFINE(M_NETGRAPH_IFACE, "netgraph_iface", "netgraph iface node"); 9170870Sjulian#else 9270870Sjulian#define M_NETGRAPH_IFACE M_NETGRAPH 9370870Sjulian#endif 9470870Sjulian 9552419Sjulian/* This struct describes one address family */ 9652419Sjulianstruct iffam { 9758015Sarchie sa_family_t family; /* Address family */ 9858015Sarchie const char *hookname; /* Name for hook */ 9952419Sjulian}; 10052419Sjuliantypedef const struct iffam *iffam_p; 10152419Sjulian 10258015Sarchie/* List of address families supported by our interface */ 10352419Sjulianconst static struct iffam gFamilies[] = { 10458015Sarchie { AF_INET, NG_IFACE_HOOK_INET }, 10558015Sarchie { AF_INET6, NG_IFACE_HOOK_INET6 }, 10658015Sarchie { AF_APPLETALK, NG_IFACE_HOOK_ATALK }, 10758015Sarchie { AF_IPX, NG_IFACE_HOOK_IPX }, 10858015Sarchie { AF_ATM, NG_IFACE_HOOK_ATM }, 10958015Sarchie { AF_NATM, NG_IFACE_HOOK_NATM }, 11052419Sjulian}; 11152419Sjulian#define NUM_FAMILIES (sizeof(gFamilies) / sizeof(*gFamilies)) 11252419Sjulian 11352419Sjulian/* Node private data */ 11453393Sarchiestruct ng_iface_private { 11558015Sarchie struct ifnet *ifp; /* Our interface */ 11658015Sarchie int unit; /* Interface unit number */ 11752419Sjulian node_p node; /* Our netgraph node */ 11852419Sjulian hook_p hooks[NUM_FAMILIES]; /* Hook for each address family */ 11952419Sjulian}; 12053393Sarchietypedef struct ng_iface_private *priv_p; 12152419Sjulian 12252419Sjulian/* Interface methods */ 12352419Sjulianstatic void ng_iface_start(struct ifnet *ifp); 12452419Sjulianstatic int ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 12552419Sjulianstatic int ng_iface_output(struct ifnet *ifp, struct mbuf *m0, 126249925Sglebius const struct sockaddr *dst, struct route *ro); 12758015Sarchiestatic void ng_iface_bpftap(struct ifnet *ifp, 12858015Sarchie struct mbuf *m, sa_family_t family); 129151203Sglebiusstatic int ng_iface_send(struct ifnet *ifp, struct mbuf *m, 130151203Sglebius sa_family_t sa); 13152419Sjulian#ifdef DEBUG 13252419Sjulianstatic void ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data); 13352419Sjulian#endif 13452419Sjulian 13552419Sjulian/* Netgraph methods */ 136141341Srustatic int ng_iface_mod_event(module_t, int, void *); 13752752Sjulianstatic ng_constructor_t ng_iface_constructor; 13852752Sjulianstatic ng_rcvmsg_t ng_iface_rcvmsg; 13970700Sjulianstatic ng_shutdown_t ng_iface_shutdown; 14052752Sjulianstatic ng_newhook_t ng_iface_newhook; 14152752Sjulianstatic ng_rcvdata_t ng_iface_rcvdata; 14252752Sjulianstatic ng_disconnect_t ng_iface_disconnect; 14352419Sjulian 14452419Sjulian/* Helper stuff */ 14558015Sarchiestatic iffam_p get_iffam_from_af(sa_family_t family); 14652419Sjulianstatic iffam_p get_iffam_from_hook(priv_p priv, hook_p hook); 14752419Sjulianstatic iffam_p get_iffam_from_name(const char *name); 14852419Sjulianstatic hook_p *get_hook_from_iffam(priv_p priv, iffam_p iffam); 14952419Sjulian 15058015Sarchie/* Parse type for struct ng_cisco_ipaddr */ 15197685Sarchiestatic const struct ng_parse_struct_field ng_cisco_ipaddr_type_fields[] 15297685Sarchie = NG_CISCO_IPADDR_TYPE_INFO; 15358015Sarchiestatic const struct ng_parse_type ng_cisco_ipaddr_type = { 15458015Sarchie &ng_parse_struct_type, 15597685Sarchie &ng_cisco_ipaddr_type_fields 15658015Sarchie}; 15758015Sarchie 15858015Sarchie/* List of commands and how to convert arguments to/from ASCII */ 15958015Sarchiestatic const struct ng_cmdlist ng_iface_cmds[] = { 16058015Sarchie { 16158015Sarchie NGM_IFACE_COOKIE, 16258015Sarchie NGM_IFACE_GET_IFNAME, 16358015Sarchie "getifname", 16458015Sarchie NULL, 165141197Sru &ng_parse_string_type 16658015Sarchie }, 16758015Sarchie { 16858015Sarchie NGM_IFACE_COOKIE, 16958015Sarchie NGM_IFACE_POINT2POINT, 17058015Sarchie "point2point", 17158015Sarchie NULL, 17258015Sarchie NULL 17358015Sarchie }, 17458015Sarchie { 17558015Sarchie NGM_IFACE_COOKIE, 17658015Sarchie NGM_IFACE_BROADCAST, 17758015Sarchie "broadcast", 17858015Sarchie NULL, 17958015Sarchie NULL 18058015Sarchie }, 18158015Sarchie { 18258015Sarchie NGM_CISCO_COOKIE, 18358015Sarchie NGM_CISCO_GET_IPADDR, 18458015Sarchie "getipaddr", 18558015Sarchie NULL, 18658015Sarchie &ng_cisco_ipaddr_type 18758015Sarchie }, 188126730Sru { 189126730Sru NGM_IFACE_COOKIE, 190126730Sru NGM_IFACE_GET_IFINDEX, 191126730Sru "getifindex", 192126730Sru NULL, 193126730Sru &ng_parse_uint32_type 194126730Sru }, 19558015Sarchie { 0 } 19658015Sarchie}; 19758015Sarchie 19852419Sjulian/* Node type descriptor */ 19952419Sjulianstatic struct ng_type typestruct = { 200129823Sjulian .version = NG_ABI_VERSION, 201129823Sjulian .name = NG_IFACE_NODE_TYPE, 202141341Sru .mod_event = ng_iface_mod_event, 203129823Sjulian .constructor = ng_iface_constructor, 204129823Sjulian .rcvmsg = ng_iface_rcvmsg, 205129823Sjulian .shutdown = ng_iface_shutdown, 206129823Sjulian .newhook = ng_iface_newhook, 207129823Sjulian .rcvdata = ng_iface_rcvdata, 208129823Sjulian .disconnect = ng_iface_disconnect, 209129823Sjulian .cmdlist = ng_iface_cmds, 21052419Sjulian}; 21152419SjulianNETGRAPH_INIT(iface, &typestruct); 21252419Sjulian 213215701Sdimstatic VNET_DEFINE(struct unrhdr *, ng_iface_unit); 214195727Srwatson#define V_ng_iface_unit VNET(ng_iface_unit) 21552419Sjulian 21652419Sjulian/************************************************************************ 21752419Sjulian HELPER STUFF 21852419Sjulian ************************************************************************/ 21952419Sjulian 22052419Sjulian/* 22152419Sjulian * Get the family descriptor from the family ID 22252419Sjulian */ 223131575Sstefanfstatic __inline iffam_p 22458015Sarchieget_iffam_from_af(sa_family_t family) 22552419Sjulian{ 22652419Sjulian iffam_p iffam; 22752419Sjulian int k; 22852419Sjulian 22952419Sjulian for (k = 0; k < NUM_FAMILIES; k++) { 23052419Sjulian iffam = &gFamilies[k]; 23158015Sarchie if (iffam->family == family) 23252419Sjulian return (iffam); 23352419Sjulian } 23452419Sjulian return (NULL); 23552419Sjulian} 23652419Sjulian 23752419Sjulian/* 23852419Sjulian * Get the family descriptor from the hook 23952419Sjulian */ 240131575Sstefanfstatic __inline iffam_p 24152419Sjulianget_iffam_from_hook(priv_p priv, hook_p hook) 24252419Sjulian{ 24352419Sjulian int k; 24452419Sjulian 24552419Sjulian for (k = 0; k < NUM_FAMILIES; k++) 24652419Sjulian if (priv->hooks[k] == hook) 24752419Sjulian return (&gFamilies[k]); 24852419Sjulian return (NULL); 24952419Sjulian} 25052419Sjulian 25152419Sjulian/* 25252419Sjulian * Get the hook from the iffam descriptor 25352419Sjulian */ 25452419Sjulian 255131575Sstefanfstatic __inline hook_p * 25652419Sjulianget_hook_from_iffam(priv_p priv, iffam_p iffam) 25752419Sjulian{ 25852419Sjulian return (&priv->hooks[iffam - gFamilies]); 25952419Sjulian} 26052419Sjulian 26152419Sjulian/* 26252419Sjulian * Get the iffam descriptor from the name 26352419Sjulian */ 264131575Sstefanfstatic __inline iffam_p 26552419Sjulianget_iffam_from_name(const char *name) 26652419Sjulian{ 26752419Sjulian iffam_p iffam; 26852419Sjulian int k; 26952419Sjulian 27052419Sjulian for (k = 0; k < NUM_FAMILIES; k++) { 27152419Sjulian iffam = &gFamilies[k]; 27252419Sjulian if (!strcmp(iffam->hookname, name)) 27352419Sjulian return (iffam); 27452419Sjulian } 27552419Sjulian return (NULL); 27652419Sjulian} 27752419Sjulian 27852419Sjulian/************************************************************************ 27952419Sjulian INTERFACE STUFF 28052419Sjulian ************************************************************************/ 28152419Sjulian 28252419Sjulian/* 28352419Sjulian * Process an ioctl for the virtual interface 28452419Sjulian */ 28552419Sjulianstatic int 28652419Sjulianng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 28752419Sjulian{ 28852419Sjulian struct ifreq *const ifr = (struct ifreq *) data; 289219781Sglebius int error = 0; 29052419Sjulian 29152419Sjulian#ifdef DEBUG 29252419Sjulian ng_iface_print_ioctl(ifp, command, data); 29352419Sjulian#endif 29452419Sjulian switch (command) { 29552419Sjulian 29652419Sjulian /* These two are mostly handled at a higher layer */ 29752419Sjulian case SIOCSIFADDR: 298148887Srwatson ifp->if_flags |= IFF_UP; 299148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 300148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 30152419Sjulian break; 30252419Sjulian case SIOCGIFADDR: 30352419Sjulian break; 30452419Sjulian 30552419Sjulian /* Set flags */ 30652419Sjulian case SIOCSIFFLAGS: 30752419Sjulian /* 30852419Sjulian * If the interface is marked up and stopped, then start it. 30952419Sjulian * If it is marked down and running, then stop it. 31052419Sjulian */ 31152419Sjulian if (ifr->ifr_flags & IFF_UP) { 312148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 313148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 314148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 31552419Sjulian } 31652419Sjulian } else { 317148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 318148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | 319148887Srwatson IFF_DRV_OACTIVE); 32052419Sjulian } 32152419Sjulian break; 32252419Sjulian 32352419Sjulian /* Set the interface MTU */ 32452419Sjulian case SIOCSIFMTU: 32552419Sjulian if (ifr->ifr_mtu > NG_IFACE_MTU_MAX 32652419Sjulian || ifr->ifr_mtu < NG_IFACE_MTU_MIN) 32752419Sjulian error = EINVAL; 32852419Sjulian else 32952419Sjulian ifp->if_mtu = ifr->ifr_mtu; 33052419Sjulian break; 33152419Sjulian 33252419Sjulian /* Stuff that's not supported */ 33352419Sjulian case SIOCADDMULTI: 33452419Sjulian case SIOCDELMULTI: 33552975Sarchie error = 0; 33652975Sarchie break; 33752419Sjulian case SIOCSIFPHYS: 33852419Sjulian error = EOPNOTSUPP; 33952419Sjulian break; 34052419Sjulian 34152419Sjulian default: 34252419Sjulian error = EINVAL; 34352419Sjulian break; 34452419Sjulian } 34552419Sjulian return (error); 34652419Sjulian} 34752419Sjulian 34852419Sjulian/* 34952419Sjulian * This routine is called to deliver a packet out the interface. 35052419Sjulian * We simply look at the address family and relay the packet to 35152419Sjulian * the corresponding hook, if it exists and is connected. 35252419Sjulian */ 35352419Sjulian 35452419Sjulianstatic int 35552419Sjulianng_iface_output(struct ifnet *ifp, struct mbuf *m, 356249925Sglebius const struct sockaddr *dst, struct route *ro) 35752419Sjulian{ 358187495Smav struct m_tag *mtag; 359151203Sglebius uint32_t af; 360151231Sglebius int error; 36152419Sjulian 36252419Sjulian /* Check interface flags */ 363148887Srwatson if (!((ifp->if_flags & IFF_UP) && 364148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) { 36552419Sjulian m_freem(m); 36652419Sjulian return (ENETDOWN); 36752419Sjulian } 36852419Sjulian 369187495Smav /* Protect from deadly infinite recursion. */ 370195231Smav mtag = NULL; 371195231Smav while ((mtag = m_tag_locate(m, MTAG_NGIF, MTAG_NGIF_CALLED, mtag))) { 372187495Smav if (*(struct ifnet **)(mtag + 1) == ifp) { 373187495Smav log(LOG_NOTICE, "Loop detected on %s\n", ifp->if_xname); 374187495Smav m_freem(m); 375187495Smav return (EDEADLK); 376187495Smav } 377187495Smav } 378187495Smav mtag = m_tag_alloc(MTAG_NGIF, MTAG_NGIF_CALLED, sizeof(struct ifnet *), 379187495Smav M_NOWAIT); 380187495Smav if (mtag == NULL) { 381187495Smav m_freem(m); 382187495Smav return (ENOMEM); 383187495Smav } 384187495Smav *(struct ifnet **)(mtag + 1) = ifp; 385187495Smav m_tag_prepend(m, mtag); 386187495Smav 387147611Sdwmalone /* BPF writes need to be handled specially. */ 388249925Sglebius if (dst->sa_family == AF_UNSPEC) 389147611Sdwmalone bcopy(dst->sa_data, &af, sizeof(af)); 390249925Sglebius else 391249925Sglebius af = dst->sa_family; 39258015Sarchie 39352419Sjulian /* Berkeley packet filter */ 394249925Sglebius ng_iface_bpftap(ifp, m, af); 39552419Sjulian 396151203Sglebius if (ALTQ_IS_ENABLED(&ifp->if_snd)) { 397243882Sglebius M_PREPEND(m, sizeof(sa_family_t), M_NOWAIT); 398151203Sglebius if (m == NULL) { 399151231Sglebius IFQ_LOCK(&ifp->if_snd); 400151231Sglebius IFQ_INC_DROPS(&ifp->if_snd); 401151231Sglebius IFQ_UNLOCK(&ifp->if_snd); 402151203Sglebius ifp->if_oerrors++; 403151203Sglebius return (ENOBUFS); 404151203Sglebius } 405249925Sglebius *(sa_family_t *)m->m_data = af; 406185164Skmacy error = (ifp->if_transmit)(ifp, m); 407151203Sglebius } else 408249925Sglebius error = ng_iface_send(ifp, m, af); 40952419Sjulian 41052419Sjulian return (error); 41152419Sjulian} 41252419Sjulian 41352419Sjulian/* 414151231Sglebius * Start method is used only when ALTQ is enabled. 41552419Sjulian */ 41652419Sjulianstatic void 41752419Sjulianng_iface_start(struct ifnet *ifp) 41852419Sjulian{ 419151203Sglebius struct mbuf *m; 420151203Sglebius sa_family_t sa; 421151203Sglebius 422151231Sglebius KASSERT(ALTQ_IS_ENABLED(&ifp->if_snd), ("%s without ALTQ", __func__)); 423151203Sglebius 424151231Sglebius for(;;) { 425151203Sglebius IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 426151203Sglebius if (m == NULL) 427151203Sglebius break; 428151203Sglebius sa = *mtod(m, sa_family_t *); 429151203Sglebius m_adj(m, sizeof(sa_family_t)); 430151203Sglebius ng_iface_send(ifp, m, sa); 431151203Sglebius } 43252419Sjulian} 43352419Sjulian 43452419Sjulian/* 43552419Sjulian * Flash a packet by the BPF (requires prepending 4 byte AF header) 43652419Sjulian * Note the phoney mbuf; this is OK because BPF treats it read-only. 43752419Sjulian */ 43852419Sjulianstatic void 43958015Sarchieng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family) 44052419Sjulian{ 44187599Sobrien KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __func__)); 442159183Ssam if (bpf_peers_present(ifp->if_bpf)) { 443123922Ssam int32_t family4 = (int32_t)family; 444123922Ssam bpf_mtap2(ifp->if_bpf, &family4, sizeof(family4), m); 44552419Sjulian } 44652419Sjulian} 44752419Sjulian 448151203Sglebius/* 449151203Sglebius * This routine does actual delivery of the packet into the 450151203Sglebius * netgraph(4). It is called from ng_iface_start() and 451151231Sglebius * ng_iface_output(). 452151203Sglebius */ 453151203Sglebiusstatic int 454151203Sglebiusng_iface_send(struct ifnet *ifp, struct mbuf *m, sa_family_t sa) 455151203Sglebius{ 456151203Sglebius const priv_p priv = (priv_p) ifp->if_softc; 457151203Sglebius const iffam_p iffam = get_iffam_from_af(sa); 458151231Sglebius int error; 459151203Sglebius int len; 460151203Sglebius 461151203Sglebius /* Check address family to determine hook (if known) */ 462151203Sglebius if (iffam == NULL) { 463151203Sglebius m_freem(m); 464151203Sglebius log(LOG_WARNING, "%s: can't handle af%d\n", ifp->if_xname, sa); 465151203Sglebius return (EAFNOSUPPORT); 466151203Sglebius } 467151203Sglebius 468151203Sglebius /* Copy length before the mbuf gets invalidated. */ 469151203Sglebius len = m->m_pkthdr.len; 470151203Sglebius 471194012Szec /* Send packet. If hook is not connected, mbuf will get freed. */ 472194012Szec NG_OUTBOUND_THREAD_REF(); 473151203Sglebius NG_SEND_DATA_ONLY(error, *get_hook_from_iffam(priv, iffam), m); 474194012Szec NG_OUTBOUND_THREAD_UNREF(); 475151203Sglebius 476151203Sglebius /* Update stats. */ 477151203Sglebius if (error == 0) { 478151203Sglebius ifp->if_obytes += len; 479151203Sglebius ifp->if_opackets++; 480151203Sglebius } 481151203Sglebius 482151203Sglebius return (error); 483151203Sglebius} 484151203Sglebius 48552419Sjulian#ifdef DEBUG 48652419Sjulian/* 48752419Sjulian * Display an ioctl to the virtual interface 48852419Sjulian */ 48952419Sjulian 49052419Sjulianstatic void 49152419Sjulianng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data) 49252419Sjulian{ 49352419Sjulian char *str; 49452419Sjulian 49552419Sjulian switch (command & IOC_DIRMASK) { 49652419Sjulian case IOC_VOID: 49752419Sjulian str = "IO"; 49852419Sjulian break; 49952419Sjulian case IOC_OUT: 50052419Sjulian str = "IOR"; 50152419Sjulian break; 50252419Sjulian case IOC_IN: 50352419Sjulian str = "IOW"; 50452419Sjulian break; 50552419Sjulian case IOC_INOUT: 50652419Sjulian str = "IORW"; 50752419Sjulian break; 50852419Sjulian default: 50952419Sjulian str = "IO??"; 51052419Sjulian } 511121816Sbrooks log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n", 512121816Sbrooks ifp->if_xname, 51352419Sjulian str, 51452419Sjulian IOCGROUP(command), 51552419Sjulian command & 0xff, 51652419Sjulian IOCPARM_LEN(command)); 51752419Sjulian} 51852419Sjulian#endif /* DEBUG */ 51952419Sjulian 52052419Sjulian/************************************************************************ 52152419Sjulian NETGRAPH NODE STUFF 52252419Sjulian ************************************************************************/ 52352419Sjulian 52452419Sjulian/* 52552419Sjulian * Constructor for a node 52652419Sjulian */ 52752419Sjulianstatic int 52870700Sjulianng_iface_constructor(node_p node) 52952419Sjulian{ 53052419Sjulian struct ifnet *ifp; 53152419Sjulian priv_p priv; 53252419Sjulian 53352419Sjulian /* Allocate node and interface private structures */ 534220768Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH_IFACE, M_WAITOK | M_ZERO); 535147256Sbrooks ifp = if_alloc(IFT_PROPVIRTUAL); 53652419Sjulian if (ifp == NULL) { 537184205Sdes free(priv, M_NETGRAPH_IFACE); 53852419Sjulian return (ENOMEM); 53952419Sjulian } 54052419Sjulian 54152419Sjulian /* Link them together */ 54252419Sjulian ifp->if_softc = priv; 54352419Sjulian priv->ifp = ifp; 54452419Sjulian 54558015Sarchie /* Get an interface unit number */ 546181803Sbz priv->unit = alloc_unr(V_ng_iface_unit); 54758015Sarchie 54852419Sjulian /* Link together node and private info */ 54970784Sjulian NG_NODE_SET_PRIVATE(node, priv); 55052419Sjulian priv->node = node; 55152419Sjulian 55252419Sjulian /* Initialize interface structure */ 553121816Sbrooks if_initname(ifp, NG_IFACE_IFACE_NAME, priv->unit); 55452419Sjulian ifp->if_output = ng_iface_output; 55552419Sjulian ifp->if_start = ng_iface_start; 55652419Sjulian ifp->if_ioctl = ng_iface_ioctl; 55752419Sjulian ifp->if_mtu = NG_IFACE_MTU_DEFAULT; 55858015Sarchie ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST); 55952419Sjulian ifp->if_type = IFT_PROPVIRTUAL; /* XXX */ 56052419Sjulian ifp->if_addrlen = 0; /* XXX */ 56152419Sjulian ifp->if_hdrlen = 0; /* XXX */ 56252419Sjulian ifp->if_baudrate = 64000; /* XXX */ 563207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 564207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 565151203Sglebius IFQ_SET_READY(&ifp->if_snd); 56652419Sjulian 56752419Sjulian /* Give this node the same name as the interface (if possible) */ 568141197Sru if (ng_name_node(node, ifp->if_xname) != 0) 569141197Sru log(LOG_WARNING, "%s: can't acquire netgraph name\n", 570141197Sru ifp->if_xname); 57152419Sjulian 57252419Sjulian /* Attach the interface */ 57352419Sjulian if_attach(ifp); 574147611Sdwmalone bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 57552419Sjulian 57652419Sjulian /* Done */ 57752419Sjulian return (0); 57852419Sjulian} 57952419Sjulian 58052419Sjulian/* 58152419Sjulian * Give our ok for a hook to be added 58252419Sjulian */ 58352419Sjulianstatic int 58452419Sjulianng_iface_newhook(node_p node, hook_p hook, const char *name) 58552419Sjulian{ 58652419Sjulian const iffam_p iffam = get_iffam_from_name(name); 58752419Sjulian hook_p *hookptr; 58852419Sjulian 58952419Sjulian if (iffam == NULL) 59052419Sjulian return (EPFNOSUPPORT); 59170784Sjulian hookptr = get_hook_from_iffam(NG_NODE_PRIVATE(node), iffam); 59252419Sjulian if (*hookptr != NULL) 59352419Sjulian return (EISCONN); 59452419Sjulian *hookptr = hook; 595175847Smav NG_HOOK_HI_STACK(hook); 596194012Szec NG_HOOK_SET_TO_INBOUND(hook); 59752419Sjulian return (0); 59852419Sjulian} 59952419Sjulian 60052419Sjulian/* 60152419Sjulian * Receive a control message 60252419Sjulian */ 60352419Sjulianstatic int 60470700Sjulianng_iface_rcvmsg(node_p node, item_p item, hook_p lasthook) 60552419Sjulian{ 60670784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 60752419Sjulian struct ifnet *const ifp = priv->ifp; 60852419Sjulian struct ng_mesg *resp = NULL; 60952419Sjulian int error = 0; 61070700Sjulian struct ng_mesg *msg; 61152419Sjulian 61270700Sjulian NGI_GET_MSG(item, msg); 61352419Sjulian switch (msg->header.typecookie) { 61452419Sjulian case NGM_IFACE_COOKIE: 61552419Sjulian switch (msg->header.cmd) { 61652419Sjulian case NGM_IFACE_GET_IFNAME: 617141197Sru NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT); 61852419Sjulian if (resp == NULL) { 61952419Sjulian error = ENOMEM; 62052419Sjulian break; 62152419Sjulian } 622141197Sru strlcpy(resp->data, ifp->if_xname, IFNAMSIZ); 62352419Sjulian break; 62452419Sjulian 62558015Sarchie case NGM_IFACE_POINT2POINT: 62658015Sarchie case NGM_IFACE_BROADCAST: 62752419Sjulian { 62852419Sjulian 62958015Sarchie /* Deny request if interface is UP */ 63058015Sarchie if ((ifp->if_flags & IFF_UP) != 0) 63158015Sarchie return (EBUSY); 63252419Sjulian 63358015Sarchie /* Change flags */ 63458015Sarchie switch (msg->header.cmd) { 63558015Sarchie case NGM_IFACE_POINT2POINT: 63658015Sarchie ifp->if_flags |= IFF_POINTOPOINT; 63758015Sarchie ifp->if_flags &= ~IFF_BROADCAST; 63852419Sjulian break; 63958015Sarchie case NGM_IFACE_BROADCAST: 64058015Sarchie ifp->if_flags &= ~IFF_POINTOPOINT; 64158015Sarchie ifp->if_flags |= IFF_BROADCAST; 64258015Sarchie break; 64352419Sjulian } 64452419Sjulian break; 64552419Sjulian } 64652419Sjulian 647126730Sru case NGM_IFACE_GET_IFINDEX: 648126730Sru NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); 649126730Sru if (resp == NULL) { 650126730Sru error = ENOMEM; 651126730Sru break; 652126730Sru } 653126730Sru *((uint32_t *)resp->data) = priv->ifp->if_index; 654126730Sru break; 655126730Sru 65652419Sjulian default: 65752419Sjulian error = EINVAL; 65852419Sjulian break; 65952419Sjulian } 66052419Sjulian break; 66152419Sjulian case NGM_CISCO_COOKIE: 66252419Sjulian switch (msg->header.cmd) { 66352419Sjulian case NGM_CISCO_GET_IPADDR: /* we understand this too */ 66452419Sjulian { 66552419Sjulian struct ifaddr *ifa; 66652419Sjulian 66752419Sjulian /* Return the first configured IP address */ 668195024Srwatson if_addr_rlock(ifp); 66952419Sjulian TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 67058015Sarchie struct ng_cisco_ipaddr *ips; 67152419Sjulian 67252419Sjulian if (ifa->ifa_addr->sa_family != AF_INET) 67352419Sjulian continue; 67458015Sarchie NG_MKRESPONSE(resp, msg, sizeof(ips), M_NOWAIT); 67552419Sjulian if (resp == NULL) { 67652419Sjulian error = ENOMEM; 67752419Sjulian break; 67852419Sjulian } 67958015Sarchie ips = (struct ng_cisco_ipaddr *)resp->data; 68058015Sarchie ips->ipaddr = ((struct sockaddr_in *) 68152419Sjulian ifa->ifa_addr)->sin_addr; 68258015Sarchie ips->netmask = ((struct sockaddr_in *) 68352419Sjulian ifa->ifa_netmask)->sin_addr; 68452419Sjulian break; 68552419Sjulian } 686195024Srwatson if_addr_runlock(ifp); 68752419Sjulian 68852419Sjulian /* No IP addresses on this interface? */ 68952419Sjulian if (ifa == NULL) 69052419Sjulian error = EADDRNOTAVAIL; 69152419Sjulian break; 69252419Sjulian } 69352419Sjulian default: 69452419Sjulian error = EINVAL; 69552419Sjulian break; 69652419Sjulian } 69752419Sjulian break; 698138011Sglebius case NGM_FLOW_COOKIE: 699138011Sglebius switch (msg->header.cmd) { 700138011Sglebius case NGM_LINK_IS_UP: 701148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 702138011Sglebius break; 703138011Sglebius case NGM_LINK_IS_DOWN: 704148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 705138011Sglebius break; 706138011Sglebius default: 707138011Sglebius break; 708138011Sglebius } 709138011Sglebius break; 71052419Sjulian default: 71152419Sjulian error = EINVAL; 71252419Sjulian break; 71352419Sjulian } 71470700Sjulian NG_RESPOND_MSG(error, node, item, resp); 71570700Sjulian NG_FREE_MSG(msg); 71652419Sjulian return (error); 71752419Sjulian} 71852419Sjulian 71952419Sjulian/* 72052419Sjulian * Recive data from a hook. Pass the packet to the correct input routine. 72152419Sjulian */ 72252419Sjulianstatic int 72370700Sjulianng_iface_rcvdata(hook_p hook, item_p item) 72452419Sjulian{ 72570784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 72652419Sjulian const iffam_p iffam = get_iffam_from_hook(priv, hook); 72752419Sjulian struct ifnet *const ifp = priv->ifp; 72870700Sjulian struct mbuf *m; 729111888Sjlemon int isr; 73052419Sjulian 73170700Sjulian NGI_GET_M(item, m); 73270700Sjulian NG_FREE_ITEM(item); 73352419Sjulian /* Sanity checks */ 73487599Sobrien KASSERT(iffam != NULL, ("%s: iffam", __func__)); 735113255Sdes M_ASSERTPKTHDR(m); 73652419Sjulian if ((ifp->if_flags & IFF_UP) == 0) { 73770700Sjulian NG_FREE_M(m); 73852419Sjulian return (ENETDOWN); 73952419Sjulian } 74052419Sjulian 74152419Sjulian /* Update interface stats */ 74252419Sjulian ifp->if_ipackets++; 74352419Sjulian ifp->if_ibytes += m->m_pkthdr.len; 74452419Sjulian 74552419Sjulian /* Note receiving interface */ 74652419Sjulian m->m_pkthdr.rcvif = ifp; 74752419Sjulian 74852419Sjulian /* Berkeley packet filter */ 74958015Sarchie ng_iface_bpftap(ifp, m, iffam->family); 75052419Sjulian 75158015Sarchie /* Send packet */ 752111888Sjlemon switch (iffam->family) { 753111888Sjlemon#ifdef INET 754111888Sjlemon case AF_INET: 755111888Sjlemon isr = NETISR_IP; 756111888Sjlemon break; 757111888Sjlemon#endif 758111888Sjlemon#ifdef INET6 759111888Sjlemon case AF_INET6: 760111888Sjlemon isr = NETISR_IPV6; 761111888Sjlemon break; 762111888Sjlemon#endif 763111888Sjlemon#ifdef IPX 764111888Sjlemon case AF_IPX: 765111888Sjlemon isr = NETISR_IPX; 766111888Sjlemon break; 767111888Sjlemon#endif 768111888Sjlemon#ifdef NETATALK 769111888Sjlemon case AF_APPLETALK: 770111888Sjlemon isr = NETISR_ATALK2; 771111888Sjlemon break; 772111888Sjlemon#endif 773111888Sjlemon default: 774111888Sjlemon m_freem(m); 775111888Sjlemon return (EAFNOSUPPORT); 776111888Sjlemon } 777111888Sjlemon if (harvest.point_to_point) 778256381Smarkm random_harvest(&(m->m_data), 12, 2, RANDOM_NET_NG); 779223741Sbz M_SETFIB(m, ifp->if_fib); 780180372Sgonzo netisr_dispatch(isr, m); 781111888Sjlemon return (0); 78252419Sjulian} 78352419Sjulian 78452419Sjulian/* 78558015Sarchie * Shutdown and remove the node and its associated interface. 78652419Sjulian */ 78752419Sjulianstatic int 78870700Sjulianng_iface_shutdown(node_p node) 78952419Sjulian{ 79070784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 79152419Sjulian 792183550Szec /* 793183550Szec * The ifnet may be in a different vnet than the netgraph node, 794183550Szec * hence we have to change the current vnet context here. 795183550Szec */ 796183550Szec CURVNET_SET_QUIET(priv->ifp->if_vnet); 79758412Sarchie bpfdetach(priv->ifp); 79858015Sarchie if_detach(priv->ifp); 799147256Sbrooks if_free(priv->ifp); 800183550Szec CURVNET_RESTORE(); 80158015Sarchie priv->ifp = NULL; 802181803Sbz free_unr(V_ng_iface_unit, priv->unit); 803184205Sdes free(priv, M_NETGRAPH_IFACE); 80470784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 80570784Sjulian NG_NODE_UNREF(node); 80652419Sjulian return (0); 80752419Sjulian} 80852419Sjulian 80952419Sjulian/* 81058015Sarchie * Hook disconnection. Note that we do *not* shutdown when all 81158015Sarchie * hooks have been disconnected. 81252419Sjulian */ 81352419Sjulianstatic int 81452419Sjulianng_iface_disconnect(hook_p hook) 81552419Sjulian{ 81670784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 81752419Sjulian const iffam_p iffam = get_iffam_from_hook(priv, hook); 81852419Sjulian 81952419Sjulian if (iffam == NULL) 820213794Srpaulo panic("%s", __func__); 82152419Sjulian *get_hook_from_iffam(priv, iffam) = NULL; 82252419Sjulian return (0); 82352419Sjulian} 82452419Sjulian 825141341Sru/* 826141341Sru * Handle loading and unloading for this node type. 827141341Sru */ 828141341Srustatic int 829141341Srung_iface_mod_event(module_t mod, int event, void *data) 830141341Sru{ 831141341Sru int error = 0; 832141341Sru 833141341Sru switch (event) { 834141341Sru case MOD_LOAD: 835141341Sru case MOD_UNLOAD: 836141341Sru break; 837141341Sru default: 838141341Sru error = EOPNOTSUPP; 839141341Sru break; 840141341Sru } 841141341Sru return (error); 842141341Sru} 843191510Szec 844195837Srwatsonstatic void 845195837Srwatsonvnet_ng_iface_init(const void *unused) 846191510Szec{ 847191510Szec 848191510Szec V_ng_iface_unit = new_unrhdr(0, 0xffff, NULL); 849191510Szec} 850195837SrwatsonVNET_SYSINIT(vnet_ng_iface_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 851195837Srwatson vnet_ng_iface_init, NULL); 852191510Szec 853195837Srwatsonstatic void 854195837Srwatsonvnet_ng_iface_uninit(const void *unused) 855191510Szec{ 856191510Szec 857191510Szec delete_unrhdr(V_ng_iface_unit); 858191510Szec} 859195837SrwatsonVNET_SYSUNINIT(vnet_ng_iface_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, 860195837Srwatson vnet_ng_iface_uninit, NULL); 861