1274246Sae/*- 2274246Sae * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org> 3274246Sae * All rights reserved. 4274246Sae * 5274246Sae * Redistribution and use in source and binary forms, with or without 6274246Sae * modification, are permitted provided that the following conditions 7274246Sae * are met: 8274246Sae * 9274246Sae * 1. Redistributions of source code must retain the above copyright 10274246Sae * notice, this list of conditions and the following disclaimer. 11274246Sae * 2. Redistributions in binary form must reproduce the above copyright 12274246Sae * notice, this list of conditions and the following disclaimer in the 13274246Sae * documentation and/or other materials provided with the distribution. 14274246Sae * 15274246Sae * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16274246Sae * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17274246Sae * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18274246Sae * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19274246Sae * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20274246Sae * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21274246Sae * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22274246Sae * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23274246Sae * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24274246Sae * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25274246Sae */ 26274246Sae 27274246Sae#include <sys/cdefs.h> 28274246Sae__FBSDID("$FreeBSD: releng/11.0/sys/net/if_me.c 288575 2015-10-03 09:15:23Z hrs $"); 29274246Sae 30274246Sae#include <sys/param.h> 31274246Sae#include <sys/jail.h> 32274246Sae#include <sys/kernel.h> 33274246Sae#include <sys/lock.h> 34274246Sae#include <sys/libkern.h> 35274246Sae#include <sys/malloc.h> 36274246Sae#include <sys/module.h> 37274246Sae#include <sys/mbuf.h> 38274246Sae#include <sys/priv.h> 39274246Sae#include <sys/proc.h> 40274246Sae#include <sys/protosw.h> 41274246Sae#include <sys/rmlock.h> 42274246Sae#include <sys/socket.h> 43274246Sae#include <sys/sockio.h> 44274246Sae#include <sys/sx.h> 45274246Sae#include <sys/sysctl.h> 46274246Sae#include <sys/syslog.h> 47274246Sae#include <sys/systm.h> 48274246Sae 49274246Sae#include <net/bpf.h> 50274246Sae#include <net/ethernet.h> 51274246Sae#include <net/if.h> 52274246Sae#include <net/if_var.h> 53274246Sae#include <net/if_clone.h> 54274246Sae#include <net/if_types.h> 55274246Sae#include <net/netisr.h> 56274246Sae#include <net/vnet.h> 57282809Sae#include <net/route.h> 58274246Sae 59274246Sae#include <netinet/in.h> 60274246Sae#include <netinet/in_systm.h> 61274246Sae#include <netinet/in_var.h> 62274246Sae#include <netinet/ip.h> 63274246Sae#include <netinet/ip_var.h> 64274246Sae#include <netinet/ip_encap.h> 65274246Sae 66274246Sae#include <machine/in_cksum.h> 67274246Sae#include <security/mac/mac_framework.h> 68274246Sae 69274246Sae#define MEMTU 1500 70274246Saestatic const char mename[] = "me"; 71274246Saestatic MALLOC_DEFINE(M_IFME, mename, "Minimal Encapsulation for IP"); 72274246Saestatic VNET_DEFINE(struct mtx, me_mtx); 73274246Sae#define V_me_mtx VNET(me_mtx) 74274246Sae/* Minimal forwarding header RFC 2004 */ 75274246Saestruct mobhdr { 76274246Sae uint8_t mob_proto; /* protocol */ 77274246Sae uint8_t mob_flags; /* flags */ 78274246Sae#define MOB_FLAGS_SP 0x80 /* source present */ 79274246Sae uint16_t mob_csum; /* header checksum */ 80274246Sae struct in_addr mob_dst; /* original destination address */ 81274246Sae struct in_addr mob_src; /* original source addr (optional) */ 82274246Sae} __packed; 83274246Sae 84274246Saestruct me_softc { 85274246Sae struct ifnet *me_ifp; 86274246Sae LIST_ENTRY(me_softc) me_list; 87274246Sae struct rmlock me_lock; 88274246Sae u_int me_fibnum; 89274246Sae const struct encaptab *me_ecookie; 90274246Sae struct in_addr me_src; 91274246Sae struct in_addr me_dst; 92274246Sae}; 93274246Sae#define ME2IFP(sc) ((sc)->me_ifp) 94274246Sae#define ME_READY(sc) ((sc)->me_src.s_addr != 0) 95274246Sae#define ME_LOCK_INIT(sc) rm_init(&(sc)->me_lock, "me softc") 96274246Sae#define ME_LOCK_DESTROY(sc) rm_destroy(&(sc)->me_lock) 97274246Sae#define ME_RLOCK_TRACKER struct rm_priotracker me_tracker 98274246Sae#define ME_RLOCK(sc) rm_rlock(&(sc)->me_lock, &me_tracker) 99274246Sae#define ME_RUNLOCK(sc) rm_runlock(&(sc)->me_lock, &me_tracker) 100274246Sae#define ME_RLOCK_ASSERT(sc) rm_assert(&(sc)->me_lock, RA_RLOCKED) 101274246Sae#define ME_WLOCK(sc) rm_wlock(&(sc)->me_lock) 102274246Sae#define ME_WUNLOCK(sc) rm_wunlock(&(sc)->me_lock) 103274246Sae#define ME_WLOCK_ASSERT(sc) rm_assert(&(sc)->me_lock, RA_WLOCKED) 104274246Sae 105274246Sae#define ME_LIST_LOCK_INIT(x) mtx_init(&V_me_mtx, "me_mtx", NULL, MTX_DEF) 106274246Sae#define ME_LIST_LOCK_DESTROY(x) mtx_destroy(&V_me_mtx) 107274246Sae#define ME_LIST_LOCK(x) mtx_lock(&V_me_mtx) 108274246Sae#define ME_LIST_UNLOCK(x) mtx_unlock(&V_me_mtx) 109274246Sae 110274246Saestatic VNET_DEFINE(LIST_HEAD(, me_softc), me_softc_list); 111274246Sae#define V_me_softc_list VNET(me_softc_list) 112274246Saestatic struct sx me_ioctl_sx; 113274246SaeSX_SYSINIT(me_ioctl_sx, &me_ioctl_sx, "me_ioctl"); 114274246Sae 115274246Saestatic int me_clone_create(struct if_clone *, int, caddr_t); 116274246Saestatic void me_clone_destroy(struct ifnet *); 117274246Saestatic VNET_DEFINE(struct if_clone *, me_cloner); 118274246Sae#define V_me_cloner VNET(me_cloner) 119274246Sae 120274246Saestatic void me_qflush(struct ifnet *); 121274246Saestatic int me_transmit(struct ifnet *, struct mbuf *); 122274246Saestatic int me_ioctl(struct ifnet *, u_long, caddr_t); 123274246Saestatic int me_output(struct ifnet *, struct mbuf *, 124274246Sae const struct sockaddr *, struct route *); 125274246Saestatic int me_input(struct mbuf **, int *, int); 126274246Sae 127274246Saestatic int me_set_tunnel(struct ifnet *, struct sockaddr_in *, 128274246Sae struct sockaddr_in *); 129274246Saestatic void me_delete_tunnel(struct ifnet *); 130274246Sae 131274246SaeSYSCTL_DECL(_net_link); 132274246Saestatic SYSCTL_NODE(_net_link, IFT_TUNNEL, me, CTLFLAG_RW, 0, 133274246Sae "Minimal Encapsulation for IP (RFC 2004)"); 134274246Sae#ifndef MAX_ME_NEST 135274246Sae#define MAX_ME_NEST 1 136274246Sae#endif 137274246Sae 138274246Saestatic VNET_DEFINE(int, max_me_nesting) = MAX_ME_NEST; 139274246Sae#define V_max_me_nesting VNET(max_me_nesting) 140274246SaeSYSCTL_INT(_net_link_me, OID_AUTO, max_nesting, CTLFLAG_RW | CTLFLAG_VNET, 141274246Sae &VNET_NAME(max_me_nesting), 0, "Max nested tunnels"); 142274246Sae 143274246Saeextern struct domain inetdomain; 144274246Saestatic const struct protosw in_mobile_protosw = { 145274246Sae .pr_type = SOCK_RAW, 146274246Sae .pr_domain = &inetdomain, 147274246Sae .pr_protocol = IPPROTO_MOBILE, 148274246Sae .pr_flags = PR_ATOMIC|PR_ADDR, 149274246Sae .pr_input = me_input, 150274246Sae .pr_output = rip_output, 151274246Sae .pr_ctlinput = rip_ctlinput, 152274246Sae .pr_ctloutput = rip_ctloutput, 153274246Sae .pr_usrreqs = &rip_usrreqs 154274246Sae}; 155274246Sae 156274246Saestatic void 157274246Saevnet_me_init(const void *unused __unused) 158274246Sae{ 159274246Sae LIST_INIT(&V_me_softc_list); 160274246Sae ME_LIST_LOCK_INIT(); 161274246Sae V_me_cloner = if_clone_simple(mename, me_clone_create, 162274246Sae me_clone_destroy, 0); 163274246Sae} 164274246SaeVNET_SYSINIT(vnet_me_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 165274246Sae vnet_me_init, NULL); 166274246Sae 167274246Saestatic void 168274246Saevnet_me_uninit(const void *unused __unused) 169274246Sae{ 170274246Sae 171274246Sae if_clone_detach(V_me_cloner); 172274246Sae ME_LIST_LOCK_DESTROY(); 173274246Sae} 174274246SaeVNET_SYSUNINIT(vnet_me_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 175274246Sae vnet_me_uninit, NULL); 176274246Sae 177274246Saestatic int 178274246Saeme_clone_create(struct if_clone *ifc, int unit, caddr_t params) 179274246Sae{ 180274246Sae struct me_softc *sc; 181274246Sae 182274246Sae sc = malloc(sizeof(struct me_softc), M_IFME, M_WAITOK | M_ZERO); 183274246Sae sc->me_fibnum = curthread->td_proc->p_fibnum; 184274246Sae ME2IFP(sc) = if_alloc(IFT_TUNNEL); 185274246Sae ME_LOCK_INIT(sc); 186274246Sae ME2IFP(sc)->if_softc = sc; 187274246Sae if_initname(ME2IFP(sc), mename, unit); 188274246Sae 189274246Sae ME2IFP(sc)->if_mtu = MEMTU - sizeof(struct mobhdr); 190274246Sae ME2IFP(sc)->if_flags = IFF_POINTOPOINT|IFF_MULTICAST; 191274246Sae ME2IFP(sc)->if_output = me_output; 192274246Sae ME2IFP(sc)->if_ioctl = me_ioctl; 193274246Sae ME2IFP(sc)->if_transmit = me_transmit; 194274246Sae ME2IFP(sc)->if_qflush = me_qflush; 195288575Shrs ME2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE; 196288575Shrs ME2IFP(sc)->if_capenable |= IFCAP_LINKSTATE; 197274246Sae if_attach(ME2IFP(sc)); 198274246Sae bpfattach(ME2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 199274246Sae ME_LIST_LOCK(); 200274246Sae LIST_INSERT_HEAD(&V_me_softc_list, sc, me_list); 201274246Sae ME_LIST_UNLOCK(); 202274246Sae return (0); 203274246Sae} 204274246Sae 205274246Saestatic void 206274246Saeme_clone_destroy(struct ifnet *ifp) 207274246Sae{ 208274246Sae struct me_softc *sc; 209274246Sae 210274246Sae sx_xlock(&me_ioctl_sx); 211274246Sae sc = ifp->if_softc; 212274246Sae me_delete_tunnel(ifp); 213274246Sae ME_LIST_LOCK(); 214274246Sae LIST_REMOVE(sc, me_list); 215274246Sae ME_LIST_UNLOCK(); 216274246Sae bpfdetach(ifp); 217274246Sae if_detach(ifp); 218274246Sae ifp->if_softc = NULL; 219274246Sae sx_xunlock(&me_ioctl_sx); 220274246Sae 221274246Sae if_free(ifp); 222274246Sae ME_LOCK_DESTROY(sc); 223274246Sae free(sc, M_IFME); 224274246Sae} 225274246Sae 226274246Saestatic int 227274246Saeme_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 228274246Sae{ 229274246Sae ME_RLOCK_TRACKER; 230274246Sae struct ifreq *ifr = (struct ifreq *)data; 231274246Sae struct sockaddr_in *src, *dst; 232274246Sae struct me_softc *sc; 233274246Sae int error; 234274246Sae 235274246Sae switch (cmd) { 236274246Sae case SIOCSIFMTU: 237274246Sae if (ifr->ifr_mtu < 576) 238274246Sae return (EINVAL); 239274246Sae ifp->if_mtu = ifr->ifr_mtu - sizeof(struct mobhdr); 240274246Sae return (0); 241274246Sae case SIOCSIFADDR: 242274246Sae ifp->if_flags |= IFF_UP; 243274246Sae case SIOCSIFFLAGS: 244274246Sae case SIOCADDMULTI: 245274246Sae case SIOCDELMULTI: 246274246Sae return (0); 247274246Sae } 248274246Sae sx_xlock(&me_ioctl_sx); 249274246Sae sc = ifp->if_softc; 250274246Sae if (sc == NULL) { 251274246Sae error = ENXIO; 252274246Sae goto end; 253274246Sae } 254274246Sae error = 0; 255274246Sae switch (cmd) { 256274246Sae case SIOCSIFPHYADDR: 257274246Sae src = (struct sockaddr_in *) 258274246Sae &(((struct in_aliasreq *)data)->ifra_addr); 259274246Sae dst = (struct sockaddr_in *) 260274246Sae &(((struct in_aliasreq *)data)->ifra_dstaddr); 261274246Sae if (src->sin_family != dst->sin_family || 262274246Sae src->sin_family != AF_INET || 263274246Sae src->sin_len != dst->sin_len || 264274246Sae src->sin_len != sizeof(struct sockaddr_in)) { 265274246Sae error = EINVAL; 266274246Sae break; 267274246Sae } 268274246Sae if (src->sin_addr.s_addr == INADDR_ANY || 269274246Sae dst->sin_addr.s_addr == INADDR_ANY) { 270274246Sae error = EADDRNOTAVAIL; 271274246Sae break; 272274246Sae } 273274246Sae error = me_set_tunnel(ifp, src, dst); 274274246Sae break; 275274246Sae case SIOCDIFPHYADDR: 276274246Sae me_delete_tunnel(ifp); 277274246Sae break; 278274246Sae case SIOCGIFPSRCADDR: 279274246Sae case SIOCGIFPDSTADDR: 280274246Sae ME_RLOCK(sc); 281274246Sae if (!ME_READY(sc)) { 282274246Sae error = EADDRNOTAVAIL; 283274246Sae ME_RUNLOCK(sc); 284274246Sae break; 285274246Sae } 286274246Sae src = (struct sockaddr_in *)&ifr->ifr_addr; 287274246Sae memset(src, 0, sizeof(*src)); 288274246Sae src->sin_family = AF_INET; 289274246Sae src->sin_len = sizeof(*src); 290274246Sae switch (cmd) { 291274246Sae case SIOCGIFPSRCADDR: 292274246Sae src->sin_addr = sc->me_src; 293274246Sae break; 294274246Sae case SIOCGIFPDSTADDR: 295274246Sae src->sin_addr = sc->me_dst; 296274246Sae break; 297274246Sae } 298274246Sae ME_RUNLOCK(sc); 299274246Sae error = prison_if(curthread->td_ucred, sintosa(src)); 300274246Sae if (error != 0) 301274246Sae memset(src, 0, sizeof(*src)); 302274246Sae break; 303282809Sae case SIOCGTUNFIB: 304282809Sae ifr->ifr_fib = sc->me_fibnum; 305282809Sae break; 306282809Sae case SIOCSTUNFIB: 307282809Sae if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0) 308282809Sae break; 309282809Sae if (ifr->ifr_fib >= rt_numfibs) 310282809Sae error = EINVAL; 311282809Sae else 312282809Sae sc->me_fibnum = ifr->ifr_fib; 313282809Sae break; 314274246Sae default: 315274246Sae error = EINVAL; 316274246Sae break; 317274246Sae } 318274246Saeend: 319274246Sae sx_xunlock(&me_ioctl_sx); 320274246Sae return (error); 321274246Sae} 322274246Sae 323274246Saestatic int 324274246Saeme_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 325274246Sae{ 326274246Sae ME_RLOCK_TRACKER; 327274246Sae struct me_softc *sc; 328274246Sae struct ip *ip; 329274246Sae int ret; 330274246Sae 331274246Sae sc = (struct me_softc *)arg; 332274246Sae if ((ME2IFP(sc)->if_flags & IFF_UP) == 0) 333274246Sae return (0); 334274246Sae 335274246Sae M_ASSERTPKTHDR(m); 336274246Sae 337274246Sae if (m->m_pkthdr.len < sizeof(struct ip) + sizeof(struct mobhdr) - 338274246Sae sizeof(struct in_addr)) 339274246Sae return (0); 340274246Sae 341274246Sae ret = 0; 342274246Sae ME_RLOCK(sc); 343274246Sae if (ME_READY(sc)) { 344274246Sae ip = mtod(m, struct ip *); 345274246Sae if (sc->me_src.s_addr == ip->ip_dst.s_addr && 346274246Sae sc->me_dst.s_addr == ip->ip_src.s_addr) 347274246Sae ret = 32 * 2; 348274246Sae } 349274246Sae ME_RUNLOCK(sc); 350274246Sae return (ret); 351274246Sae} 352274246Sae 353274246Saestatic int 354274246Saeme_set_tunnel(struct ifnet *ifp, struct sockaddr_in *src, 355274246Sae struct sockaddr_in *dst) 356274246Sae{ 357274246Sae struct me_softc *sc, *tsc; 358274246Sae 359274246Sae sx_assert(&me_ioctl_sx, SA_XLOCKED); 360274246Sae ME_LIST_LOCK(); 361274246Sae sc = ifp->if_softc; 362274246Sae LIST_FOREACH(tsc, &V_me_softc_list, me_list) { 363274246Sae if (tsc == sc || !ME_READY(tsc)) 364274246Sae continue; 365274246Sae if (tsc->me_src.s_addr == src->sin_addr.s_addr && 366274246Sae tsc->me_dst.s_addr == dst->sin_addr.s_addr) { 367274246Sae ME_LIST_UNLOCK(); 368274246Sae return (EADDRNOTAVAIL); 369274246Sae } 370274246Sae } 371274246Sae ME_LIST_UNLOCK(); 372274246Sae 373274246Sae ME_WLOCK(sc); 374274246Sae sc->me_dst = dst->sin_addr; 375274246Sae sc->me_src = src->sin_addr; 376274246Sae ME_WUNLOCK(sc); 377274246Sae 378274246Sae if (sc->me_ecookie == NULL) 379274246Sae sc->me_ecookie = encap_attach_func(AF_INET, IPPROTO_MOBILE, 380274246Sae me_encapcheck, &in_mobile_protosw, sc); 381288575Shrs if (sc->me_ecookie != NULL) { 382274246Sae ifp->if_drv_flags |= IFF_DRV_RUNNING; 383288575Shrs if_link_state_change(ifp, LINK_STATE_UP); 384288575Shrs } 385274246Sae return (0); 386274246Sae} 387274246Sae 388274246Saestatic void 389274246Saeme_delete_tunnel(struct ifnet *ifp) 390274246Sae{ 391274246Sae struct me_softc *sc = ifp->if_softc; 392274246Sae 393274246Sae sx_assert(&me_ioctl_sx, SA_XLOCKED); 394274246Sae if (sc->me_ecookie != NULL) 395274246Sae encap_detach(sc->me_ecookie); 396274246Sae sc->me_ecookie = NULL; 397274246Sae ME_WLOCK(sc); 398274246Sae sc->me_src.s_addr = 0; 399274246Sae sc->me_dst.s_addr = 0; 400274246Sae ME_WUNLOCK(sc); 401274246Sae ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 402288575Shrs if_link_state_change(ifp, LINK_STATE_DOWN); 403274246Sae} 404274246Sae 405274246Saestatic uint16_t 406274246Saeme_in_cksum(uint16_t *p, int nwords) 407274246Sae{ 408274246Sae uint32_t sum = 0; 409274246Sae 410274246Sae while (nwords-- > 0) 411274246Sae sum += *p++; 412274246Sae sum = (sum >> 16) + (sum & 0xffff); 413274246Sae sum += (sum >> 16); 414274246Sae return (~sum); 415274246Sae} 416274246Sae 417274246Saeint 418274246Saeme_input(struct mbuf **mp, int *offp, int proto) 419274246Sae{ 420274246Sae struct me_softc *sc; 421274246Sae struct mobhdr *mh; 422274246Sae struct ifnet *ifp; 423274246Sae struct mbuf *m; 424274246Sae struct ip *ip; 425274246Sae int hlen; 426274246Sae 427274246Sae m = *mp; 428274246Sae sc = encap_getarg(m); 429274246Sae KASSERT(sc != NULL, ("encap_getarg returned NULL")); 430274246Sae 431274246Sae ifp = ME2IFP(sc); 432274246Sae /* checks for short packets */ 433274246Sae hlen = sizeof(struct mobhdr); 434274246Sae if (m->m_pkthdr.len < sizeof(struct ip) + hlen) 435274246Sae hlen -= sizeof(struct in_addr); 436274246Sae if (m->m_len < sizeof(struct ip) + hlen) 437274246Sae m = m_pullup(m, sizeof(struct ip) + hlen); 438274246Sae if (m == NULL) 439274246Sae goto drop; 440274246Sae mh = (struct mobhdr *)mtodo(m, sizeof(struct ip)); 441274246Sae /* check for wrong flags */ 442274246Sae if (mh->mob_flags & (~MOB_FLAGS_SP)) { 443274246Sae m_freem(m); 444274246Sae goto drop; 445274246Sae } 446274246Sae if (mh->mob_flags) { 447274246Sae if (hlen != sizeof(struct mobhdr)) { 448274246Sae m_freem(m); 449274246Sae goto drop; 450274246Sae } 451274246Sae } else 452274246Sae hlen = sizeof(struct mobhdr) - sizeof(struct in_addr); 453274246Sae /* check mobile header checksum */ 454274246Sae if (me_in_cksum((uint16_t *)mh, hlen / sizeof(uint16_t)) != 0) { 455274246Sae m_freem(m); 456274246Sae goto drop; 457274246Sae } 458274246Sae#ifdef MAC 459274246Sae mac_ifnet_create_mbuf(ifp, m); 460274246Sae#endif 461274246Sae ip = mtod(m, struct ip *); 462274246Sae ip->ip_dst = mh->mob_dst; 463274246Sae ip->ip_p = mh->mob_proto; 464274246Sae ip->ip_sum = 0; 465274246Sae ip->ip_len = htons(m->m_pkthdr.len - hlen); 466274246Sae if (mh->mob_flags) 467274246Sae ip->ip_src = mh->mob_src; 468274246Sae memmove(mtodo(m, hlen), ip, sizeof(struct ip)); 469274246Sae m_adj(m, hlen); 470274246Sae m_clrprotoflags(m); 471274246Sae m->m_pkthdr.rcvif = ifp; 472274246Sae m->m_pkthdr.csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID); 473282809Sae M_SETFIB(m, ifp->if_fib); 474274246Sae hlen = AF_INET; 475274246Sae BPF_MTAP2(ifp, &hlen, sizeof(hlen), m); 476274246Sae if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 477274246Sae if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 478274246Sae if ((ifp->if_flags & IFF_MONITOR) != 0) 479274246Sae m_freem(m); 480274246Sae else 481274246Sae netisr_dispatch(NETISR_IP, m); 482274246Sae return (IPPROTO_DONE); 483274246Saedrop: 484274246Sae if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 485274246Sae return (IPPROTO_DONE); 486274246Sae} 487274246Sae 488274246Sae#define MTAG_ME 1414491977 489274246Saestatic int 490274246Saeme_check_nesting(struct ifnet *ifp, struct mbuf *m) 491274246Sae{ 492274246Sae struct m_tag *mtag; 493274246Sae int count; 494274246Sae 495274246Sae count = 1; 496274246Sae mtag = NULL; 497282536Sae while ((mtag = m_tag_locate(m, MTAG_ME, 0, mtag)) != NULL) { 498274246Sae if (*(struct ifnet **)(mtag + 1) == ifp) { 499274246Sae log(LOG_NOTICE, "%s: loop detected\n", ifp->if_xname); 500274246Sae return (EIO); 501274246Sae } 502274246Sae count++; 503274246Sae } 504274246Sae if (count > V_max_me_nesting) { 505274246Sae log(LOG_NOTICE, 506274246Sae "%s: if_output recursively called too many times(%d)\n", 507274246Sae ifp->if_xname, count); 508274246Sae return (EIO); 509274246Sae } 510274246Sae mtag = m_tag_alloc(MTAG_ME, 0, sizeof(struct ifnet *), M_NOWAIT); 511274246Sae if (mtag == NULL) 512274246Sae return (ENOMEM); 513274246Sae *(struct ifnet **)(mtag + 1) = ifp; 514274246Sae m_tag_prepend(m, mtag); 515274246Sae return (0); 516274246Sae} 517274246Sae 518274246Saestatic int 519274246Saeme_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 520274246Sae struct route *ro) 521274246Sae{ 522274246Sae uint32_t af; 523274246Sae int error; 524274246Sae 525274246Sae#ifdef MAC 526274246Sae error = mac_ifnet_check_transmit(ifp, m); 527274246Sae if (error != 0) 528274246Sae goto drop; 529274246Sae#endif 530274246Sae if ((ifp->if_flags & IFF_MONITOR) != 0 || 531274246Sae (ifp->if_flags & IFF_UP) == 0) { 532274246Sae error = ENETDOWN; 533274246Sae goto drop; 534274246Sae } 535274246Sae 536274246Sae error = me_check_nesting(ifp, m); 537274246Sae if (error != 0) 538274246Sae goto drop; 539274246Sae 540274246Sae m->m_flags &= ~(M_BCAST|M_MCAST); 541274246Sae if (dst->sa_family == AF_UNSPEC) 542274246Sae bcopy(dst->sa_data, &af, sizeof(af)); 543274246Sae else 544274246Sae af = dst->sa_family; 545274246Sae if (af != AF_INET) { 546274246Sae error = EAFNOSUPPORT; 547274246Sae goto drop; 548274246Sae } 549274246Sae BPF_MTAP2(ifp, &af, sizeof(af), m); 550274246Sae return (ifp->if_transmit(ifp, m)); 551274246Saedrop: 552274246Sae m_freem(m); 553274246Sae if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 554274246Sae return (error); 555274246Sae} 556274246Sae 557274246Saestatic int 558274246Saeme_transmit(struct ifnet *ifp, struct mbuf *m) 559274246Sae{ 560274246Sae ME_RLOCK_TRACKER; 561274246Sae struct mobhdr mh; 562274246Sae struct me_softc *sc; 563274246Sae struct ip *ip; 564274246Sae int error, hlen, plen; 565274246Sae 566274246Sae sc = ifp->if_softc; 567274246Sae if (sc == NULL) { 568274246Sae error = ENETDOWN; 569274246Sae m_freem(m); 570274246Sae goto drop; 571274246Sae } 572274246Sae if (m->m_len < sizeof(struct ip)) 573274246Sae m = m_pullup(m, sizeof(struct ip)); 574274246Sae if (m == NULL) { 575274246Sae error = ENOBUFS; 576274246Sae goto drop; 577274246Sae } 578274246Sae ip = mtod(m, struct ip *); 579274246Sae /* Fragmented datagramms shouldn't be encapsulated */ 580274246Sae if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) { 581274246Sae error = EINVAL; 582274246Sae m_freem(m); 583274246Sae goto drop; 584274246Sae } 585274246Sae mh.mob_proto = ip->ip_p; 586274246Sae mh.mob_src = ip->ip_src; 587274246Sae mh.mob_dst = ip->ip_dst; 588274246Sae ME_RLOCK(sc); 589274246Sae if (!ME_READY(sc)) { 590274246Sae ME_RUNLOCK(sc); 591274246Sae error = ENETDOWN; 592274246Sae m_freem(m); 593274246Sae goto drop; 594274246Sae } 595274246Sae if (in_hosteq(sc->me_src, ip->ip_src)) { 596274246Sae hlen = sizeof(struct mobhdr) - sizeof(struct in_addr); 597274246Sae mh.mob_flags = 0; 598274246Sae } else { 599274246Sae hlen = sizeof(struct mobhdr); 600274246Sae mh.mob_flags = MOB_FLAGS_SP; 601274246Sae } 602274246Sae plen = m->m_pkthdr.len; 603274246Sae ip->ip_src = sc->me_src; 604274246Sae ip->ip_dst = sc->me_dst; 605274246Sae M_SETFIB(m, sc->me_fibnum); 606274246Sae ME_RUNLOCK(sc); 607274246Sae M_PREPEND(m, hlen, M_NOWAIT); 608274246Sae if (m == NULL) { 609274246Sae error = ENOBUFS; 610274246Sae goto drop; 611274246Sae } 612274246Sae if (m->m_len < sizeof(struct ip) + hlen) 613274246Sae m = m_pullup(m, sizeof(struct ip) + hlen); 614274246Sae if (m == NULL) { 615274246Sae error = ENOBUFS; 616274246Sae goto drop; 617274246Sae } 618274246Sae memmove(mtod(m, void *), mtodo(m, hlen), sizeof(struct ip)); 619274246Sae ip = mtod(m, struct ip *); 620274246Sae ip->ip_len = htons(m->m_pkthdr.len); 621274246Sae ip->ip_p = IPPROTO_MOBILE; 622274246Sae ip->ip_sum = 0; 623274246Sae mh.mob_csum = 0; 624274246Sae mh.mob_csum = me_in_cksum((uint16_t *)&mh, hlen / sizeof(uint16_t)); 625274246Sae bcopy(&mh, mtodo(m, sizeof(struct ip)), hlen); 626274246Sae error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); 627274246Saedrop: 628274246Sae if (error) 629274246Sae if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 630274246Sae else { 631274246Sae if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 632274246Sae if_inc_counter(ifp, IFCOUNTER_OBYTES, plen); 633274246Sae } 634274246Sae return (error); 635274246Sae} 636274246Sae 637274246Saestatic void 638274246Saeme_qflush(struct ifnet *ifp __unused) 639274246Sae{ 640274246Sae 641274246Sae} 642274246Sae 643274246Saestatic int 644274246Saememodevent(module_t mod, int type, void *data) 645274246Sae{ 646274246Sae 647274246Sae switch (type) { 648274246Sae case MOD_LOAD: 649274246Sae case MOD_UNLOAD: 650274246Sae break; 651274246Sae default: 652274246Sae return (EOPNOTSUPP); 653274246Sae } 654274246Sae return (0); 655274246Sae} 656274246Sae 657274246Saestatic moduledata_t me_mod = { 658274246Sae "if_me", 659274246Sae memodevent, 660274246Sae 0 661274246Sae}; 662274246Sae 663274246SaeDECLARE_MODULE(if_me, me_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 664274246SaeMODULE_VERSION(if_me, 1); 665