if_me.c revision 282809
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: head/sys/net/if_me.c 282809 2015-05-12 07:37:27Z ae $");
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;
195274246Sae	if_attach(ME2IFP(sc));
196274246Sae	bpfattach(ME2IFP(sc), DLT_NULL, sizeof(u_int32_t));
197274246Sae	ME_LIST_LOCK();
198274246Sae	LIST_INSERT_HEAD(&V_me_softc_list, sc, me_list);
199274246Sae	ME_LIST_UNLOCK();
200274246Sae	return (0);
201274246Sae}
202274246Sae
203274246Saestatic void
204274246Saeme_clone_destroy(struct ifnet *ifp)
205274246Sae{
206274246Sae	struct me_softc *sc;
207274246Sae
208274246Sae	sx_xlock(&me_ioctl_sx);
209274246Sae	sc = ifp->if_softc;
210274246Sae	me_delete_tunnel(ifp);
211274246Sae	ME_LIST_LOCK();
212274246Sae	LIST_REMOVE(sc, me_list);
213274246Sae	ME_LIST_UNLOCK();
214274246Sae	bpfdetach(ifp);
215274246Sae	if_detach(ifp);
216274246Sae	ifp->if_softc = NULL;
217274246Sae	sx_xunlock(&me_ioctl_sx);
218274246Sae
219274246Sae	if_free(ifp);
220274246Sae	ME_LOCK_DESTROY(sc);
221274246Sae	free(sc, M_IFME);
222274246Sae}
223274246Sae
224274246Saestatic int
225274246Saeme_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
226274246Sae{
227274246Sae	ME_RLOCK_TRACKER;
228274246Sae	struct ifreq *ifr = (struct ifreq *)data;
229274246Sae	struct sockaddr_in *src, *dst;
230274246Sae	struct me_softc *sc;
231274246Sae	int error;
232274246Sae
233274246Sae	switch (cmd) {
234274246Sae	case SIOCSIFMTU:
235274246Sae		if (ifr->ifr_mtu < 576)
236274246Sae			return (EINVAL);
237274246Sae		ifp->if_mtu = ifr->ifr_mtu - sizeof(struct mobhdr);
238274246Sae		return (0);
239274246Sae	case SIOCSIFADDR:
240274246Sae		ifp->if_flags |= IFF_UP;
241274246Sae	case SIOCSIFFLAGS:
242274246Sae	case SIOCADDMULTI:
243274246Sae	case SIOCDELMULTI:
244274246Sae		return (0);
245274246Sae	}
246274246Sae	sx_xlock(&me_ioctl_sx);
247274246Sae	sc = ifp->if_softc;
248274246Sae	if (sc == NULL) {
249274246Sae		error = ENXIO;
250274246Sae		goto end;
251274246Sae	}
252274246Sae	error = 0;
253274246Sae	switch (cmd) {
254274246Sae	case SIOCSIFPHYADDR:
255274246Sae		src = (struct sockaddr_in *)
256274246Sae			&(((struct in_aliasreq *)data)->ifra_addr);
257274246Sae		dst = (struct sockaddr_in *)
258274246Sae			&(((struct in_aliasreq *)data)->ifra_dstaddr);
259274246Sae		if (src->sin_family != dst->sin_family ||
260274246Sae		    src->sin_family != AF_INET ||
261274246Sae		    src->sin_len != dst->sin_len ||
262274246Sae		    src->sin_len != sizeof(struct sockaddr_in)) {
263274246Sae			error = EINVAL;
264274246Sae			break;
265274246Sae		}
266274246Sae		if (src->sin_addr.s_addr == INADDR_ANY ||
267274246Sae		    dst->sin_addr.s_addr == INADDR_ANY) {
268274246Sae			error = EADDRNOTAVAIL;
269274246Sae			break;
270274246Sae		}
271274246Sae		error = me_set_tunnel(ifp, src, dst);
272274246Sae		break;
273274246Sae	case SIOCDIFPHYADDR:
274274246Sae		me_delete_tunnel(ifp);
275274246Sae		break;
276274246Sae	case SIOCGIFPSRCADDR:
277274246Sae	case SIOCGIFPDSTADDR:
278274246Sae		ME_RLOCK(sc);
279274246Sae		if (!ME_READY(sc)) {
280274246Sae			error = EADDRNOTAVAIL;
281274246Sae			ME_RUNLOCK(sc);
282274246Sae			break;
283274246Sae		}
284274246Sae		src = (struct sockaddr_in *)&ifr->ifr_addr;
285274246Sae		memset(src, 0, sizeof(*src));
286274246Sae		src->sin_family = AF_INET;
287274246Sae		src->sin_len = sizeof(*src);
288274246Sae		switch (cmd) {
289274246Sae		case SIOCGIFPSRCADDR:
290274246Sae			src->sin_addr = sc->me_src;
291274246Sae			break;
292274246Sae		case SIOCGIFPDSTADDR:
293274246Sae			src->sin_addr = sc->me_dst;
294274246Sae			break;
295274246Sae		}
296274246Sae		ME_RUNLOCK(sc);
297274246Sae		error = prison_if(curthread->td_ucred, sintosa(src));
298274246Sae		if (error != 0)
299274246Sae			memset(src, 0, sizeof(*src));
300274246Sae		break;
301282809Sae	case SIOCGTUNFIB:
302282809Sae		ifr->ifr_fib = sc->me_fibnum;
303282809Sae		break;
304282809Sae	case SIOCSTUNFIB:
305282809Sae		if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0)
306282809Sae			break;
307282809Sae		if (ifr->ifr_fib >= rt_numfibs)
308282809Sae			error = EINVAL;
309282809Sae		else
310282809Sae			sc->me_fibnum = ifr->ifr_fib;
311282809Sae		break;
312274246Sae	default:
313274246Sae		error = EINVAL;
314274246Sae		break;
315274246Sae	}
316274246Saeend:
317274246Sae	sx_xunlock(&me_ioctl_sx);
318274246Sae	return (error);
319274246Sae}
320274246Sae
321274246Saestatic int
322274246Saeme_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
323274246Sae{
324274246Sae	ME_RLOCK_TRACKER;
325274246Sae	struct me_softc *sc;
326274246Sae	struct ip *ip;
327274246Sae	int ret;
328274246Sae
329274246Sae	sc = (struct me_softc *)arg;
330274246Sae	if ((ME2IFP(sc)->if_flags & IFF_UP) == 0)
331274246Sae		return (0);
332274246Sae
333274246Sae	M_ASSERTPKTHDR(m);
334274246Sae
335274246Sae	if (m->m_pkthdr.len < sizeof(struct ip) + sizeof(struct mobhdr) -
336274246Sae	    sizeof(struct in_addr))
337274246Sae		return (0);
338274246Sae
339274246Sae	ret = 0;
340274246Sae	ME_RLOCK(sc);
341274246Sae	if (ME_READY(sc)) {
342274246Sae		ip = mtod(m, struct ip *);
343274246Sae		if (sc->me_src.s_addr == ip->ip_dst.s_addr &&
344274246Sae		    sc->me_dst.s_addr == ip->ip_src.s_addr)
345274246Sae			ret = 32 * 2;
346274246Sae	}
347274246Sae	ME_RUNLOCK(sc);
348274246Sae	return (ret);
349274246Sae}
350274246Sae
351274246Saestatic int
352274246Saeme_set_tunnel(struct ifnet *ifp, struct sockaddr_in *src,
353274246Sae    struct sockaddr_in *dst)
354274246Sae{
355274246Sae	struct me_softc *sc, *tsc;
356274246Sae
357274246Sae	sx_assert(&me_ioctl_sx, SA_XLOCKED);
358274246Sae	ME_LIST_LOCK();
359274246Sae	sc = ifp->if_softc;
360274246Sae	LIST_FOREACH(tsc, &V_me_softc_list, me_list) {
361274246Sae		if (tsc == sc || !ME_READY(tsc))
362274246Sae			continue;
363274246Sae		if (tsc->me_src.s_addr == src->sin_addr.s_addr &&
364274246Sae		    tsc->me_dst.s_addr == dst->sin_addr.s_addr) {
365274246Sae			ME_LIST_UNLOCK();
366274246Sae			return (EADDRNOTAVAIL);
367274246Sae		}
368274246Sae	}
369274246Sae	ME_LIST_UNLOCK();
370274246Sae
371274246Sae	ME_WLOCK(sc);
372274246Sae	sc->me_dst = dst->sin_addr;
373274246Sae	sc->me_src = src->sin_addr;
374274246Sae	ME_WUNLOCK(sc);
375274246Sae
376274246Sae	if (sc->me_ecookie == NULL)
377274246Sae		sc->me_ecookie = encap_attach_func(AF_INET, IPPROTO_MOBILE,
378274246Sae		    me_encapcheck, &in_mobile_protosw, sc);
379274246Sae	if (sc->me_ecookie != NULL)
380274246Sae		ifp->if_drv_flags |= IFF_DRV_RUNNING;
381274246Sae	return (0);
382274246Sae}
383274246Sae
384274246Saestatic void
385274246Saeme_delete_tunnel(struct ifnet *ifp)
386274246Sae{
387274246Sae	struct me_softc *sc = ifp->if_softc;
388274246Sae
389274246Sae	sx_assert(&me_ioctl_sx, SA_XLOCKED);
390274246Sae	if (sc->me_ecookie != NULL)
391274246Sae		encap_detach(sc->me_ecookie);
392274246Sae	sc->me_ecookie = NULL;
393274246Sae	ME_WLOCK(sc);
394274246Sae	sc->me_src.s_addr = 0;
395274246Sae	sc->me_dst.s_addr = 0;
396274246Sae	ME_WUNLOCK(sc);
397274246Sae	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
398274246Sae}
399274246Sae
400274246Saestatic uint16_t
401274246Saeme_in_cksum(uint16_t *p, int nwords)
402274246Sae{
403274246Sae	uint32_t sum = 0;
404274246Sae
405274246Sae	while (nwords-- > 0)
406274246Sae		sum += *p++;
407274246Sae	sum = (sum >> 16) + (sum & 0xffff);
408274246Sae	sum += (sum >> 16);
409274246Sae	return (~sum);
410274246Sae}
411274246Sae
412274246Saeint
413274246Saeme_input(struct mbuf **mp, int *offp, int proto)
414274246Sae{
415274246Sae	struct me_softc *sc;
416274246Sae	struct mobhdr *mh;
417274246Sae	struct ifnet *ifp;
418274246Sae	struct mbuf *m;
419274246Sae	struct ip *ip;
420274246Sae	int hlen;
421274246Sae
422274246Sae	m = *mp;
423274246Sae	sc = encap_getarg(m);
424274246Sae	KASSERT(sc != NULL, ("encap_getarg returned NULL"));
425274246Sae
426274246Sae	ifp = ME2IFP(sc);
427274246Sae	/* checks for short packets */
428274246Sae	hlen = sizeof(struct mobhdr);
429274246Sae	if (m->m_pkthdr.len < sizeof(struct ip) + hlen)
430274246Sae		hlen -= sizeof(struct in_addr);
431274246Sae	if (m->m_len < sizeof(struct ip) + hlen)
432274246Sae		m = m_pullup(m, sizeof(struct ip) + hlen);
433274246Sae	if (m == NULL)
434274246Sae		goto drop;
435274246Sae	mh = (struct mobhdr *)mtodo(m, sizeof(struct ip));
436274246Sae	/* check for wrong flags */
437274246Sae	if (mh->mob_flags & (~MOB_FLAGS_SP)) {
438274246Sae		m_freem(m);
439274246Sae		goto drop;
440274246Sae	}
441274246Sae	if (mh->mob_flags) {
442274246Sae	       if (hlen != sizeof(struct mobhdr)) {
443274246Sae			m_freem(m);
444274246Sae			goto drop;
445274246Sae	       }
446274246Sae	} else
447274246Sae		hlen = sizeof(struct mobhdr) - sizeof(struct in_addr);
448274246Sae	/* check mobile header checksum */
449274246Sae	if (me_in_cksum((uint16_t *)mh, hlen / sizeof(uint16_t)) != 0) {
450274246Sae		m_freem(m);
451274246Sae		goto drop;
452274246Sae	}
453274246Sae#ifdef MAC
454274246Sae	mac_ifnet_create_mbuf(ifp, m);
455274246Sae#endif
456274246Sae	ip = mtod(m, struct ip *);
457274246Sae	ip->ip_dst = mh->mob_dst;
458274246Sae	ip->ip_p = mh->mob_proto;
459274246Sae	ip->ip_sum = 0;
460274246Sae	ip->ip_len = htons(m->m_pkthdr.len - hlen);
461274246Sae	if (mh->mob_flags)
462274246Sae		ip->ip_src = mh->mob_src;
463274246Sae	memmove(mtodo(m, hlen), ip, sizeof(struct ip));
464274246Sae	m_adj(m, hlen);
465274246Sae	m_clrprotoflags(m);
466274246Sae	m->m_pkthdr.rcvif = ifp;
467274246Sae	m->m_pkthdr.csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID);
468282809Sae	M_SETFIB(m, ifp->if_fib);
469274246Sae	hlen = AF_INET;
470274246Sae	BPF_MTAP2(ifp, &hlen, sizeof(hlen), m);
471274246Sae	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
472274246Sae	if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
473274246Sae	if ((ifp->if_flags & IFF_MONITOR) != 0)
474274246Sae		m_freem(m);
475274246Sae	else
476274246Sae		netisr_dispatch(NETISR_IP, m);
477274246Sae	return (IPPROTO_DONE);
478274246Saedrop:
479274246Sae	if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
480274246Sae	return (IPPROTO_DONE);
481274246Sae}
482274246Sae
483274246Sae#define	MTAG_ME	1414491977
484274246Saestatic int
485274246Saeme_check_nesting(struct ifnet *ifp, struct mbuf *m)
486274246Sae{
487274246Sae	struct m_tag *mtag;
488274246Sae	int count;
489274246Sae
490274246Sae	count = 1;
491274246Sae	mtag = NULL;
492282536Sae	while ((mtag = m_tag_locate(m, MTAG_ME, 0, mtag)) != NULL) {
493274246Sae		if (*(struct ifnet **)(mtag + 1) == ifp) {
494274246Sae			log(LOG_NOTICE, "%s: loop detected\n", ifp->if_xname);
495274246Sae			return (EIO);
496274246Sae		}
497274246Sae		count++;
498274246Sae	}
499274246Sae	if (count > V_max_me_nesting) {
500274246Sae		log(LOG_NOTICE,
501274246Sae		    "%s: if_output recursively called too many times(%d)\n",
502274246Sae		    ifp->if_xname, count);
503274246Sae		return (EIO);
504274246Sae	}
505274246Sae	mtag = m_tag_alloc(MTAG_ME, 0, sizeof(struct ifnet *), M_NOWAIT);
506274246Sae	if (mtag == NULL)
507274246Sae		return (ENOMEM);
508274246Sae	*(struct ifnet **)(mtag + 1) = ifp;
509274246Sae	m_tag_prepend(m, mtag);
510274246Sae	return (0);
511274246Sae}
512274246Sae
513274246Saestatic int
514274246Saeme_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
515274246Sae   struct route *ro)
516274246Sae{
517274246Sae	uint32_t af;
518274246Sae	int error;
519274246Sae
520274246Sae#ifdef MAC
521274246Sae	error = mac_ifnet_check_transmit(ifp, m);
522274246Sae	if (error != 0)
523274246Sae		goto drop;
524274246Sae#endif
525274246Sae	if ((ifp->if_flags & IFF_MONITOR) != 0 ||
526274246Sae	    (ifp->if_flags & IFF_UP) == 0) {
527274246Sae		error = ENETDOWN;
528274246Sae		goto drop;
529274246Sae	}
530274246Sae
531274246Sae	error = me_check_nesting(ifp, m);
532274246Sae	if (error != 0)
533274246Sae		goto drop;
534274246Sae
535274246Sae	m->m_flags &= ~(M_BCAST|M_MCAST);
536274246Sae	if (dst->sa_family == AF_UNSPEC)
537274246Sae		bcopy(dst->sa_data, &af, sizeof(af));
538274246Sae	else
539274246Sae		af = dst->sa_family;
540274246Sae	if (af != AF_INET) {
541274246Sae		error = EAFNOSUPPORT;
542274246Sae		goto drop;
543274246Sae	}
544274246Sae	BPF_MTAP2(ifp, &af, sizeof(af), m);
545274246Sae	return (ifp->if_transmit(ifp, m));
546274246Saedrop:
547274246Sae	m_freem(m);
548274246Sae	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
549274246Sae	return (error);
550274246Sae}
551274246Sae
552274246Saestatic int
553274246Saeme_transmit(struct ifnet *ifp, struct mbuf *m)
554274246Sae{
555274246Sae	ME_RLOCK_TRACKER;
556274246Sae	struct mobhdr mh;
557274246Sae	struct me_softc *sc;
558274246Sae	struct ip *ip;
559274246Sae	int error, hlen, plen;
560274246Sae
561274246Sae	sc = ifp->if_softc;
562274246Sae	if (sc == NULL) {
563274246Sae		error = ENETDOWN;
564274246Sae		m_freem(m);
565274246Sae		goto drop;
566274246Sae	}
567274246Sae	if (m->m_len < sizeof(struct ip))
568274246Sae		m = m_pullup(m, sizeof(struct ip));
569274246Sae	if (m == NULL) {
570274246Sae		error = ENOBUFS;
571274246Sae		goto drop;
572274246Sae	}
573274246Sae	ip = mtod(m, struct ip *);
574274246Sae	/* Fragmented datagramms shouldn't be encapsulated */
575274246Sae	if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) {
576274246Sae		error = EINVAL;
577274246Sae		m_freem(m);
578274246Sae		goto drop;
579274246Sae	}
580274246Sae	mh.mob_proto = ip->ip_p;
581274246Sae	mh.mob_src = ip->ip_src;
582274246Sae	mh.mob_dst = ip->ip_dst;
583274246Sae	ME_RLOCK(sc);
584274246Sae	if (!ME_READY(sc)) {
585274246Sae		ME_RUNLOCK(sc);
586274246Sae		error = ENETDOWN;
587274246Sae		m_freem(m);
588274246Sae		goto drop;
589274246Sae	}
590274246Sae	if (in_hosteq(sc->me_src, ip->ip_src)) {
591274246Sae		hlen = sizeof(struct mobhdr) - sizeof(struct in_addr);
592274246Sae		mh.mob_flags = 0;
593274246Sae	} else {
594274246Sae		hlen = sizeof(struct mobhdr);
595274246Sae		mh.mob_flags = MOB_FLAGS_SP;
596274246Sae	}
597274246Sae	plen = m->m_pkthdr.len;
598274246Sae	ip->ip_src = sc->me_src;
599274246Sae	ip->ip_dst = sc->me_dst;
600274246Sae	M_SETFIB(m, sc->me_fibnum);
601274246Sae	ME_RUNLOCK(sc);
602274246Sae	M_PREPEND(m, hlen, M_NOWAIT);
603274246Sae	if (m == NULL) {
604274246Sae		error = ENOBUFS;
605274246Sae		goto drop;
606274246Sae	}
607274246Sae	if (m->m_len < sizeof(struct ip) + hlen)
608274246Sae		m = m_pullup(m, sizeof(struct ip) + hlen);
609274246Sae	if (m == NULL) {
610274246Sae		error = ENOBUFS;
611274246Sae		goto drop;
612274246Sae	}
613274246Sae	memmove(mtod(m, void *), mtodo(m, hlen), sizeof(struct ip));
614274246Sae	ip = mtod(m, struct ip *);
615274246Sae	ip->ip_len = htons(m->m_pkthdr.len);
616274246Sae	ip->ip_p = IPPROTO_MOBILE;
617274246Sae	ip->ip_sum = 0;
618274246Sae	mh.mob_csum = 0;
619274246Sae	mh.mob_csum = me_in_cksum((uint16_t *)&mh, hlen / sizeof(uint16_t));
620274246Sae	bcopy(&mh, mtodo(m, sizeof(struct ip)), hlen);
621274246Sae	error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
622274246Saedrop:
623274246Sae	if (error)
624274246Sae		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
625274246Sae	else {
626274246Sae		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
627274246Sae		if_inc_counter(ifp, IFCOUNTER_OBYTES, plen);
628274246Sae	}
629274246Sae	return (error);
630274246Sae}
631274246Sae
632274246Saestatic void
633274246Saeme_qflush(struct ifnet *ifp __unused)
634274246Sae{
635274246Sae
636274246Sae}
637274246Sae
638274246Saestatic int
639274246Saememodevent(module_t mod, int type, void *data)
640274246Sae{
641274246Sae
642274246Sae	switch (type) {
643274246Sae	case MOD_LOAD:
644274246Sae	case MOD_UNLOAD:
645274246Sae		break;
646274246Sae	default:
647274246Sae		return (EOPNOTSUPP);
648274246Sae	}
649274246Sae	return (0);
650274246Sae}
651274246Sae
652274246Saestatic moduledata_t me_mod = {
653274246Sae	"if_me",
654274246Sae	memodevent,
655274246Sae	0
656274246Sae};
657274246Sae
658274246SaeDECLARE_MODULE(if_me, me_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
659274246SaeMODULE_VERSION(if_me, 1);
660