1f325335cSAndrey V. Elsukov /*- 22addcba7SAndrey V. Elsukov * Copyright (c) 2014, 2018 Andrey V. Elsukov <ae@FreeBSD.org> 3f325335cSAndrey V. Elsukov * All rights reserved. 4f325335cSAndrey V. Elsukov * 5f325335cSAndrey V. Elsukov * Redistribution and use in source and binary forms, with or without 6f325335cSAndrey V. Elsukov * modification, are permitted provided that the following conditions 7f325335cSAndrey V. Elsukov * are met: 8f325335cSAndrey V. Elsukov * 9f325335cSAndrey V. Elsukov * 1. Redistributions of source code must retain the above copyright 10f325335cSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer. 11f325335cSAndrey V. Elsukov * 2. Redistributions in binary form must reproduce the above copyright 12f325335cSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer in the 13f325335cSAndrey V. Elsukov * documentation and/or other materials provided with the distribution. 14f325335cSAndrey V. Elsukov * 15f325335cSAndrey V. Elsukov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16f325335cSAndrey V. Elsukov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17f325335cSAndrey V. Elsukov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18f325335cSAndrey V. Elsukov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19f325335cSAndrey V. Elsukov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20f325335cSAndrey V. Elsukov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21f325335cSAndrey V. Elsukov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22f325335cSAndrey V. Elsukov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23f325335cSAndrey V. Elsukov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24f325335cSAndrey V. Elsukov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25f325335cSAndrey V. Elsukov */ 26f325335cSAndrey V. Elsukov 27f325335cSAndrey V. Elsukov #include <sys/cdefs.h> 28f325335cSAndrey V. Elsukov __FBSDID("$FreeBSD$"); 29f325335cSAndrey V. Elsukov 30f325335cSAndrey V. Elsukov #include <sys/param.h> 312addcba7SAndrey V. Elsukov #include <sys/systm.h> 32f325335cSAndrey V. Elsukov #include <sys/jail.h> 33f325335cSAndrey V. Elsukov #include <sys/kernel.h> 34f325335cSAndrey V. Elsukov #include <sys/lock.h> 35f325335cSAndrey V. Elsukov #include <sys/malloc.h> 36f325335cSAndrey V. Elsukov #include <sys/module.h> 37f325335cSAndrey V. Elsukov #include <sys/mbuf.h> 38f325335cSAndrey V. Elsukov #include <sys/priv.h> 39f325335cSAndrey V. Elsukov #include <sys/proc.h> 40f325335cSAndrey V. Elsukov #include <sys/socket.h> 41f325335cSAndrey V. Elsukov #include <sys/sockio.h> 42f325335cSAndrey V. Elsukov #include <sys/sx.h> 43f325335cSAndrey V. Elsukov #include <sys/sysctl.h> 44f325335cSAndrey V. Elsukov #include <sys/syslog.h> 45f325335cSAndrey V. Elsukov 46f325335cSAndrey V. Elsukov #include <net/bpf.h> 47f325335cSAndrey V. Elsukov #include <net/ethernet.h> 48f325335cSAndrey V. Elsukov #include <net/if.h> 49f325335cSAndrey V. Elsukov #include <net/if_var.h> 50f325335cSAndrey V. Elsukov #include <net/if_clone.h> 51f325335cSAndrey V. Elsukov #include <net/if_types.h> 52f325335cSAndrey V. Elsukov #include <net/netisr.h> 53f325335cSAndrey V. Elsukov #include <net/vnet.h> 54eccfe69aSAndrey V. Elsukov #include <net/route.h> 55f325335cSAndrey V. Elsukov 56f325335cSAndrey V. Elsukov #include <netinet/in.h> 57f325335cSAndrey V. Elsukov #include <netinet/in_systm.h> 58f325335cSAndrey V. Elsukov #include <netinet/in_var.h> 59f325335cSAndrey V. Elsukov #include <netinet/ip.h> 60f325335cSAndrey V. Elsukov #include <netinet/ip_var.h> 61f325335cSAndrey V. Elsukov #include <netinet/ip_encap.h> 62f325335cSAndrey V. Elsukov 63f325335cSAndrey V. Elsukov #include <machine/in_cksum.h> 64f325335cSAndrey V. Elsukov #include <security/mac/mac_framework.h> 65f325335cSAndrey V. Elsukov 66c00bf730SAndrey V. Elsukov #define MEMTU (1500 - sizeof(struct mobhdr)) 67f325335cSAndrey V. Elsukov static const char mename[] = "me"; 68f325335cSAndrey V. Elsukov static MALLOC_DEFINE(M_IFME, mename, "Minimal Encapsulation for IP"); 69f325335cSAndrey V. Elsukov /* Minimal forwarding header RFC 2004 */ 70f325335cSAndrey V. Elsukov struct mobhdr { 71f325335cSAndrey V. Elsukov uint8_t mob_proto; /* protocol */ 72f325335cSAndrey V. Elsukov uint8_t mob_flags; /* flags */ 73f325335cSAndrey V. Elsukov #define MOB_FLAGS_SP 0x80 /* source present */ 74f325335cSAndrey V. Elsukov uint16_t mob_csum; /* header checksum */ 75f325335cSAndrey V. Elsukov struct in_addr mob_dst; /* original destination address */ 76f325335cSAndrey V. Elsukov struct in_addr mob_src; /* original source addr (optional) */ 77f325335cSAndrey V. Elsukov } __packed; 78f325335cSAndrey V. Elsukov 79f325335cSAndrey V. Elsukov struct me_softc { 80f325335cSAndrey V. Elsukov struct ifnet *me_ifp; 81f325335cSAndrey V. Elsukov u_int me_fibnum; 82f325335cSAndrey V. Elsukov struct in_addr me_src; 83f325335cSAndrey V. Elsukov struct in_addr me_dst; 842addcba7SAndrey V. Elsukov 852addcba7SAndrey V. Elsukov CK_LIST_ENTRY(me_softc) chain; 86df49ca9fSAndrey V. Elsukov CK_LIST_ENTRY(me_softc) srchash; 87f325335cSAndrey V. Elsukov }; 882addcba7SAndrey V. Elsukov CK_LIST_HEAD(me_list, me_softc); 89f325335cSAndrey V. Elsukov #define ME2IFP(sc) ((sc)->me_ifp) 90f325335cSAndrey V. Elsukov #define ME_READY(sc) ((sc)->me_src.s_addr != 0) 91df49ca9fSAndrey V. Elsukov #define ME_RLOCK_TRACKER struct epoch_tracker me_et 92df49ca9fSAndrey V. Elsukov #define ME_RLOCK() epoch_enter_preempt(net_epoch_preempt, &me_et) 936573d758SMatt Macy #define ME_RUNLOCK() epoch_exit_preempt(net_epoch_preempt, &me_et) 942addcba7SAndrey V. Elsukov #define ME_WAIT() epoch_wait_preempt(net_epoch_preempt) 95f325335cSAndrey V. Elsukov 962addcba7SAndrey V. Elsukov #ifndef ME_HASH_SIZE 972addcba7SAndrey V. Elsukov #define ME_HASH_SIZE (1 << 4) 982addcba7SAndrey V. Elsukov #endif 995f901c92SAndrew Turner VNET_DEFINE_STATIC(struct me_list *, me_hashtbl) = NULL; 100df49ca9fSAndrey V. Elsukov VNET_DEFINE_STATIC(struct me_list *, me_srchashtbl) = NULL; 1012addcba7SAndrey V. Elsukov #define V_me_hashtbl VNET(me_hashtbl) 102df49ca9fSAndrey V. Elsukov #define V_me_srchashtbl VNET(me_srchashtbl) 1032addcba7SAndrey V. Elsukov #define ME_HASH(src, dst) (V_me_hashtbl[\ 1042addcba7SAndrey V. Elsukov me_hashval((src), (dst)) & (ME_HASH_SIZE - 1)]) 105df49ca9fSAndrey V. Elsukov #define ME_SRCHASH(src) (V_me_srchashtbl[\ 106df49ca9fSAndrey V. Elsukov fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (ME_HASH_SIZE - 1)]) 107f325335cSAndrey V. Elsukov 108f325335cSAndrey V. Elsukov static struct sx me_ioctl_sx; 109f325335cSAndrey V. Elsukov SX_SYSINIT(me_ioctl_sx, &me_ioctl_sx, "me_ioctl"); 110f325335cSAndrey V. Elsukov 111f325335cSAndrey V. Elsukov static int me_clone_create(struct if_clone *, int, caddr_t); 112f325335cSAndrey V. Elsukov static void me_clone_destroy(struct ifnet *); 1135f901c92SAndrew Turner VNET_DEFINE_STATIC(struct if_clone *, me_cloner); 114f325335cSAndrey V. Elsukov #define V_me_cloner VNET(me_cloner) 115f325335cSAndrey V. Elsukov 116dd4490fdSAndrey V. Elsukov #ifdef VIMAGE 117dd4490fdSAndrey V. Elsukov static void me_reassign(struct ifnet *, struct vnet *, char *); 118dd4490fdSAndrey V. Elsukov #endif 119f325335cSAndrey V. Elsukov static void me_qflush(struct ifnet *); 120f325335cSAndrey V. Elsukov static int me_transmit(struct ifnet *, struct mbuf *); 121f325335cSAndrey V. Elsukov static int me_ioctl(struct ifnet *, u_long, caddr_t); 122f325335cSAndrey V. Elsukov static int me_output(struct ifnet *, struct mbuf *, 123f325335cSAndrey V. Elsukov const struct sockaddr *, struct route *); 1246d8fdfa9SAndrey V. Elsukov static int me_input(struct mbuf *, int, int, void *); 125f325335cSAndrey V. Elsukov 1262addcba7SAndrey V. Elsukov static int me_set_tunnel(struct me_softc *, in_addr_t, in_addr_t); 1272addcba7SAndrey V. Elsukov static void me_delete_tunnel(struct me_softc *); 128f325335cSAndrey V. Elsukov 129f325335cSAndrey V. Elsukov SYSCTL_DECL(_net_link); 1307029da5cSPawel Biernacki static SYSCTL_NODE(_net_link, IFT_TUNNEL, me, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 131f325335cSAndrey V. Elsukov "Minimal Encapsulation for IP (RFC 2004)"); 132f325335cSAndrey V. Elsukov #ifndef MAX_ME_NEST 133f325335cSAndrey V. Elsukov #define MAX_ME_NEST 1 134f325335cSAndrey V. Elsukov #endif 135f325335cSAndrey V. Elsukov 1365f901c92SAndrew Turner VNET_DEFINE_STATIC(int, max_me_nesting) = MAX_ME_NEST; 137f325335cSAndrey V. Elsukov #define V_max_me_nesting VNET(max_me_nesting) 138f325335cSAndrey V. Elsukov SYSCTL_INT(_net_link_me, OID_AUTO, max_nesting, CTLFLAG_RW | CTLFLAG_VNET, 139f325335cSAndrey V. Elsukov &VNET_NAME(max_me_nesting), 0, "Max nested tunnels"); 140f325335cSAndrey V. Elsukov 1412addcba7SAndrey V. Elsukov static uint32_t 1422addcba7SAndrey V. Elsukov me_hashval(in_addr_t src, in_addr_t dst) 1432addcba7SAndrey V. Elsukov { 1442addcba7SAndrey V. Elsukov uint32_t ret; 1452addcba7SAndrey V. Elsukov 1462addcba7SAndrey V. Elsukov ret = fnv_32_buf(&src, sizeof(src), FNV1_32_INIT); 1472addcba7SAndrey V. Elsukov return (fnv_32_buf(&dst, sizeof(dst), ret)); 1482addcba7SAndrey V. Elsukov } 1492addcba7SAndrey V. Elsukov 1502addcba7SAndrey V. Elsukov static struct me_list * 1512addcba7SAndrey V. Elsukov me_hashinit(void) 1522addcba7SAndrey V. Elsukov { 1532addcba7SAndrey V. Elsukov struct me_list *hash; 1542addcba7SAndrey V. Elsukov int i; 1552addcba7SAndrey V. Elsukov 1562addcba7SAndrey V. Elsukov hash = malloc(sizeof(struct me_list) * ME_HASH_SIZE, 1572addcba7SAndrey V. Elsukov M_IFME, M_WAITOK); 1582addcba7SAndrey V. Elsukov for (i = 0; i < ME_HASH_SIZE; i++) 1592addcba7SAndrey V. Elsukov CK_LIST_INIT(&hash[i]); 1602addcba7SAndrey V. Elsukov 1612addcba7SAndrey V. Elsukov return (hash); 1622addcba7SAndrey V. Elsukov } 1632addcba7SAndrey V. Elsukov 164f325335cSAndrey V. Elsukov static void 165f325335cSAndrey V. Elsukov vnet_me_init(const void *unused __unused) 166f325335cSAndrey V. Elsukov { 1678796e291SAndrey V. Elsukov 168f325335cSAndrey V. Elsukov V_me_cloner = if_clone_simple(mename, me_clone_create, 169f325335cSAndrey V. Elsukov me_clone_destroy, 0); 170f325335cSAndrey V. Elsukov } 171f325335cSAndrey V. Elsukov VNET_SYSINIT(vnet_me_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 172f325335cSAndrey V. Elsukov vnet_me_init, NULL); 173f325335cSAndrey V. Elsukov 174f325335cSAndrey V. Elsukov static void 175f325335cSAndrey V. Elsukov vnet_me_uninit(const void *unused __unused) 176f325335cSAndrey V. Elsukov { 177f325335cSAndrey V. Elsukov 178df49ca9fSAndrey V. Elsukov if (V_me_hashtbl != NULL) { 1792addcba7SAndrey V. Elsukov free(V_me_hashtbl, M_IFME); 1808796e291SAndrey V. Elsukov V_me_hashtbl = NULL; 1818796e291SAndrey V. Elsukov ME_WAIT(); 182df49ca9fSAndrey V. Elsukov free(V_me_srchashtbl, M_IFME); 183df49ca9fSAndrey V. Elsukov } 184f325335cSAndrey V. Elsukov if_clone_detach(V_me_cloner); 185f325335cSAndrey V. Elsukov } 186f325335cSAndrey V. Elsukov VNET_SYSUNINIT(vnet_me_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 187f325335cSAndrey V. Elsukov vnet_me_uninit, NULL); 188f325335cSAndrey V. Elsukov 189f325335cSAndrey V. Elsukov static int 190f325335cSAndrey V. Elsukov me_clone_create(struct if_clone *ifc, int unit, caddr_t params) 191f325335cSAndrey V. Elsukov { 192f325335cSAndrey V. Elsukov struct me_softc *sc; 193f325335cSAndrey V. Elsukov 194f325335cSAndrey V. Elsukov sc = malloc(sizeof(struct me_softc), M_IFME, M_WAITOK | M_ZERO); 195f325335cSAndrey V. Elsukov sc->me_fibnum = curthread->td_proc->p_fibnum; 196f325335cSAndrey V. Elsukov ME2IFP(sc) = if_alloc(IFT_TUNNEL); 197f325335cSAndrey V. Elsukov ME2IFP(sc)->if_softc = sc; 198f325335cSAndrey V. Elsukov if_initname(ME2IFP(sc), mename, unit); 199f325335cSAndrey V. Elsukov 200aeb665b5SEd Maste ME2IFP(sc)->if_mtu = MEMTU; 201f325335cSAndrey V. Elsukov ME2IFP(sc)->if_flags = IFF_POINTOPOINT|IFF_MULTICAST; 202f325335cSAndrey V. Elsukov ME2IFP(sc)->if_output = me_output; 203f325335cSAndrey V. Elsukov ME2IFP(sc)->if_ioctl = me_ioctl; 204f325335cSAndrey V. Elsukov ME2IFP(sc)->if_transmit = me_transmit; 205f325335cSAndrey V. Elsukov ME2IFP(sc)->if_qflush = me_qflush; 206dd4490fdSAndrey V. Elsukov #ifdef VIMAGE 207dd4490fdSAndrey V. Elsukov ME2IFP(sc)->if_reassign = me_reassign; 208dd4490fdSAndrey V. Elsukov #endif 209f1aaad0cSHiroki Sato ME2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE; 210f1aaad0cSHiroki Sato ME2IFP(sc)->if_capenable |= IFCAP_LINKSTATE; 211f325335cSAndrey V. Elsukov if_attach(ME2IFP(sc)); 212f325335cSAndrey V. Elsukov bpfattach(ME2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 213f325335cSAndrey V. Elsukov return (0); 214f325335cSAndrey V. Elsukov } 215f325335cSAndrey V. Elsukov 216dd4490fdSAndrey V. Elsukov #ifdef VIMAGE 217dd4490fdSAndrey V. Elsukov static void 218dd4490fdSAndrey V. Elsukov me_reassign(struct ifnet *ifp, struct vnet *new_vnet __unused, 219dd4490fdSAndrey V. Elsukov char *unused __unused) 220dd4490fdSAndrey V. Elsukov { 221dd4490fdSAndrey V. Elsukov struct me_softc *sc; 222dd4490fdSAndrey V. Elsukov 223dd4490fdSAndrey V. Elsukov sx_xlock(&me_ioctl_sx); 224dd4490fdSAndrey V. Elsukov sc = ifp->if_softc; 225dd4490fdSAndrey V. Elsukov if (sc != NULL) 226dd4490fdSAndrey V. Elsukov me_delete_tunnel(sc); 227dd4490fdSAndrey V. Elsukov sx_xunlock(&me_ioctl_sx); 228dd4490fdSAndrey V. Elsukov } 229dd4490fdSAndrey V. Elsukov #endif /* VIMAGE */ 230dd4490fdSAndrey V. Elsukov 231f325335cSAndrey V. Elsukov static void 232f325335cSAndrey V. Elsukov me_clone_destroy(struct ifnet *ifp) 233f325335cSAndrey V. Elsukov { 234f325335cSAndrey V. Elsukov struct me_softc *sc; 235f325335cSAndrey V. Elsukov 236f325335cSAndrey V. Elsukov sx_xlock(&me_ioctl_sx); 237f325335cSAndrey V. Elsukov sc = ifp->if_softc; 2382addcba7SAndrey V. Elsukov me_delete_tunnel(sc); 239f325335cSAndrey V. Elsukov bpfdetach(ifp); 240f325335cSAndrey V. Elsukov if_detach(ifp); 241f325335cSAndrey V. Elsukov ifp->if_softc = NULL; 242f325335cSAndrey V. Elsukov sx_xunlock(&me_ioctl_sx); 243f325335cSAndrey V. Elsukov 2442addcba7SAndrey V. Elsukov ME_WAIT(); 245f325335cSAndrey V. Elsukov if_free(ifp); 246f325335cSAndrey V. Elsukov free(sc, M_IFME); 247f325335cSAndrey V. Elsukov } 248f325335cSAndrey V. Elsukov 249f325335cSAndrey V. Elsukov static int 250f325335cSAndrey V. Elsukov me_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 251f325335cSAndrey V. Elsukov { 252f325335cSAndrey V. Elsukov struct ifreq *ifr = (struct ifreq *)data; 253f325335cSAndrey V. Elsukov struct sockaddr_in *src, *dst; 254f325335cSAndrey V. Elsukov struct me_softc *sc; 255f325335cSAndrey V. Elsukov int error; 256f325335cSAndrey V. Elsukov 257f325335cSAndrey V. Elsukov switch (cmd) { 258f325335cSAndrey V. Elsukov case SIOCSIFMTU: 259f325335cSAndrey V. Elsukov if (ifr->ifr_mtu < 576) 260f325335cSAndrey V. Elsukov return (EINVAL); 261c00bf730SAndrey V. Elsukov ifp->if_mtu = ifr->ifr_mtu; 262f325335cSAndrey V. Elsukov return (0); 263f325335cSAndrey V. Elsukov case SIOCSIFADDR: 264f325335cSAndrey V. Elsukov ifp->if_flags |= IFF_UP; 265f325335cSAndrey V. Elsukov case SIOCSIFFLAGS: 266f325335cSAndrey V. Elsukov case SIOCADDMULTI: 267f325335cSAndrey V. Elsukov case SIOCDELMULTI: 268f325335cSAndrey V. Elsukov return (0); 269f325335cSAndrey V. Elsukov } 270f325335cSAndrey V. Elsukov sx_xlock(&me_ioctl_sx); 271f325335cSAndrey V. Elsukov sc = ifp->if_softc; 272f325335cSAndrey V. Elsukov if (sc == NULL) { 273f325335cSAndrey V. Elsukov error = ENXIO; 274f325335cSAndrey V. Elsukov goto end; 275f325335cSAndrey V. Elsukov } 276f325335cSAndrey V. Elsukov error = 0; 277f325335cSAndrey V. Elsukov switch (cmd) { 278f325335cSAndrey V. Elsukov case SIOCSIFPHYADDR: 2792addcba7SAndrey V. Elsukov src = &((struct in_aliasreq *)data)->ifra_addr; 2802addcba7SAndrey V. Elsukov dst = &((struct in_aliasreq *)data)->ifra_dstaddr; 281f325335cSAndrey V. Elsukov if (src->sin_family != dst->sin_family || 282f325335cSAndrey V. Elsukov src->sin_family != AF_INET || 283f325335cSAndrey V. Elsukov src->sin_len != dst->sin_len || 284f325335cSAndrey V. Elsukov src->sin_len != sizeof(struct sockaddr_in)) { 285f325335cSAndrey V. Elsukov error = EINVAL; 286f325335cSAndrey V. Elsukov break; 287f325335cSAndrey V. Elsukov } 288f325335cSAndrey V. Elsukov if (src->sin_addr.s_addr == INADDR_ANY || 289f325335cSAndrey V. Elsukov dst->sin_addr.s_addr == INADDR_ANY) { 290f325335cSAndrey V. Elsukov error = EADDRNOTAVAIL; 291f325335cSAndrey V. Elsukov break; 292f325335cSAndrey V. Elsukov } 2932addcba7SAndrey V. Elsukov error = me_set_tunnel(sc, src->sin_addr.s_addr, 2942addcba7SAndrey V. Elsukov dst->sin_addr.s_addr); 295f325335cSAndrey V. Elsukov break; 296f325335cSAndrey V. Elsukov case SIOCDIFPHYADDR: 2972addcba7SAndrey V. Elsukov me_delete_tunnel(sc); 298f325335cSAndrey V. Elsukov break; 299f325335cSAndrey V. Elsukov case SIOCGIFPSRCADDR: 300f325335cSAndrey V. Elsukov case SIOCGIFPDSTADDR: 301f325335cSAndrey V. Elsukov if (!ME_READY(sc)) { 302f325335cSAndrey V. Elsukov error = EADDRNOTAVAIL; 303f325335cSAndrey V. Elsukov break; 304f325335cSAndrey V. Elsukov } 305f325335cSAndrey V. Elsukov src = (struct sockaddr_in *)&ifr->ifr_addr; 306f325335cSAndrey V. Elsukov memset(src, 0, sizeof(*src)); 307f325335cSAndrey V. Elsukov src->sin_family = AF_INET; 308f325335cSAndrey V. Elsukov src->sin_len = sizeof(*src); 309f325335cSAndrey V. Elsukov switch (cmd) { 310f325335cSAndrey V. Elsukov case SIOCGIFPSRCADDR: 311f325335cSAndrey V. Elsukov src->sin_addr = sc->me_src; 312f325335cSAndrey V. Elsukov break; 313f325335cSAndrey V. Elsukov case SIOCGIFPDSTADDR: 314f325335cSAndrey V. Elsukov src->sin_addr = sc->me_dst; 315f325335cSAndrey V. Elsukov break; 316f325335cSAndrey V. Elsukov } 317f325335cSAndrey V. Elsukov error = prison_if(curthread->td_ucred, sintosa(src)); 318f325335cSAndrey V. Elsukov if (error != 0) 319f325335cSAndrey V. Elsukov memset(src, 0, sizeof(*src)); 320f325335cSAndrey V. Elsukov break; 321eccfe69aSAndrey V. Elsukov case SIOCGTUNFIB: 322eccfe69aSAndrey V. Elsukov ifr->ifr_fib = sc->me_fibnum; 323eccfe69aSAndrey V. Elsukov break; 324eccfe69aSAndrey V. Elsukov case SIOCSTUNFIB: 325*43f8c763SZhenlei Huang if ((error = priv_check(curthread, PRIV_NET_ME)) != 0) 326eccfe69aSAndrey V. Elsukov break; 327eccfe69aSAndrey V. Elsukov if (ifr->ifr_fib >= rt_numfibs) 328eccfe69aSAndrey V. Elsukov error = EINVAL; 329eccfe69aSAndrey V. Elsukov else 330eccfe69aSAndrey V. Elsukov sc->me_fibnum = ifr->ifr_fib; 331eccfe69aSAndrey V. Elsukov break; 332f325335cSAndrey V. Elsukov default: 333f325335cSAndrey V. Elsukov error = EINVAL; 334f325335cSAndrey V. Elsukov break; 335f325335cSAndrey V. Elsukov } 336f325335cSAndrey V. Elsukov end: 337f325335cSAndrey V. Elsukov sx_xunlock(&me_ioctl_sx); 338f325335cSAndrey V. Elsukov return (error); 339f325335cSAndrey V. Elsukov } 340f325335cSAndrey V. Elsukov 341f325335cSAndrey V. Elsukov static int 3422addcba7SAndrey V. Elsukov me_lookup(const struct mbuf *m, int off, int proto, void **arg) 343f325335cSAndrey V. Elsukov { 3442addcba7SAndrey V. Elsukov const struct ip *ip; 345f325335cSAndrey V. Elsukov struct me_softc *sc; 346f325335cSAndrey V. Elsukov 3476e081509SAndrey V. Elsukov if (V_me_hashtbl == NULL) 3486e081509SAndrey V. Elsukov return (0); 3496e081509SAndrey V. Elsukov 35097168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 3512addcba7SAndrey V. Elsukov ip = mtod(m, const struct ip *); 3522addcba7SAndrey V. Elsukov CK_LIST_FOREACH(sc, &ME_HASH(ip->ip_dst.s_addr, 3532addcba7SAndrey V. Elsukov ip->ip_src.s_addr), chain) { 3542addcba7SAndrey V. Elsukov if (sc->me_src.s_addr == ip->ip_dst.s_addr && 3552addcba7SAndrey V. Elsukov sc->me_dst.s_addr == ip->ip_src.s_addr) { 356f325335cSAndrey V. Elsukov if ((ME2IFP(sc)->if_flags & IFF_UP) == 0) 357f325335cSAndrey V. Elsukov return (0); 3582addcba7SAndrey V. Elsukov *arg = sc; 3592addcba7SAndrey V. Elsukov return (ENCAP_DRV_LOOKUP); 360f325335cSAndrey V. Elsukov } 3612addcba7SAndrey V. Elsukov } 3622addcba7SAndrey V. Elsukov return (0); 363f325335cSAndrey V. Elsukov } 364f325335cSAndrey V. Elsukov 365df49ca9fSAndrey V. Elsukov /* 366df49ca9fSAndrey V. Elsukov * Check that ingress address belongs to local host. 367df49ca9fSAndrey V. Elsukov */ 368df49ca9fSAndrey V. Elsukov static void 369df49ca9fSAndrey V. Elsukov me_set_running(struct me_softc *sc) 370df49ca9fSAndrey V. Elsukov { 371df49ca9fSAndrey V. Elsukov 372df49ca9fSAndrey V. Elsukov if (in_localip(sc->me_src)) 373df49ca9fSAndrey V. Elsukov ME2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING; 374df49ca9fSAndrey V. Elsukov else 375df49ca9fSAndrey V. Elsukov ME2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 376df49ca9fSAndrey V. Elsukov } 377df49ca9fSAndrey V. Elsukov 378df49ca9fSAndrey V. Elsukov /* 379df49ca9fSAndrey V. Elsukov * ifaddr_event handler. 380df49ca9fSAndrey V. Elsukov * Clear IFF_DRV_RUNNING flag when ingress address disappears to prevent 381df49ca9fSAndrey V. Elsukov * source address spoofing. 382df49ca9fSAndrey V. Elsukov */ 383df49ca9fSAndrey V. Elsukov static void 384df49ca9fSAndrey V. Elsukov me_srcaddr(void *arg __unused, const struct sockaddr *sa, 385df49ca9fSAndrey V. Elsukov int event __unused) 386df49ca9fSAndrey V. Elsukov { 387df49ca9fSAndrey V. Elsukov const struct sockaddr_in *sin; 388df49ca9fSAndrey V. Elsukov struct me_softc *sc; 389df49ca9fSAndrey V. Elsukov 3908796e291SAndrey V. Elsukov /* Check that VNET is ready */ 3918796e291SAndrey V. Elsukov if (V_me_hashtbl == NULL) 392df49ca9fSAndrey V. Elsukov return; 393df49ca9fSAndrey V. Elsukov 39497168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 395df49ca9fSAndrey V. Elsukov sin = (const struct sockaddr_in *)sa; 396df49ca9fSAndrey V. Elsukov CK_LIST_FOREACH(sc, &ME_SRCHASH(sin->sin_addr.s_addr), srchash) { 397df49ca9fSAndrey V. Elsukov if (sc->me_src.s_addr != sin->sin_addr.s_addr) 398df49ca9fSAndrey V. Elsukov continue; 399df49ca9fSAndrey V. Elsukov me_set_running(sc); 400df49ca9fSAndrey V. Elsukov } 401df49ca9fSAndrey V. Elsukov } 402df49ca9fSAndrey V. Elsukov 403f325335cSAndrey V. Elsukov static int 4042addcba7SAndrey V. Elsukov me_set_tunnel(struct me_softc *sc, in_addr_t src, in_addr_t dst) 405f325335cSAndrey V. Elsukov { 406c8ee75f2SGleb Smirnoff struct epoch_tracker et; 4072addcba7SAndrey V. Elsukov struct me_softc *tmp; 408f325335cSAndrey V. Elsukov 409f325335cSAndrey V. Elsukov sx_assert(&me_ioctl_sx, SA_XLOCKED); 4102addcba7SAndrey V. Elsukov 411df49ca9fSAndrey V. Elsukov if (V_me_hashtbl == NULL) { 4122addcba7SAndrey V. Elsukov V_me_hashtbl = me_hashinit(); 413df49ca9fSAndrey V. Elsukov V_me_srchashtbl = me_hashinit(); 414df49ca9fSAndrey V. Elsukov } 4152addcba7SAndrey V. Elsukov 4162addcba7SAndrey V. Elsukov if (sc->me_src.s_addr == src && sc->me_dst.s_addr == dst) 4172addcba7SAndrey V. Elsukov return (0); 4182addcba7SAndrey V. Elsukov 4192addcba7SAndrey V. Elsukov CK_LIST_FOREACH(tmp, &ME_HASH(src, dst), chain) { 4202addcba7SAndrey V. Elsukov if (tmp == sc) 421f325335cSAndrey V. Elsukov continue; 4222addcba7SAndrey V. Elsukov if (tmp->me_src.s_addr == src && 4232addcba7SAndrey V. Elsukov tmp->me_dst.s_addr == dst) 424f325335cSAndrey V. Elsukov return (EADDRNOTAVAIL); 425f325335cSAndrey V. Elsukov } 426f325335cSAndrey V. Elsukov 4272addcba7SAndrey V. Elsukov me_delete_tunnel(sc); 4282addcba7SAndrey V. Elsukov sc->me_dst.s_addr = dst; 4292addcba7SAndrey V. Elsukov sc->me_src.s_addr = src; 4302addcba7SAndrey V. Elsukov CK_LIST_INSERT_HEAD(&ME_HASH(src, dst), sc, chain); 431df49ca9fSAndrey V. Elsukov CK_LIST_INSERT_HEAD(&ME_SRCHASH(src), sc, srchash); 432f325335cSAndrey V. Elsukov 433c8ee75f2SGleb Smirnoff NET_EPOCH_ENTER(et); 434df49ca9fSAndrey V. Elsukov me_set_running(sc); 435c8ee75f2SGleb Smirnoff NET_EPOCH_EXIT(et); 4362addcba7SAndrey V. Elsukov if_link_state_change(ME2IFP(sc), LINK_STATE_UP); 437f325335cSAndrey V. Elsukov return (0); 438f325335cSAndrey V. Elsukov } 439f325335cSAndrey V. Elsukov 440f325335cSAndrey V. Elsukov static void 4412addcba7SAndrey V. Elsukov me_delete_tunnel(struct me_softc *sc) 442f325335cSAndrey V. Elsukov { 443f325335cSAndrey V. Elsukov 444f325335cSAndrey V. Elsukov sx_assert(&me_ioctl_sx, SA_XLOCKED); 4452addcba7SAndrey V. Elsukov if (ME_READY(sc)) { 4462addcba7SAndrey V. Elsukov CK_LIST_REMOVE(sc, chain); 447df49ca9fSAndrey V. Elsukov CK_LIST_REMOVE(sc, srchash); 4482addcba7SAndrey V. Elsukov ME_WAIT(); 4492addcba7SAndrey V. Elsukov 450f325335cSAndrey V. Elsukov sc->me_src.s_addr = 0; 451f325335cSAndrey V. Elsukov sc->me_dst.s_addr = 0; 4522addcba7SAndrey V. Elsukov ME2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 4532addcba7SAndrey V. Elsukov if_link_state_change(ME2IFP(sc), LINK_STATE_DOWN); 4542addcba7SAndrey V. Elsukov } 455f325335cSAndrey V. Elsukov } 456f325335cSAndrey V. Elsukov 457f325335cSAndrey V. Elsukov static uint16_t 458f325335cSAndrey V. Elsukov me_in_cksum(uint16_t *p, int nwords) 459f325335cSAndrey V. Elsukov { 460f325335cSAndrey V. Elsukov uint32_t sum = 0; 461f325335cSAndrey V. Elsukov 462f325335cSAndrey V. Elsukov while (nwords-- > 0) 463f325335cSAndrey V. Elsukov sum += *p++; 464f325335cSAndrey V. Elsukov sum = (sum >> 16) + (sum & 0xffff); 465f325335cSAndrey V. Elsukov sum += (sum >> 16); 466f325335cSAndrey V. Elsukov return (~sum); 467f325335cSAndrey V. Elsukov } 468f325335cSAndrey V. Elsukov 4696d8fdfa9SAndrey V. Elsukov static int 4706d8fdfa9SAndrey V. Elsukov me_input(struct mbuf *m, int off, int proto, void *arg) 471f325335cSAndrey V. Elsukov { 4726d8fdfa9SAndrey V. Elsukov struct me_softc *sc = arg; 473f325335cSAndrey V. Elsukov struct mobhdr *mh; 474f325335cSAndrey V. Elsukov struct ifnet *ifp; 475f325335cSAndrey V. Elsukov struct ip *ip; 476f325335cSAndrey V. Elsukov int hlen; 477f325335cSAndrey V. Elsukov 478b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 479b8a6e03fSGleb Smirnoff 480f325335cSAndrey V. Elsukov ifp = ME2IFP(sc); 481f325335cSAndrey V. Elsukov /* checks for short packets */ 482f325335cSAndrey V. Elsukov hlen = sizeof(struct mobhdr); 483f325335cSAndrey V. Elsukov if (m->m_pkthdr.len < sizeof(struct ip) + hlen) 484f325335cSAndrey V. Elsukov hlen -= sizeof(struct in_addr); 485f325335cSAndrey V. Elsukov if (m->m_len < sizeof(struct ip) + hlen) 486f325335cSAndrey V. Elsukov m = m_pullup(m, sizeof(struct ip) + hlen); 487f325335cSAndrey V. Elsukov if (m == NULL) 488f325335cSAndrey V. Elsukov goto drop; 489f325335cSAndrey V. Elsukov mh = (struct mobhdr *)mtodo(m, sizeof(struct ip)); 490f325335cSAndrey V. Elsukov /* check for wrong flags */ 491f325335cSAndrey V. Elsukov if (mh->mob_flags & (~MOB_FLAGS_SP)) { 492f325335cSAndrey V. Elsukov m_freem(m); 493f325335cSAndrey V. Elsukov goto drop; 494f325335cSAndrey V. Elsukov } 495f325335cSAndrey V. Elsukov if (mh->mob_flags) { 496f325335cSAndrey V. Elsukov if (hlen != sizeof(struct mobhdr)) { 497f325335cSAndrey V. Elsukov m_freem(m); 498f325335cSAndrey V. Elsukov goto drop; 499f325335cSAndrey V. Elsukov } 500f325335cSAndrey V. Elsukov } else 501f325335cSAndrey V. Elsukov hlen = sizeof(struct mobhdr) - sizeof(struct in_addr); 502f325335cSAndrey V. Elsukov /* check mobile header checksum */ 503f325335cSAndrey V. Elsukov if (me_in_cksum((uint16_t *)mh, hlen / sizeof(uint16_t)) != 0) { 504f325335cSAndrey V. Elsukov m_freem(m); 505f325335cSAndrey V. Elsukov goto drop; 506f325335cSAndrey V. Elsukov } 507f325335cSAndrey V. Elsukov #ifdef MAC 508f325335cSAndrey V. Elsukov mac_ifnet_create_mbuf(ifp, m); 509f325335cSAndrey V. Elsukov #endif 510f325335cSAndrey V. Elsukov ip = mtod(m, struct ip *); 511f325335cSAndrey V. Elsukov ip->ip_dst = mh->mob_dst; 512f325335cSAndrey V. Elsukov ip->ip_p = mh->mob_proto; 513f325335cSAndrey V. Elsukov ip->ip_sum = 0; 514f325335cSAndrey V. Elsukov ip->ip_len = htons(m->m_pkthdr.len - hlen); 515f325335cSAndrey V. Elsukov if (mh->mob_flags) 516f325335cSAndrey V. Elsukov ip->ip_src = mh->mob_src; 517f325335cSAndrey V. Elsukov memmove(mtodo(m, hlen), ip, sizeof(struct ip)); 518f325335cSAndrey V. Elsukov m_adj(m, hlen); 519f325335cSAndrey V. Elsukov m_clrprotoflags(m); 520f325335cSAndrey V. Elsukov m->m_pkthdr.rcvif = ifp; 521f325335cSAndrey V. Elsukov m->m_pkthdr.csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID); 522eccfe69aSAndrey V. Elsukov M_SETFIB(m, ifp->if_fib); 523f325335cSAndrey V. Elsukov hlen = AF_INET; 524f325335cSAndrey V. Elsukov BPF_MTAP2(ifp, &hlen, sizeof(hlen), m); 525f325335cSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 526f325335cSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 527f325335cSAndrey V. Elsukov if ((ifp->if_flags & IFF_MONITOR) != 0) 528f325335cSAndrey V. Elsukov m_freem(m); 529f325335cSAndrey V. Elsukov else 530f325335cSAndrey V. Elsukov netisr_dispatch(NETISR_IP, m); 531f325335cSAndrey V. Elsukov return (IPPROTO_DONE); 532f325335cSAndrey V. Elsukov drop: 533f325335cSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 534f325335cSAndrey V. Elsukov return (IPPROTO_DONE); 535f325335cSAndrey V. Elsukov } 536f325335cSAndrey V. Elsukov 537f325335cSAndrey V. Elsukov static int 538f325335cSAndrey V. Elsukov me_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 53962e1a437SZhenlei Huang struct route *ro) 540f325335cSAndrey V. Elsukov { 541f325335cSAndrey V. Elsukov uint32_t af; 5422addcba7SAndrey V. Elsukov 5432addcba7SAndrey V. Elsukov if (dst->sa_family == AF_UNSPEC) 5442addcba7SAndrey V. Elsukov bcopy(dst->sa_data, &af, sizeof(af)); 5452addcba7SAndrey V. Elsukov else 54662e1a437SZhenlei Huang af = RO_GET_FAMILY(ro, dst); 5472addcba7SAndrey V. Elsukov m->m_pkthdr.csum_data = af; 5482addcba7SAndrey V. Elsukov return (ifp->if_transmit(ifp, m)); 5492addcba7SAndrey V. Elsukov } 5502addcba7SAndrey V. Elsukov 55198a8fdf6SAndrey V. Elsukov #define MTAG_ME 1414491977 5522addcba7SAndrey V. Elsukov static int 5532addcba7SAndrey V. Elsukov me_transmit(struct ifnet *ifp, struct mbuf *m) 5542addcba7SAndrey V. Elsukov { 555df49ca9fSAndrey V. Elsukov ME_RLOCK_TRACKER; 5562addcba7SAndrey V. Elsukov struct mobhdr mh; 5572addcba7SAndrey V. Elsukov struct me_softc *sc; 5582addcba7SAndrey V. Elsukov struct ip *ip; 5592addcba7SAndrey V. Elsukov uint32_t af; 5602addcba7SAndrey V. Elsukov int error, hlen, plen; 561f325335cSAndrey V. Elsukov 5620a27163fSGleb Smirnoff ME_RLOCK(); 563f325335cSAndrey V. Elsukov #ifdef MAC 564f325335cSAndrey V. Elsukov error = mac_ifnet_check_transmit(ifp, m); 565f325335cSAndrey V. Elsukov if (error != 0) 566f325335cSAndrey V. Elsukov goto drop; 567f325335cSAndrey V. Elsukov #endif 568f325335cSAndrey V. Elsukov error = ENETDOWN; 5692addcba7SAndrey V. Elsukov sc = ifp->if_softc; 5702addcba7SAndrey V. Elsukov if (sc == NULL || !ME_READY(sc) || 5712addcba7SAndrey V. Elsukov (ifp->if_flags & IFF_MONITOR) != 0 || 5722addcba7SAndrey V. Elsukov (ifp->if_flags & IFF_UP) == 0 || 573df49ca9fSAndrey V. Elsukov (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 57498a8fdf6SAndrey V. Elsukov (error = if_tunnel_check_nesting(ifp, m, MTAG_ME, 57598a8fdf6SAndrey V. Elsukov V_max_me_nesting)) != 0) { 5762addcba7SAndrey V. Elsukov m_freem(m); 577f325335cSAndrey V. Elsukov goto drop; 578f325335cSAndrey V. Elsukov } 5792addcba7SAndrey V. Elsukov af = m->m_pkthdr.csum_data; 580f325335cSAndrey V. Elsukov if (af != AF_INET) { 581f325335cSAndrey V. Elsukov error = EAFNOSUPPORT; 582f325335cSAndrey V. Elsukov m_freem(m); 583f325335cSAndrey V. Elsukov goto drop; 584f325335cSAndrey V. Elsukov } 585f325335cSAndrey V. Elsukov if (m->m_len < sizeof(struct ip)) 586f325335cSAndrey V. Elsukov m = m_pullup(m, sizeof(struct ip)); 587f325335cSAndrey V. Elsukov if (m == NULL) { 588f325335cSAndrey V. Elsukov error = ENOBUFS; 589f325335cSAndrey V. Elsukov goto drop; 590f325335cSAndrey V. Elsukov } 591f325335cSAndrey V. Elsukov ip = mtod(m, struct ip *); 592f325335cSAndrey V. Elsukov /* Fragmented datagramms shouldn't be encapsulated */ 593f325335cSAndrey V. Elsukov if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) { 594f325335cSAndrey V. Elsukov error = EINVAL; 595f325335cSAndrey V. Elsukov m_freem(m); 596f325335cSAndrey V. Elsukov goto drop; 597f325335cSAndrey V. Elsukov } 598f325335cSAndrey V. Elsukov mh.mob_proto = ip->ip_p; 599f325335cSAndrey V. Elsukov mh.mob_src = ip->ip_src; 600f325335cSAndrey V. Elsukov mh.mob_dst = ip->ip_dst; 601f325335cSAndrey V. Elsukov if (in_hosteq(sc->me_src, ip->ip_src)) { 602f325335cSAndrey V. Elsukov hlen = sizeof(struct mobhdr) - sizeof(struct in_addr); 603f325335cSAndrey V. Elsukov mh.mob_flags = 0; 604f325335cSAndrey V. Elsukov } else { 605f325335cSAndrey V. Elsukov hlen = sizeof(struct mobhdr); 606f325335cSAndrey V. Elsukov mh.mob_flags = MOB_FLAGS_SP; 607f325335cSAndrey V. Elsukov } 6089597ff83SAndrey V. Elsukov BPF_MTAP2(ifp, &af, sizeof(af), m); 609f325335cSAndrey V. Elsukov plen = m->m_pkthdr.len; 610f325335cSAndrey V. Elsukov ip->ip_src = sc->me_src; 611f325335cSAndrey V. Elsukov ip->ip_dst = sc->me_dst; 6122addcba7SAndrey V. Elsukov m->m_flags &= ~(M_BCAST|M_MCAST); 613f325335cSAndrey V. Elsukov M_SETFIB(m, sc->me_fibnum); 614f325335cSAndrey V. Elsukov M_PREPEND(m, hlen, M_NOWAIT); 615f325335cSAndrey V. Elsukov if (m == NULL) { 616f325335cSAndrey V. Elsukov error = ENOBUFS; 617f325335cSAndrey V. Elsukov goto drop; 618f325335cSAndrey V. Elsukov } 619f325335cSAndrey V. Elsukov if (m->m_len < sizeof(struct ip) + hlen) 620f325335cSAndrey V. Elsukov m = m_pullup(m, sizeof(struct ip) + hlen); 621f325335cSAndrey V. Elsukov if (m == NULL) { 622f325335cSAndrey V. Elsukov error = ENOBUFS; 623f325335cSAndrey V. Elsukov goto drop; 624f325335cSAndrey V. Elsukov } 625f325335cSAndrey V. Elsukov memmove(mtod(m, void *), mtodo(m, hlen), sizeof(struct ip)); 626f325335cSAndrey V. Elsukov ip = mtod(m, struct ip *); 627f325335cSAndrey V. Elsukov ip->ip_len = htons(m->m_pkthdr.len); 628f325335cSAndrey V. Elsukov ip->ip_p = IPPROTO_MOBILE; 629f325335cSAndrey V. Elsukov ip->ip_sum = 0; 630f325335cSAndrey V. Elsukov mh.mob_csum = 0; 631f325335cSAndrey V. Elsukov mh.mob_csum = me_in_cksum((uint16_t *)&mh, hlen / sizeof(uint16_t)); 632f325335cSAndrey V. Elsukov bcopy(&mh, mtodo(m, sizeof(struct ip)), hlen); 633f325335cSAndrey V. Elsukov error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); 634f325335cSAndrey V. Elsukov drop: 635f325335cSAndrey V. Elsukov if (error) 636f325335cSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 637f325335cSAndrey V. Elsukov else { 638f325335cSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 639f325335cSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OBYTES, plen); 640f325335cSAndrey V. Elsukov } 6412addcba7SAndrey V. Elsukov ME_RUNLOCK(); 642f325335cSAndrey V. Elsukov return (error); 643f325335cSAndrey V. Elsukov } 644f325335cSAndrey V. Elsukov 645f325335cSAndrey V. Elsukov static void 646f325335cSAndrey V. Elsukov me_qflush(struct ifnet *ifp __unused) 647f325335cSAndrey V. Elsukov { 648f325335cSAndrey V. Elsukov 649f325335cSAndrey V. Elsukov } 650f325335cSAndrey V. Elsukov 651df49ca9fSAndrey V. Elsukov static const struct srcaddrtab *me_srcaddrtab = NULL; 6522addcba7SAndrey V. Elsukov static const struct encaptab *ecookie = NULL; 6532addcba7SAndrey V. Elsukov static const struct encap_config me_encap_cfg = { 6542addcba7SAndrey V. Elsukov .proto = IPPROTO_MOBILE, 6552addcba7SAndrey V. Elsukov .min_length = sizeof(struct ip) + sizeof(struct mobhdr) - 6562addcba7SAndrey V. Elsukov sizeof(in_addr_t), 6572addcba7SAndrey V. Elsukov .exact_match = ENCAP_DRV_LOOKUP, 6582addcba7SAndrey V. Elsukov .lookup = me_lookup, 6592addcba7SAndrey V. Elsukov .input = me_input 6602addcba7SAndrey V. Elsukov }; 6612addcba7SAndrey V. Elsukov 662f325335cSAndrey V. Elsukov static int 663f325335cSAndrey V. Elsukov memodevent(module_t mod, int type, void *data) 664f325335cSAndrey V. Elsukov { 665f325335cSAndrey V. Elsukov 666f325335cSAndrey V. Elsukov switch (type) { 667f325335cSAndrey V. Elsukov case MOD_LOAD: 668df49ca9fSAndrey V. Elsukov me_srcaddrtab = ip_encap_register_srcaddr(me_srcaddr, 669df49ca9fSAndrey V. Elsukov NULL, M_WAITOK); 6702addcba7SAndrey V. Elsukov ecookie = ip_encap_attach(&me_encap_cfg, NULL, M_WAITOK); 6712addcba7SAndrey V. Elsukov break; 672f325335cSAndrey V. Elsukov case MOD_UNLOAD: 6732addcba7SAndrey V. Elsukov ip_encap_detach(ecookie); 674df49ca9fSAndrey V. Elsukov ip_encap_unregister_srcaddr(me_srcaddrtab); 675f325335cSAndrey V. Elsukov break; 676f325335cSAndrey V. Elsukov default: 677f325335cSAndrey V. Elsukov return (EOPNOTSUPP); 678f325335cSAndrey V. Elsukov } 679f325335cSAndrey V. Elsukov return (0); 680f325335cSAndrey V. Elsukov } 681f325335cSAndrey V. Elsukov 682f325335cSAndrey V. Elsukov static moduledata_t me_mod = { 683f325335cSAndrey V. Elsukov "if_me", 684f325335cSAndrey V. Elsukov memodevent, 685f325335cSAndrey V. Elsukov 0 686f325335cSAndrey V. Elsukov }; 687f325335cSAndrey V. Elsukov 688f325335cSAndrey V. Elsukov DECLARE_MODULE(if_me, me_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 689f325335cSAndrey V. Elsukov MODULE_VERSION(if_me, 1); 690