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: stable/11/sys/net/if_me.c 317403 2017-04-25 11:19:22Z 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
69317403Sae#define	MEMTU			(1500 - sizeof(struct mobhdr))
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
189317403Sae	ME2IFP(sc)->if_mtu = MEMTU;;
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);
239317403Sae		ifp->if_mtu = ifr->ifr_mtu;
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