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: stable/10/sys/netgraph/ng_iface.c 324176 2017-10-01 19:40:29Z eugen $ 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> 64324176Seugen#include <sys/lock.h> 6552419Sjulian#include <sys/malloc.h> 6652419Sjulian#include <sys/mbuf.h> 6752419Sjulian#include <sys/errno.h> 68196019Srwatson#include <sys/proc.h> 69111888Sjlemon#include <sys/random.h> 70324176Seugen#include <sys/rmlock.h> 7152419Sjulian#include <sys/sockio.h> 7252419Sjulian#include <sys/socket.h> 7352419Sjulian#include <sys/syslog.h> 7458015Sarchie#include <sys/libkern.h> 7552419Sjulian 7652419Sjulian#include <net/if.h> 7752419Sjulian#include <net/if_types.h> 7858015Sarchie#include <net/bpf.h> 79111888Sjlemon#include <net/netisr.h> 80191148Skmacy#include <net/route.h> 81195837Srwatson#include <net/vnet.h> 8252419Sjulian 8353913Sarchie#include <netinet/in.h> 8453913Sarchie 8552419Sjulian#include <netgraph/ng_message.h> 8652419Sjulian#include <netgraph/netgraph.h> 8758015Sarchie#include <netgraph/ng_parse.h> 8852419Sjulian#include <netgraph/ng_iface.h> 8952419Sjulian#include <netgraph/ng_cisco.h> 9052419Sjulian 9170870Sjulian#ifdef NG_SEPARATE_MALLOC 92227293Sedstatic MALLOC_DEFINE(M_NETGRAPH_IFACE, "netgraph_iface", "netgraph iface node"); 9370870Sjulian#else 9470870Sjulian#define M_NETGRAPH_IFACE M_NETGRAPH 9570870Sjulian#endif 9670870Sjulian 9752419Sjulian/* This struct describes one address family */ 9852419Sjulianstruct iffam { 9958015Sarchie sa_family_t family; /* Address family */ 10058015Sarchie const char *hookname; /* Name for hook */ 10152419Sjulian}; 10252419Sjuliantypedef const struct iffam *iffam_p; 10352419Sjulian 10458015Sarchie/* List of address families supported by our interface */ 10552419Sjulianconst static struct iffam gFamilies[] = { 10658015Sarchie { AF_INET, NG_IFACE_HOOK_INET }, 10758015Sarchie { AF_INET6, NG_IFACE_HOOK_INET6 }, 10858015Sarchie { AF_APPLETALK, NG_IFACE_HOOK_ATALK }, 10958015Sarchie { AF_IPX, NG_IFACE_HOOK_IPX }, 11058015Sarchie { AF_ATM, NG_IFACE_HOOK_ATM }, 11158015Sarchie { AF_NATM, NG_IFACE_HOOK_NATM }, 11252419Sjulian}; 11352419Sjulian#define NUM_FAMILIES (sizeof(gFamilies) / sizeof(*gFamilies)) 11452419Sjulian 11552419Sjulian/* Node private data */ 11653393Sarchiestruct ng_iface_private { 11758015Sarchie struct ifnet *ifp; /* Our interface */ 11858015Sarchie int unit; /* Interface unit number */ 11952419Sjulian node_p node; /* Our netgraph node */ 12052419Sjulian hook_p hooks[NUM_FAMILIES]; /* Hook for each address family */ 121324176Seugen struct rmlock lock; /* Protect private data changes */ 12252419Sjulian}; 12353393Sarchietypedef struct ng_iface_private *priv_p; 12452419Sjulian 125324176Seugen#define PRIV_RLOCK(priv, t) rm_rlock(&priv->lock, t) 126324176Seugen#define PRIV_RUNLOCK(priv, t) rm_runlock(&priv->lock, t) 127324176Seugen#define PRIV_WLOCK(priv) rm_wlock(&priv->lock) 128324176Seugen#define PRIV_WUNLOCK(priv) rm_wunlock(&priv->lock) 129324176Seugen 13052419Sjulian/* Interface methods */ 13152419Sjulianstatic void ng_iface_start(struct ifnet *ifp); 13252419Sjulianstatic int ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 13352419Sjulianstatic int ng_iface_output(struct ifnet *ifp, struct mbuf *m0, 134249925Sglebius const struct sockaddr *dst, struct route *ro); 13558015Sarchiestatic void ng_iface_bpftap(struct ifnet *ifp, 13658015Sarchie struct mbuf *m, sa_family_t family); 137151203Sglebiusstatic int ng_iface_send(struct ifnet *ifp, struct mbuf *m, 138151203Sglebius sa_family_t sa); 13952419Sjulian#ifdef DEBUG 14052419Sjulianstatic void ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data); 14152419Sjulian#endif 14252419Sjulian 14352419Sjulian/* Netgraph methods */ 144141341Srustatic int ng_iface_mod_event(module_t, int, void *); 14552752Sjulianstatic ng_constructor_t ng_iface_constructor; 14652752Sjulianstatic ng_rcvmsg_t ng_iface_rcvmsg; 14770700Sjulianstatic ng_shutdown_t ng_iface_shutdown; 14852752Sjulianstatic ng_newhook_t ng_iface_newhook; 14952752Sjulianstatic ng_rcvdata_t ng_iface_rcvdata; 15052752Sjulianstatic ng_disconnect_t ng_iface_disconnect; 15152419Sjulian 15252419Sjulian/* Helper stuff */ 15358015Sarchiestatic iffam_p get_iffam_from_af(sa_family_t family); 15452419Sjulianstatic iffam_p get_iffam_from_hook(priv_p priv, hook_p hook); 15552419Sjulianstatic iffam_p get_iffam_from_name(const char *name); 15652419Sjulianstatic hook_p *get_hook_from_iffam(priv_p priv, iffam_p iffam); 15752419Sjulian 15858015Sarchie/* Parse type for struct ng_cisco_ipaddr */ 15997685Sarchiestatic const struct ng_parse_struct_field ng_cisco_ipaddr_type_fields[] 16097685Sarchie = NG_CISCO_IPADDR_TYPE_INFO; 16158015Sarchiestatic const struct ng_parse_type ng_cisco_ipaddr_type = { 16258015Sarchie &ng_parse_struct_type, 16397685Sarchie &ng_cisco_ipaddr_type_fields 16458015Sarchie}; 16558015Sarchie 16658015Sarchie/* List of commands and how to convert arguments to/from ASCII */ 16758015Sarchiestatic const struct ng_cmdlist ng_iface_cmds[] = { 16858015Sarchie { 16958015Sarchie NGM_IFACE_COOKIE, 17058015Sarchie NGM_IFACE_GET_IFNAME, 17158015Sarchie "getifname", 17258015Sarchie NULL, 173141197Sru &ng_parse_string_type 17458015Sarchie }, 17558015Sarchie { 17658015Sarchie NGM_IFACE_COOKIE, 17758015Sarchie NGM_IFACE_POINT2POINT, 17858015Sarchie "point2point", 17958015Sarchie NULL, 18058015Sarchie NULL 18158015Sarchie }, 18258015Sarchie { 18358015Sarchie NGM_IFACE_COOKIE, 18458015Sarchie NGM_IFACE_BROADCAST, 18558015Sarchie "broadcast", 18658015Sarchie NULL, 18758015Sarchie NULL 18858015Sarchie }, 18958015Sarchie { 19058015Sarchie NGM_CISCO_COOKIE, 19158015Sarchie NGM_CISCO_GET_IPADDR, 19258015Sarchie "getipaddr", 19358015Sarchie NULL, 19458015Sarchie &ng_cisco_ipaddr_type 19558015Sarchie }, 196126730Sru { 197126730Sru NGM_IFACE_COOKIE, 198126730Sru NGM_IFACE_GET_IFINDEX, 199126730Sru "getifindex", 200126730Sru NULL, 201126730Sru &ng_parse_uint32_type 202126730Sru }, 20358015Sarchie { 0 } 20458015Sarchie}; 20558015Sarchie 20652419Sjulian/* Node type descriptor */ 20752419Sjulianstatic struct ng_type typestruct = { 208129823Sjulian .version = NG_ABI_VERSION, 209129823Sjulian .name = NG_IFACE_NODE_TYPE, 210141341Sru .mod_event = ng_iface_mod_event, 211129823Sjulian .constructor = ng_iface_constructor, 212129823Sjulian .rcvmsg = ng_iface_rcvmsg, 213129823Sjulian .shutdown = ng_iface_shutdown, 214129823Sjulian .newhook = ng_iface_newhook, 215129823Sjulian .rcvdata = ng_iface_rcvdata, 216129823Sjulian .disconnect = ng_iface_disconnect, 217129823Sjulian .cmdlist = ng_iface_cmds, 21852419Sjulian}; 21952419SjulianNETGRAPH_INIT(iface, &typestruct); 22052419Sjulian 221215701Sdimstatic VNET_DEFINE(struct unrhdr *, ng_iface_unit); 222195727Srwatson#define V_ng_iface_unit VNET(ng_iface_unit) 22352419Sjulian 22452419Sjulian/************************************************************************ 22552419Sjulian HELPER STUFF 22652419Sjulian ************************************************************************/ 22752419Sjulian 22852419Sjulian/* 22952419Sjulian * Get the family descriptor from the family ID 23052419Sjulian */ 231131575Sstefanfstatic __inline iffam_p 23258015Sarchieget_iffam_from_af(sa_family_t family) 23352419Sjulian{ 23452419Sjulian iffam_p iffam; 23552419Sjulian int k; 23652419Sjulian 23752419Sjulian for (k = 0; k < NUM_FAMILIES; k++) { 23852419Sjulian iffam = &gFamilies[k]; 23958015Sarchie if (iffam->family == family) 24052419Sjulian return (iffam); 24152419Sjulian } 24252419Sjulian return (NULL); 24352419Sjulian} 24452419Sjulian 24552419Sjulian/* 24652419Sjulian * Get the family descriptor from the hook 24752419Sjulian */ 248131575Sstefanfstatic __inline iffam_p 24952419Sjulianget_iffam_from_hook(priv_p priv, hook_p hook) 25052419Sjulian{ 25152419Sjulian int k; 25252419Sjulian 25352419Sjulian for (k = 0; k < NUM_FAMILIES; k++) 25452419Sjulian if (priv->hooks[k] == hook) 25552419Sjulian return (&gFamilies[k]); 25652419Sjulian return (NULL); 25752419Sjulian} 25852419Sjulian 25952419Sjulian/* 26052419Sjulian * Get the hook from the iffam descriptor 26152419Sjulian */ 26252419Sjulian 263131575Sstefanfstatic __inline hook_p * 26452419Sjulianget_hook_from_iffam(priv_p priv, iffam_p iffam) 26552419Sjulian{ 26652419Sjulian return (&priv->hooks[iffam - gFamilies]); 26752419Sjulian} 26852419Sjulian 26952419Sjulian/* 27052419Sjulian * Get the iffam descriptor from the name 27152419Sjulian */ 272131575Sstefanfstatic __inline iffam_p 27352419Sjulianget_iffam_from_name(const char *name) 27452419Sjulian{ 27552419Sjulian iffam_p iffam; 27652419Sjulian int k; 27752419Sjulian 27852419Sjulian for (k = 0; k < NUM_FAMILIES; k++) { 27952419Sjulian iffam = &gFamilies[k]; 28052419Sjulian if (!strcmp(iffam->hookname, name)) 28152419Sjulian return (iffam); 28252419Sjulian } 28352419Sjulian return (NULL); 28452419Sjulian} 28552419Sjulian 28652419Sjulian/************************************************************************ 28752419Sjulian INTERFACE STUFF 28852419Sjulian ************************************************************************/ 28952419Sjulian 29052419Sjulian/* 29152419Sjulian * Process an ioctl for the virtual interface 29252419Sjulian */ 29352419Sjulianstatic int 29452419Sjulianng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 29552419Sjulian{ 29652419Sjulian struct ifreq *const ifr = (struct ifreq *) data; 297219781Sglebius int error = 0; 29852419Sjulian 29952419Sjulian#ifdef DEBUG 30052419Sjulian ng_iface_print_ioctl(ifp, command, data); 30152419Sjulian#endif 30252419Sjulian switch (command) { 30352419Sjulian 30452419Sjulian /* These two are mostly handled at a higher layer */ 30552419Sjulian case SIOCSIFADDR: 306148887Srwatson ifp->if_flags |= IFF_UP; 307148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 308148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 30952419Sjulian break; 31052419Sjulian case SIOCGIFADDR: 31152419Sjulian break; 31252419Sjulian 31352419Sjulian /* Set flags */ 31452419Sjulian case SIOCSIFFLAGS: 31552419Sjulian /* 31652419Sjulian * If the interface is marked up and stopped, then start it. 31752419Sjulian * If it is marked down and running, then stop it. 31852419Sjulian */ 31952419Sjulian if (ifr->ifr_flags & IFF_UP) { 320148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 321148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 322148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 32352419Sjulian } 32452419Sjulian } else { 325148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 326148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | 327148887Srwatson IFF_DRV_OACTIVE); 32852419Sjulian } 32952419Sjulian break; 33052419Sjulian 33152419Sjulian /* Set the interface MTU */ 33252419Sjulian case SIOCSIFMTU: 33352419Sjulian if (ifr->ifr_mtu > NG_IFACE_MTU_MAX 33452419Sjulian || ifr->ifr_mtu < NG_IFACE_MTU_MIN) 33552419Sjulian error = EINVAL; 33652419Sjulian else 33752419Sjulian ifp->if_mtu = ifr->ifr_mtu; 33852419Sjulian break; 33952419Sjulian 34052419Sjulian /* Stuff that's not supported */ 34152419Sjulian case SIOCADDMULTI: 34252419Sjulian case SIOCDELMULTI: 34352975Sarchie error = 0; 34452975Sarchie break; 34552419Sjulian case SIOCSIFPHYS: 34652419Sjulian error = EOPNOTSUPP; 34752419Sjulian break; 34852419Sjulian 34952419Sjulian default: 35052419Sjulian error = EINVAL; 35152419Sjulian break; 35252419Sjulian } 35352419Sjulian return (error); 35452419Sjulian} 35552419Sjulian 35652419Sjulian/* 35752419Sjulian * This routine is called to deliver a packet out the interface. 35852419Sjulian * We simply look at the address family and relay the packet to 35952419Sjulian * the corresponding hook, if it exists and is connected. 36052419Sjulian */ 36152419Sjulian 36252419Sjulianstatic int 36352419Sjulianng_iface_output(struct ifnet *ifp, struct mbuf *m, 364249925Sglebius const struct sockaddr *dst, struct route *ro) 36552419Sjulian{ 366187495Smav struct m_tag *mtag; 367151203Sglebius uint32_t af; 368151231Sglebius int error; 36952419Sjulian 37052419Sjulian /* Check interface flags */ 371148887Srwatson if (!((ifp->if_flags & IFF_UP) && 372148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) { 37352419Sjulian m_freem(m); 37452419Sjulian return (ENETDOWN); 37552419Sjulian } 37652419Sjulian 377187495Smav /* Protect from deadly infinite recursion. */ 378195231Smav mtag = NULL; 379195231Smav while ((mtag = m_tag_locate(m, MTAG_NGIF, MTAG_NGIF_CALLED, mtag))) { 380187495Smav if (*(struct ifnet **)(mtag + 1) == ifp) { 381187495Smav log(LOG_NOTICE, "Loop detected on %s\n", ifp->if_xname); 382187495Smav m_freem(m); 383187495Smav return (EDEADLK); 384187495Smav } 385187495Smav } 386187495Smav mtag = m_tag_alloc(MTAG_NGIF, MTAG_NGIF_CALLED, sizeof(struct ifnet *), 387187495Smav M_NOWAIT); 388187495Smav if (mtag == NULL) { 389187495Smav m_freem(m); 390187495Smav return (ENOMEM); 391187495Smav } 392187495Smav *(struct ifnet **)(mtag + 1) = ifp; 393187495Smav m_tag_prepend(m, mtag); 394187495Smav 395147611Sdwmalone /* BPF writes need to be handled specially. */ 396249925Sglebius if (dst->sa_family == AF_UNSPEC) 397147611Sdwmalone bcopy(dst->sa_data, &af, sizeof(af)); 398249925Sglebius else 399249925Sglebius af = dst->sa_family; 40058015Sarchie 40152419Sjulian /* Berkeley packet filter */ 402249925Sglebius ng_iface_bpftap(ifp, m, af); 40352419Sjulian 404151203Sglebius if (ALTQ_IS_ENABLED(&ifp->if_snd)) { 405243882Sglebius M_PREPEND(m, sizeof(sa_family_t), M_NOWAIT); 406151203Sglebius if (m == NULL) { 407151231Sglebius IFQ_LOCK(&ifp->if_snd); 408151231Sglebius IFQ_INC_DROPS(&ifp->if_snd); 409151231Sglebius IFQ_UNLOCK(&ifp->if_snd); 410151203Sglebius ifp->if_oerrors++; 411151203Sglebius return (ENOBUFS); 412151203Sglebius } 413249925Sglebius *(sa_family_t *)m->m_data = af; 414185164Skmacy error = (ifp->if_transmit)(ifp, m); 415151203Sglebius } else 416249925Sglebius error = ng_iface_send(ifp, m, af); 41752419Sjulian 41852419Sjulian return (error); 41952419Sjulian} 42052419Sjulian 42152419Sjulian/* 422151231Sglebius * Start method is used only when ALTQ is enabled. 42352419Sjulian */ 42452419Sjulianstatic void 42552419Sjulianng_iface_start(struct ifnet *ifp) 42652419Sjulian{ 427151203Sglebius struct mbuf *m; 428151203Sglebius sa_family_t sa; 429151203Sglebius 430151231Sglebius KASSERT(ALTQ_IS_ENABLED(&ifp->if_snd), ("%s without ALTQ", __func__)); 431151203Sglebius 432151231Sglebius for(;;) { 433151203Sglebius IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 434151203Sglebius if (m == NULL) 435151203Sglebius break; 436151203Sglebius sa = *mtod(m, sa_family_t *); 437151203Sglebius m_adj(m, sizeof(sa_family_t)); 438151203Sglebius ng_iface_send(ifp, m, sa); 439151203Sglebius } 44052419Sjulian} 44152419Sjulian 44252419Sjulian/* 44352419Sjulian * Flash a packet by the BPF (requires prepending 4 byte AF header) 44452419Sjulian * Note the phoney mbuf; this is OK because BPF treats it read-only. 44552419Sjulian */ 44652419Sjulianstatic void 44758015Sarchieng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family) 44852419Sjulian{ 44987599Sobrien KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __func__)); 450159183Ssam if (bpf_peers_present(ifp->if_bpf)) { 451123922Ssam int32_t family4 = (int32_t)family; 452123922Ssam bpf_mtap2(ifp->if_bpf, &family4, sizeof(family4), m); 45352419Sjulian } 45452419Sjulian} 45552419Sjulian 456151203Sglebius/* 457151203Sglebius * This routine does actual delivery of the packet into the 458151203Sglebius * netgraph(4). It is called from ng_iface_start() and 459151231Sglebius * ng_iface_output(). 460151203Sglebius */ 461151203Sglebiusstatic int 462151203Sglebiusng_iface_send(struct ifnet *ifp, struct mbuf *m, sa_family_t sa) 463151203Sglebius{ 464324176Seugen struct rm_priotracker priv_tracker; 465151203Sglebius const priv_p priv = (priv_p) ifp->if_softc; 466151203Sglebius const iffam_p iffam = get_iffam_from_af(sa); 467324176Seugen hook_p hook; 468151231Sglebius int error; 469151203Sglebius int len; 470151203Sglebius 471151203Sglebius /* Check address family to determine hook (if known) */ 472151203Sglebius if (iffam == NULL) { 473151203Sglebius m_freem(m); 474151203Sglebius log(LOG_WARNING, "%s: can't handle af%d\n", ifp->if_xname, sa); 475151203Sglebius return (EAFNOSUPPORT); 476151203Sglebius } 477151203Sglebius 478151203Sglebius /* Copy length before the mbuf gets invalidated. */ 479151203Sglebius len = m->m_pkthdr.len; 480151203Sglebius 481324176Seugen PRIV_RLOCK(priv, &priv_tracker); 482324176Seugen hook = *get_hook_from_iffam(priv, iffam); 483324176Seugen if (hook == NULL) { 484324176Seugen NG_FREE_M(m); 485324176Seugen PRIV_RUNLOCK(priv, &priv_tracker); 486324176Seugen return ENETDOWN; 487324176Seugen } 488324176Seugen NG_HOOK_REF(hook); 489324176Seugen PRIV_RUNLOCK(priv, &priv_tracker); 490324176Seugen 491194012Szec NG_OUTBOUND_THREAD_REF(); 492324176Seugen NG_SEND_DATA_ONLY(error, hook, m); 493194012Szec NG_OUTBOUND_THREAD_UNREF(); 494324176Seugen NG_HOOK_UNREF(hook); 495151203Sglebius 496151203Sglebius /* Update stats. */ 497151203Sglebius if (error == 0) { 498151203Sglebius ifp->if_obytes += len; 499151203Sglebius ifp->if_opackets++; 500151203Sglebius } 501151203Sglebius 502151203Sglebius return (error); 503151203Sglebius} 504151203Sglebius 50552419Sjulian#ifdef DEBUG 50652419Sjulian/* 50752419Sjulian * Display an ioctl to the virtual interface 50852419Sjulian */ 50952419Sjulian 51052419Sjulianstatic void 51152419Sjulianng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data) 51252419Sjulian{ 51352419Sjulian char *str; 51452419Sjulian 51552419Sjulian switch (command & IOC_DIRMASK) { 51652419Sjulian case IOC_VOID: 51752419Sjulian str = "IO"; 51852419Sjulian break; 51952419Sjulian case IOC_OUT: 52052419Sjulian str = "IOR"; 52152419Sjulian break; 52252419Sjulian case IOC_IN: 52352419Sjulian str = "IOW"; 52452419Sjulian break; 52552419Sjulian case IOC_INOUT: 52652419Sjulian str = "IORW"; 52752419Sjulian break; 52852419Sjulian default: 52952419Sjulian str = "IO??"; 53052419Sjulian } 531121816Sbrooks log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n", 532121816Sbrooks ifp->if_xname, 53352419Sjulian str, 53452419Sjulian IOCGROUP(command), 53552419Sjulian command & 0xff, 53652419Sjulian IOCPARM_LEN(command)); 53752419Sjulian} 53852419Sjulian#endif /* DEBUG */ 53952419Sjulian 54052419Sjulian/************************************************************************ 54152419Sjulian NETGRAPH NODE STUFF 54252419Sjulian ************************************************************************/ 54352419Sjulian 54452419Sjulian/* 54552419Sjulian * Constructor for a node 54652419Sjulian */ 54752419Sjulianstatic int 54870700Sjulianng_iface_constructor(node_p node) 54952419Sjulian{ 55052419Sjulian struct ifnet *ifp; 55152419Sjulian priv_p priv; 55252419Sjulian 55352419Sjulian /* Allocate node and interface private structures */ 554220768Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH_IFACE, M_WAITOK | M_ZERO); 555147256Sbrooks ifp = if_alloc(IFT_PROPVIRTUAL); 55652419Sjulian if (ifp == NULL) { 557184205Sdes free(priv, M_NETGRAPH_IFACE); 55852419Sjulian return (ENOMEM); 55952419Sjulian } 56052419Sjulian 561324176Seugen rm_init(&priv->lock, "ng_iface private rmlock"); 562324176Seugen 56352419Sjulian /* Link them together */ 56452419Sjulian ifp->if_softc = priv; 56552419Sjulian priv->ifp = ifp; 56652419Sjulian 56758015Sarchie /* Get an interface unit number */ 568181803Sbz priv->unit = alloc_unr(V_ng_iface_unit); 56958015Sarchie 57052419Sjulian /* Link together node and private info */ 57170784Sjulian NG_NODE_SET_PRIVATE(node, priv); 57252419Sjulian priv->node = node; 57352419Sjulian 57452419Sjulian /* Initialize interface structure */ 575121816Sbrooks if_initname(ifp, NG_IFACE_IFACE_NAME, priv->unit); 57652419Sjulian ifp->if_output = ng_iface_output; 57752419Sjulian ifp->if_start = ng_iface_start; 57852419Sjulian ifp->if_ioctl = ng_iface_ioctl; 57952419Sjulian ifp->if_mtu = NG_IFACE_MTU_DEFAULT; 58058015Sarchie ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST); 58152419Sjulian ifp->if_type = IFT_PROPVIRTUAL; /* XXX */ 58252419Sjulian ifp->if_addrlen = 0; /* XXX */ 58352419Sjulian ifp->if_hdrlen = 0; /* XXX */ 58452419Sjulian ifp->if_baudrate = 64000; /* XXX */ 585207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 586207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 587151203Sglebius IFQ_SET_READY(&ifp->if_snd); 58852419Sjulian 58952419Sjulian /* Give this node the same name as the interface (if possible) */ 590141197Sru if (ng_name_node(node, ifp->if_xname) != 0) 591141197Sru log(LOG_WARNING, "%s: can't acquire netgraph name\n", 592141197Sru ifp->if_xname); 59352419Sjulian 59452419Sjulian /* Attach the interface */ 59552419Sjulian if_attach(ifp); 596147611Sdwmalone bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 59752419Sjulian 59852419Sjulian /* Done */ 59952419Sjulian return (0); 60052419Sjulian} 60152419Sjulian 60252419Sjulian/* 60352419Sjulian * Give our ok for a hook to be added 60452419Sjulian */ 60552419Sjulianstatic int 60652419Sjulianng_iface_newhook(node_p node, hook_p hook, const char *name) 60752419Sjulian{ 60852419Sjulian const iffam_p iffam = get_iffam_from_name(name); 609324176Seugen const priv_p priv = NG_NODE_PRIVATE(node); 61052419Sjulian hook_p *hookptr; 61152419Sjulian 61252419Sjulian if (iffam == NULL) 61352419Sjulian return (EPFNOSUPPORT); 614324176Seugen PRIV_WLOCK(priv); 615324176Seugen hookptr = get_hook_from_iffam(priv, iffam); 616324176Seugen if (*hookptr != NULL) { 617324176Seugen PRIV_WUNLOCK(priv); 61852419Sjulian return (EISCONN); 619324176Seugen } 62052419Sjulian *hookptr = hook; 621175847Smav NG_HOOK_HI_STACK(hook); 622194012Szec NG_HOOK_SET_TO_INBOUND(hook); 623324176Seugen PRIV_WUNLOCK(priv); 62452419Sjulian return (0); 62552419Sjulian} 62652419Sjulian 62752419Sjulian/* 62852419Sjulian * Receive a control message 62952419Sjulian */ 63052419Sjulianstatic int 63170700Sjulianng_iface_rcvmsg(node_p node, item_p item, hook_p lasthook) 63252419Sjulian{ 63370784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 63452419Sjulian struct ifnet *const ifp = priv->ifp; 63552419Sjulian struct ng_mesg *resp = NULL; 63652419Sjulian int error = 0; 63770700Sjulian struct ng_mesg *msg; 63852419Sjulian 63970700Sjulian NGI_GET_MSG(item, msg); 64052419Sjulian switch (msg->header.typecookie) { 64152419Sjulian case NGM_IFACE_COOKIE: 64252419Sjulian switch (msg->header.cmd) { 64352419Sjulian case NGM_IFACE_GET_IFNAME: 644141197Sru NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT); 64552419Sjulian if (resp == NULL) { 64652419Sjulian error = ENOMEM; 64752419Sjulian break; 64852419Sjulian } 649141197Sru strlcpy(resp->data, ifp->if_xname, IFNAMSIZ); 65052419Sjulian break; 65152419Sjulian 65258015Sarchie case NGM_IFACE_POINT2POINT: 65358015Sarchie case NGM_IFACE_BROADCAST: 65452419Sjulian { 65552419Sjulian 65658015Sarchie /* Deny request if interface is UP */ 65758015Sarchie if ((ifp->if_flags & IFF_UP) != 0) 65858015Sarchie return (EBUSY); 65952419Sjulian 66058015Sarchie /* Change flags */ 66158015Sarchie switch (msg->header.cmd) { 66258015Sarchie case NGM_IFACE_POINT2POINT: 66358015Sarchie ifp->if_flags |= IFF_POINTOPOINT; 66458015Sarchie ifp->if_flags &= ~IFF_BROADCAST; 66552419Sjulian break; 66658015Sarchie case NGM_IFACE_BROADCAST: 66758015Sarchie ifp->if_flags &= ~IFF_POINTOPOINT; 66858015Sarchie ifp->if_flags |= IFF_BROADCAST; 66958015Sarchie break; 67052419Sjulian } 67152419Sjulian break; 67252419Sjulian } 67352419Sjulian 674126730Sru case NGM_IFACE_GET_IFINDEX: 675126730Sru NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); 676126730Sru if (resp == NULL) { 677126730Sru error = ENOMEM; 678126730Sru break; 679126730Sru } 680126730Sru *((uint32_t *)resp->data) = priv->ifp->if_index; 681126730Sru break; 682126730Sru 68352419Sjulian default: 68452419Sjulian error = EINVAL; 68552419Sjulian break; 68652419Sjulian } 68752419Sjulian break; 68852419Sjulian case NGM_CISCO_COOKIE: 68952419Sjulian switch (msg->header.cmd) { 69052419Sjulian case NGM_CISCO_GET_IPADDR: /* we understand this too */ 69152419Sjulian { 69252419Sjulian struct ifaddr *ifa; 69352419Sjulian 69452419Sjulian /* Return the first configured IP address */ 695195024Srwatson if_addr_rlock(ifp); 69652419Sjulian TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 69758015Sarchie struct ng_cisco_ipaddr *ips; 69852419Sjulian 69952419Sjulian if (ifa->ifa_addr->sa_family != AF_INET) 70052419Sjulian continue; 70158015Sarchie NG_MKRESPONSE(resp, msg, sizeof(ips), M_NOWAIT); 70252419Sjulian if (resp == NULL) { 70352419Sjulian error = ENOMEM; 70452419Sjulian break; 70552419Sjulian } 70658015Sarchie ips = (struct ng_cisco_ipaddr *)resp->data; 70758015Sarchie ips->ipaddr = ((struct sockaddr_in *) 70852419Sjulian ifa->ifa_addr)->sin_addr; 70958015Sarchie ips->netmask = ((struct sockaddr_in *) 71052419Sjulian ifa->ifa_netmask)->sin_addr; 71152419Sjulian break; 71252419Sjulian } 713195024Srwatson if_addr_runlock(ifp); 71452419Sjulian 71552419Sjulian /* No IP addresses on this interface? */ 71652419Sjulian if (ifa == NULL) 71752419Sjulian error = EADDRNOTAVAIL; 71852419Sjulian break; 71952419Sjulian } 72052419Sjulian default: 72152419Sjulian error = EINVAL; 72252419Sjulian break; 72352419Sjulian } 72452419Sjulian break; 725138011Sglebius case NGM_FLOW_COOKIE: 726138011Sglebius switch (msg->header.cmd) { 727138011Sglebius case NGM_LINK_IS_UP: 728148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 729138011Sglebius break; 730138011Sglebius case NGM_LINK_IS_DOWN: 731148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 732138011Sglebius break; 733138011Sglebius default: 734138011Sglebius break; 735138011Sglebius } 736138011Sglebius break; 73752419Sjulian default: 73852419Sjulian error = EINVAL; 73952419Sjulian break; 74052419Sjulian } 74170700Sjulian NG_RESPOND_MSG(error, node, item, resp); 74270700Sjulian NG_FREE_MSG(msg); 74352419Sjulian return (error); 74452419Sjulian} 74552419Sjulian 74652419Sjulian/* 74752419Sjulian * Recive data from a hook. Pass the packet to the correct input routine. 74852419Sjulian */ 74952419Sjulianstatic int 75070700Sjulianng_iface_rcvdata(hook_p hook, item_p item) 75152419Sjulian{ 75270784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 75352419Sjulian const iffam_p iffam = get_iffam_from_hook(priv, hook); 75452419Sjulian struct ifnet *const ifp = priv->ifp; 75570700Sjulian struct mbuf *m; 756111888Sjlemon int isr; 75752419Sjulian 75870700Sjulian NGI_GET_M(item, m); 75970700Sjulian NG_FREE_ITEM(item); 76052419Sjulian /* Sanity checks */ 76187599Sobrien KASSERT(iffam != NULL, ("%s: iffam", __func__)); 762113255Sdes M_ASSERTPKTHDR(m); 76352419Sjulian if ((ifp->if_flags & IFF_UP) == 0) { 76470700Sjulian NG_FREE_M(m); 76552419Sjulian return (ENETDOWN); 76652419Sjulian } 76752419Sjulian 76852419Sjulian /* Update interface stats */ 76952419Sjulian ifp->if_ipackets++; 77052419Sjulian ifp->if_ibytes += m->m_pkthdr.len; 77152419Sjulian 77252419Sjulian /* Note receiving interface */ 77352419Sjulian m->m_pkthdr.rcvif = ifp; 77452419Sjulian 77552419Sjulian /* Berkeley packet filter */ 77658015Sarchie ng_iface_bpftap(ifp, m, iffam->family); 77752419Sjulian 77858015Sarchie /* Send packet */ 779111888Sjlemon switch (iffam->family) { 780111888Sjlemon#ifdef INET 781111888Sjlemon case AF_INET: 782111888Sjlemon isr = NETISR_IP; 783111888Sjlemon break; 784111888Sjlemon#endif 785111888Sjlemon#ifdef INET6 786111888Sjlemon case AF_INET6: 787111888Sjlemon isr = NETISR_IPV6; 788111888Sjlemon break; 789111888Sjlemon#endif 790111888Sjlemon#ifdef IPX 791111888Sjlemon case AF_IPX: 792111888Sjlemon isr = NETISR_IPX; 793111888Sjlemon break; 794111888Sjlemon#endif 795111888Sjlemon#ifdef NETATALK 796111888Sjlemon case AF_APPLETALK: 797111888Sjlemon isr = NETISR_ATALK2; 798111888Sjlemon break; 799111888Sjlemon#endif 800111888Sjlemon default: 801111888Sjlemon m_freem(m); 802111888Sjlemon return (EAFNOSUPPORT); 803111888Sjlemon } 804111888Sjlemon if (harvest.point_to_point) 805256381Smarkm random_harvest(&(m->m_data), 12, 2, RANDOM_NET_NG); 806223741Sbz M_SETFIB(m, ifp->if_fib); 807180372Sgonzo netisr_dispatch(isr, m); 808111888Sjlemon return (0); 80952419Sjulian} 81052419Sjulian 81152419Sjulian/* 81258015Sarchie * Shutdown and remove the node and its associated interface. 81352419Sjulian */ 81452419Sjulianstatic int 81570700Sjulianng_iface_shutdown(node_p node) 81652419Sjulian{ 81770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 81852419Sjulian 819183550Szec /* 820183550Szec * The ifnet may be in a different vnet than the netgraph node, 821183550Szec * hence we have to change the current vnet context here. 822183550Szec */ 823183550Szec CURVNET_SET_QUIET(priv->ifp->if_vnet); 82458412Sarchie bpfdetach(priv->ifp); 82558015Sarchie if_detach(priv->ifp); 826147256Sbrooks if_free(priv->ifp); 827183550Szec CURVNET_RESTORE(); 82858015Sarchie priv->ifp = NULL; 829181803Sbz free_unr(V_ng_iface_unit, priv->unit); 830324176Seugen rm_destroy(&priv->lock); 831184205Sdes free(priv, M_NETGRAPH_IFACE); 83270784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 83370784Sjulian NG_NODE_UNREF(node); 83452419Sjulian return (0); 83552419Sjulian} 83652419Sjulian 83752419Sjulian/* 83858015Sarchie * Hook disconnection. Note that we do *not* shutdown when all 83958015Sarchie * hooks have been disconnected. 84052419Sjulian */ 84152419Sjulianstatic int 84252419Sjulianng_iface_disconnect(hook_p hook) 84352419Sjulian{ 84470784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 84552419Sjulian const iffam_p iffam = get_iffam_from_hook(priv, hook); 84652419Sjulian 84752419Sjulian if (iffam == NULL) 848213794Srpaulo panic("%s", __func__); 849324176Seugen PRIV_WLOCK(priv); 85052419Sjulian *get_hook_from_iffam(priv, iffam) = NULL; 851324176Seugen PRIV_WUNLOCK(priv); 85252419Sjulian return (0); 85352419Sjulian} 85452419Sjulian 855141341Sru/* 856141341Sru * Handle loading and unloading for this node type. 857141341Sru */ 858141341Srustatic int 859141341Srung_iface_mod_event(module_t mod, int event, void *data) 860141341Sru{ 861141341Sru int error = 0; 862141341Sru 863141341Sru switch (event) { 864141341Sru case MOD_LOAD: 865141341Sru case MOD_UNLOAD: 866141341Sru break; 867141341Sru default: 868141341Sru error = EOPNOTSUPP; 869141341Sru break; 870141341Sru } 871141341Sru return (error); 872141341Sru} 873191510Szec 874195837Srwatsonstatic void 875195837Srwatsonvnet_ng_iface_init(const void *unused) 876191510Szec{ 877191510Szec 878191510Szec V_ng_iface_unit = new_unrhdr(0, 0xffff, NULL); 879191510Szec} 880195837SrwatsonVNET_SYSINIT(vnet_ng_iface_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 881195837Srwatson vnet_ng_iface_init, NULL); 882191510Szec 883195837Srwatsonstatic void 884195837Srwatsonvnet_ng_iface_uninit(const void *unused) 885191510Szec{ 886191510Szec 887191510Szec delete_unrhdr(V_ng_iface_unit); 888191510Szec} 889195837SrwatsonVNET_SYSUNINIT(vnet_ng_iface_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, 890195837Srwatson vnet_ng_iface_uninit, NULL); 891