1/*-
2 * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/sys/net/if_me.c 317403 2017-04-25 11:19:22Z ae $");
29
30#include <sys/param.h>
31#include <sys/jail.h>
32#include <sys/kernel.h>
33#include <sys/lock.h>
34#include <sys/libkern.h>
35#include <sys/malloc.h>
36#include <sys/module.h>
37#include <sys/mbuf.h>
38#include <sys/priv.h>
39#include <sys/proc.h>
40#include <sys/protosw.h>
41#include <sys/rmlock.h>
42#include <sys/socket.h>
43#include <sys/sockio.h>
44#include <sys/sx.h>
45#include <sys/sysctl.h>
46#include <sys/syslog.h>
47#include <sys/systm.h>
48
49#include <net/bpf.h>
50#include <net/ethernet.h>
51#include <net/if.h>
52#include <net/if_var.h>
53#include <net/if_clone.h>
54#include <net/if_types.h>
55#include <net/netisr.h>
56#include <net/vnet.h>
57#include <net/route.h>
58
59#include <netinet/in.h>
60#include <netinet/in_systm.h>
61#include <netinet/in_var.h>
62#include <netinet/ip.h>
63#include <netinet/ip_var.h>
64#include <netinet/ip_encap.h>
65
66#include <machine/in_cksum.h>
67#include <security/mac/mac_framework.h>
68
69#define	MEMTU			(1500 - sizeof(struct mobhdr))
70static const char mename[] = "me";
71static MALLOC_DEFINE(M_IFME, mename, "Minimal Encapsulation for IP");
72static VNET_DEFINE(struct mtx, me_mtx);
73#define	V_me_mtx	VNET(me_mtx)
74/* Minimal forwarding header RFC 2004 */
75struct mobhdr {
76	uint8_t		mob_proto;	/* protocol */
77	uint8_t		mob_flags;	/* flags */
78#define	MOB_FLAGS_SP	0x80		/* source present */
79	uint16_t	mob_csum;	/* header checksum */
80	struct in_addr	mob_dst;	/* original destination address */
81	struct in_addr	mob_src;	/* original source addr (optional) */
82} __packed;
83
84struct me_softc {
85	struct ifnet		*me_ifp;
86	LIST_ENTRY(me_softc)	me_list;
87	struct rmlock		me_lock;
88	u_int			me_fibnum;
89	const struct encaptab	*me_ecookie;
90	struct in_addr		me_src;
91	struct in_addr		me_dst;
92};
93#define	ME2IFP(sc)		((sc)->me_ifp)
94#define	ME_READY(sc)		((sc)->me_src.s_addr != 0)
95#define	ME_LOCK_INIT(sc)	rm_init(&(sc)->me_lock, "me softc")
96#define	ME_LOCK_DESTROY(sc)	rm_destroy(&(sc)->me_lock)
97#define	ME_RLOCK_TRACKER	struct rm_priotracker me_tracker
98#define	ME_RLOCK(sc)		rm_rlock(&(sc)->me_lock, &me_tracker)
99#define	ME_RUNLOCK(sc)		rm_runlock(&(sc)->me_lock, &me_tracker)
100#define	ME_RLOCK_ASSERT(sc)	rm_assert(&(sc)->me_lock, RA_RLOCKED)
101#define	ME_WLOCK(sc)		rm_wlock(&(sc)->me_lock)
102#define	ME_WUNLOCK(sc)		rm_wunlock(&(sc)->me_lock)
103#define	ME_WLOCK_ASSERT(sc)	rm_assert(&(sc)->me_lock, RA_WLOCKED)
104
105#define	ME_LIST_LOCK_INIT(x)	mtx_init(&V_me_mtx, "me_mtx", NULL, MTX_DEF)
106#define	ME_LIST_LOCK_DESTROY(x)	mtx_destroy(&V_me_mtx)
107#define	ME_LIST_LOCK(x)		mtx_lock(&V_me_mtx)
108#define	ME_LIST_UNLOCK(x)	mtx_unlock(&V_me_mtx)
109
110static VNET_DEFINE(LIST_HEAD(, me_softc), me_softc_list);
111#define	V_me_softc_list	VNET(me_softc_list)
112static struct sx me_ioctl_sx;
113SX_SYSINIT(me_ioctl_sx, &me_ioctl_sx, "me_ioctl");
114
115static int	me_clone_create(struct if_clone *, int, caddr_t);
116static void	me_clone_destroy(struct ifnet *);
117static VNET_DEFINE(struct if_clone *, me_cloner);
118#define	V_me_cloner	VNET(me_cloner)
119
120static void	me_qflush(struct ifnet *);
121static int	me_transmit(struct ifnet *, struct mbuf *);
122static int	me_ioctl(struct ifnet *, u_long, caddr_t);
123static int	me_output(struct ifnet *, struct mbuf *,
124		    const struct sockaddr *, struct route *);
125static int	me_input(struct mbuf **, int *, int);
126
127static int	me_set_tunnel(struct ifnet *, struct sockaddr_in *,
128    struct sockaddr_in *);
129static void	me_delete_tunnel(struct ifnet *);
130
131SYSCTL_DECL(_net_link);
132static SYSCTL_NODE(_net_link, IFT_TUNNEL, me, CTLFLAG_RW, 0,
133    "Minimal Encapsulation for IP (RFC 2004)");
134#ifndef MAX_ME_NEST
135#define MAX_ME_NEST 1
136#endif
137
138static VNET_DEFINE(int, max_me_nesting) = MAX_ME_NEST;
139#define	V_max_me_nesting	VNET(max_me_nesting)
140SYSCTL_INT(_net_link_me, OID_AUTO, max_nesting, CTLFLAG_RW | CTLFLAG_VNET,
141    &VNET_NAME(max_me_nesting), 0, "Max nested tunnels");
142
143extern struct domain inetdomain;
144static const struct protosw in_mobile_protosw = {
145	.pr_type =		SOCK_RAW,
146	.pr_domain =		&inetdomain,
147	.pr_protocol =		IPPROTO_MOBILE,
148	.pr_flags =		PR_ATOMIC|PR_ADDR,
149	.pr_input =		me_input,
150	.pr_output =		rip_output,
151	.pr_ctlinput =		rip_ctlinput,
152	.pr_ctloutput =		rip_ctloutput,
153	.pr_usrreqs =		&rip_usrreqs
154};
155
156static void
157vnet_me_init(const void *unused __unused)
158{
159	LIST_INIT(&V_me_softc_list);
160	ME_LIST_LOCK_INIT();
161	V_me_cloner = if_clone_simple(mename, me_clone_create,
162	    me_clone_destroy, 0);
163}
164VNET_SYSINIT(vnet_me_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
165    vnet_me_init, NULL);
166
167static void
168vnet_me_uninit(const void *unused __unused)
169{
170
171	if_clone_detach(V_me_cloner);
172	ME_LIST_LOCK_DESTROY();
173}
174VNET_SYSUNINIT(vnet_me_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
175    vnet_me_uninit, NULL);
176
177static int
178me_clone_create(struct if_clone *ifc, int unit, caddr_t params)
179{
180	struct me_softc *sc;
181
182	sc = malloc(sizeof(struct me_softc), M_IFME, M_WAITOK | M_ZERO);
183	sc->me_fibnum = curthread->td_proc->p_fibnum;
184	ME2IFP(sc) = if_alloc(IFT_TUNNEL);
185	ME_LOCK_INIT(sc);
186	ME2IFP(sc)->if_softc = sc;
187	if_initname(ME2IFP(sc), mename, unit);
188
189	ME2IFP(sc)->if_mtu = MEMTU;;
190	ME2IFP(sc)->if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
191	ME2IFP(sc)->if_output = me_output;
192	ME2IFP(sc)->if_ioctl = me_ioctl;
193	ME2IFP(sc)->if_transmit = me_transmit;
194	ME2IFP(sc)->if_qflush = me_qflush;
195	ME2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE;
196	ME2IFP(sc)->if_capenable |= IFCAP_LINKSTATE;
197	if_attach(ME2IFP(sc));
198	bpfattach(ME2IFP(sc), DLT_NULL, sizeof(u_int32_t));
199	ME_LIST_LOCK();
200	LIST_INSERT_HEAD(&V_me_softc_list, sc, me_list);
201	ME_LIST_UNLOCK();
202	return (0);
203}
204
205static void
206me_clone_destroy(struct ifnet *ifp)
207{
208	struct me_softc *sc;
209
210	sx_xlock(&me_ioctl_sx);
211	sc = ifp->if_softc;
212	me_delete_tunnel(ifp);
213	ME_LIST_LOCK();
214	LIST_REMOVE(sc, me_list);
215	ME_LIST_UNLOCK();
216	bpfdetach(ifp);
217	if_detach(ifp);
218	ifp->if_softc = NULL;
219	sx_xunlock(&me_ioctl_sx);
220
221	if_free(ifp);
222	ME_LOCK_DESTROY(sc);
223	free(sc, M_IFME);
224}
225
226static int
227me_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
228{
229	ME_RLOCK_TRACKER;
230	struct ifreq *ifr = (struct ifreq *)data;
231	struct sockaddr_in *src, *dst;
232	struct me_softc *sc;
233	int error;
234
235	switch (cmd) {
236	case SIOCSIFMTU:
237		if (ifr->ifr_mtu < 576)
238			return (EINVAL);
239		ifp->if_mtu = ifr->ifr_mtu;
240		return (0);
241	case SIOCSIFADDR:
242		ifp->if_flags |= IFF_UP;
243	case SIOCSIFFLAGS:
244	case SIOCADDMULTI:
245	case SIOCDELMULTI:
246		return (0);
247	}
248	sx_xlock(&me_ioctl_sx);
249	sc = ifp->if_softc;
250	if (sc == NULL) {
251		error = ENXIO;
252		goto end;
253	}
254	error = 0;
255	switch (cmd) {
256	case SIOCSIFPHYADDR:
257		src = (struct sockaddr_in *)
258			&(((struct in_aliasreq *)data)->ifra_addr);
259		dst = (struct sockaddr_in *)
260			&(((struct in_aliasreq *)data)->ifra_dstaddr);
261		if (src->sin_family != dst->sin_family ||
262		    src->sin_family != AF_INET ||
263		    src->sin_len != dst->sin_len ||
264		    src->sin_len != sizeof(struct sockaddr_in)) {
265			error = EINVAL;
266			break;
267		}
268		if (src->sin_addr.s_addr == INADDR_ANY ||
269		    dst->sin_addr.s_addr == INADDR_ANY) {
270			error = EADDRNOTAVAIL;
271			break;
272		}
273		error = me_set_tunnel(ifp, src, dst);
274		break;
275	case SIOCDIFPHYADDR:
276		me_delete_tunnel(ifp);
277		break;
278	case SIOCGIFPSRCADDR:
279	case SIOCGIFPDSTADDR:
280		ME_RLOCK(sc);
281		if (!ME_READY(sc)) {
282			error = EADDRNOTAVAIL;
283			ME_RUNLOCK(sc);
284			break;
285		}
286		src = (struct sockaddr_in *)&ifr->ifr_addr;
287		memset(src, 0, sizeof(*src));
288		src->sin_family = AF_INET;
289		src->sin_len = sizeof(*src);
290		switch (cmd) {
291		case SIOCGIFPSRCADDR:
292			src->sin_addr = sc->me_src;
293			break;
294		case SIOCGIFPDSTADDR:
295			src->sin_addr = sc->me_dst;
296			break;
297		}
298		ME_RUNLOCK(sc);
299		error = prison_if(curthread->td_ucred, sintosa(src));
300		if (error != 0)
301			memset(src, 0, sizeof(*src));
302		break;
303	case SIOCGTUNFIB:
304		ifr->ifr_fib = sc->me_fibnum;
305		break;
306	case SIOCSTUNFIB:
307		if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0)
308			break;
309		if (ifr->ifr_fib >= rt_numfibs)
310			error = EINVAL;
311		else
312			sc->me_fibnum = ifr->ifr_fib;
313		break;
314	default:
315		error = EINVAL;
316		break;
317	}
318end:
319	sx_xunlock(&me_ioctl_sx);
320	return (error);
321}
322
323static int
324me_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
325{
326	ME_RLOCK_TRACKER;
327	struct me_softc *sc;
328	struct ip *ip;
329	int ret;
330
331	sc = (struct me_softc *)arg;
332	if ((ME2IFP(sc)->if_flags & IFF_UP) == 0)
333		return (0);
334
335	M_ASSERTPKTHDR(m);
336
337	if (m->m_pkthdr.len < sizeof(struct ip) + sizeof(struct mobhdr) -
338	    sizeof(struct in_addr))
339		return (0);
340
341	ret = 0;
342	ME_RLOCK(sc);
343	if (ME_READY(sc)) {
344		ip = mtod(m, struct ip *);
345		if (sc->me_src.s_addr == ip->ip_dst.s_addr &&
346		    sc->me_dst.s_addr == ip->ip_src.s_addr)
347			ret = 32 * 2;
348	}
349	ME_RUNLOCK(sc);
350	return (ret);
351}
352
353static int
354me_set_tunnel(struct ifnet *ifp, struct sockaddr_in *src,
355    struct sockaddr_in *dst)
356{
357	struct me_softc *sc, *tsc;
358
359	sx_assert(&me_ioctl_sx, SA_XLOCKED);
360	ME_LIST_LOCK();
361	sc = ifp->if_softc;
362	LIST_FOREACH(tsc, &V_me_softc_list, me_list) {
363		if (tsc == sc || !ME_READY(tsc))
364			continue;
365		if (tsc->me_src.s_addr == src->sin_addr.s_addr &&
366		    tsc->me_dst.s_addr == dst->sin_addr.s_addr) {
367			ME_LIST_UNLOCK();
368			return (EADDRNOTAVAIL);
369		}
370	}
371	ME_LIST_UNLOCK();
372
373	ME_WLOCK(sc);
374	sc->me_dst = dst->sin_addr;
375	sc->me_src = src->sin_addr;
376	ME_WUNLOCK(sc);
377
378	if (sc->me_ecookie == NULL)
379		sc->me_ecookie = encap_attach_func(AF_INET, IPPROTO_MOBILE,
380		    me_encapcheck, &in_mobile_protosw, sc);
381	if (sc->me_ecookie != NULL) {
382		ifp->if_drv_flags |= IFF_DRV_RUNNING;
383		if_link_state_change(ifp, LINK_STATE_UP);
384	}
385	return (0);
386}
387
388static void
389me_delete_tunnel(struct ifnet *ifp)
390{
391	struct me_softc *sc = ifp->if_softc;
392
393	sx_assert(&me_ioctl_sx, SA_XLOCKED);
394	if (sc->me_ecookie != NULL)
395		encap_detach(sc->me_ecookie);
396	sc->me_ecookie = NULL;
397	ME_WLOCK(sc);
398	sc->me_src.s_addr = 0;
399	sc->me_dst.s_addr = 0;
400	ME_WUNLOCK(sc);
401	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
402	if_link_state_change(ifp, LINK_STATE_DOWN);
403}
404
405static uint16_t
406me_in_cksum(uint16_t *p, int nwords)
407{
408	uint32_t sum = 0;
409
410	while (nwords-- > 0)
411		sum += *p++;
412	sum = (sum >> 16) + (sum & 0xffff);
413	sum += (sum >> 16);
414	return (~sum);
415}
416
417int
418me_input(struct mbuf **mp, int *offp, int proto)
419{
420	struct me_softc *sc;
421	struct mobhdr *mh;
422	struct ifnet *ifp;
423	struct mbuf *m;
424	struct ip *ip;
425	int hlen;
426
427	m = *mp;
428	sc = encap_getarg(m);
429	KASSERT(sc != NULL, ("encap_getarg returned NULL"));
430
431	ifp = ME2IFP(sc);
432	/* checks for short packets */
433	hlen = sizeof(struct mobhdr);
434	if (m->m_pkthdr.len < sizeof(struct ip) + hlen)
435		hlen -= sizeof(struct in_addr);
436	if (m->m_len < sizeof(struct ip) + hlen)
437		m = m_pullup(m, sizeof(struct ip) + hlen);
438	if (m == NULL)
439		goto drop;
440	mh = (struct mobhdr *)mtodo(m, sizeof(struct ip));
441	/* check for wrong flags */
442	if (mh->mob_flags & (~MOB_FLAGS_SP)) {
443		m_freem(m);
444		goto drop;
445	}
446	if (mh->mob_flags) {
447	       if (hlen != sizeof(struct mobhdr)) {
448			m_freem(m);
449			goto drop;
450	       }
451	} else
452		hlen = sizeof(struct mobhdr) - sizeof(struct in_addr);
453	/* check mobile header checksum */
454	if (me_in_cksum((uint16_t *)mh, hlen / sizeof(uint16_t)) != 0) {
455		m_freem(m);
456		goto drop;
457	}
458#ifdef MAC
459	mac_ifnet_create_mbuf(ifp, m);
460#endif
461	ip = mtod(m, struct ip *);
462	ip->ip_dst = mh->mob_dst;
463	ip->ip_p = mh->mob_proto;
464	ip->ip_sum = 0;
465	ip->ip_len = htons(m->m_pkthdr.len - hlen);
466	if (mh->mob_flags)
467		ip->ip_src = mh->mob_src;
468	memmove(mtodo(m, hlen), ip, sizeof(struct ip));
469	m_adj(m, hlen);
470	m_clrprotoflags(m);
471	m->m_pkthdr.rcvif = ifp;
472	m->m_pkthdr.csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID);
473	M_SETFIB(m, ifp->if_fib);
474	hlen = AF_INET;
475	BPF_MTAP2(ifp, &hlen, sizeof(hlen), m);
476	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
477	if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
478	if ((ifp->if_flags & IFF_MONITOR) != 0)
479		m_freem(m);
480	else
481		netisr_dispatch(NETISR_IP, m);
482	return (IPPROTO_DONE);
483drop:
484	if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
485	return (IPPROTO_DONE);
486}
487
488#define	MTAG_ME	1414491977
489static int
490me_check_nesting(struct ifnet *ifp, struct mbuf *m)
491{
492	struct m_tag *mtag;
493	int count;
494
495	count = 1;
496	mtag = NULL;
497	while ((mtag = m_tag_locate(m, MTAG_ME, 0, mtag)) != NULL) {
498		if (*(struct ifnet **)(mtag + 1) == ifp) {
499			log(LOG_NOTICE, "%s: loop detected\n", ifp->if_xname);
500			return (EIO);
501		}
502		count++;
503	}
504	if (count > V_max_me_nesting) {
505		log(LOG_NOTICE,
506		    "%s: if_output recursively called too many times(%d)\n",
507		    ifp->if_xname, count);
508		return (EIO);
509	}
510	mtag = m_tag_alloc(MTAG_ME, 0, sizeof(struct ifnet *), M_NOWAIT);
511	if (mtag == NULL)
512		return (ENOMEM);
513	*(struct ifnet **)(mtag + 1) = ifp;
514	m_tag_prepend(m, mtag);
515	return (0);
516}
517
518static int
519me_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
520   struct route *ro)
521{
522	uint32_t af;
523	int error;
524
525#ifdef MAC
526	error = mac_ifnet_check_transmit(ifp, m);
527	if (error != 0)
528		goto drop;
529#endif
530	if ((ifp->if_flags & IFF_MONITOR) != 0 ||
531	    (ifp->if_flags & IFF_UP) == 0) {
532		error = ENETDOWN;
533		goto drop;
534	}
535
536	error = me_check_nesting(ifp, m);
537	if (error != 0)
538		goto drop;
539
540	m->m_flags &= ~(M_BCAST|M_MCAST);
541	if (dst->sa_family == AF_UNSPEC)
542		bcopy(dst->sa_data, &af, sizeof(af));
543	else
544		af = dst->sa_family;
545	if (af != AF_INET) {
546		error = EAFNOSUPPORT;
547		goto drop;
548	}
549	BPF_MTAP2(ifp, &af, sizeof(af), m);
550	return (ifp->if_transmit(ifp, m));
551drop:
552	m_freem(m);
553	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
554	return (error);
555}
556
557static int
558me_transmit(struct ifnet *ifp, struct mbuf *m)
559{
560	ME_RLOCK_TRACKER;
561	struct mobhdr mh;
562	struct me_softc *sc;
563	struct ip *ip;
564	int error, hlen, plen;
565
566	sc = ifp->if_softc;
567	if (sc == NULL) {
568		error = ENETDOWN;
569		m_freem(m);
570		goto drop;
571	}
572	if (m->m_len < sizeof(struct ip))
573		m = m_pullup(m, sizeof(struct ip));
574	if (m == NULL) {
575		error = ENOBUFS;
576		goto drop;
577	}
578	ip = mtod(m, struct ip *);
579	/* Fragmented datagramms shouldn't be encapsulated */
580	if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) {
581		error = EINVAL;
582		m_freem(m);
583		goto drop;
584	}
585	mh.mob_proto = ip->ip_p;
586	mh.mob_src = ip->ip_src;
587	mh.mob_dst = ip->ip_dst;
588	ME_RLOCK(sc);
589	if (!ME_READY(sc)) {
590		ME_RUNLOCK(sc);
591		error = ENETDOWN;
592		m_freem(m);
593		goto drop;
594	}
595	if (in_hosteq(sc->me_src, ip->ip_src)) {
596		hlen = sizeof(struct mobhdr) - sizeof(struct in_addr);
597		mh.mob_flags = 0;
598	} else {
599		hlen = sizeof(struct mobhdr);
600		mh.mob_flags = MOB_FLAGS_SP;
601	}
602	plen = m->m_pkthdr.len;
603	ip->ip_src = sc->me_src;
604	ip->ip_dst = sc->me_dst;
605	M_SETFIB(m, sc->me_fibnum);
606	ME_RUNLOCK(sc);
607	M_PREPEND(m, hlen, M_NOWAIT);
608	if (m == NULL) {
609		error = ENOBUFS;
610		goto drop;
611	}
612	if (m->m_len < sizeof(struct ip) + hlen)
613		m = m_pullup(m, sizeof(struct ip) + hlen);
614	if (m == NULL) {
615		error = ENOBUFS;
616		goto drop;
617	}
618	memmove(mtod(m, void *), mtodo(m, hlen), sizeof(struct ip));
619	ip = mtod(m, struct ip *);
620	ip->ip_len = htons(m->m_pkthdr.len);
621	ip->ip_p = IPPROTO_MOBILE;
622	ip->ip_sum = 0;
623	mh.mob_csum = 0;
624	mh.mob_csum = me_in_cksum((uint16_t *)&mh, hlen / sizeof(uint16_t));
625	bcopy(&mh, mtodo(m, sizeof(struct ip)), hlen);
626	error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
627drop:
628	if (error)
629		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
630	else {
631		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
632		if_inc_counter(ifp, IFCOUNTER_OBYTES, plen);
633	}
634	return (error);
635}
636
637static void
638me_qflush(struct ifnet *ifp __unused)
639{
640
641}
642
643static int
644memodevent(module_t mod, int type, void *data)
645{
646
647	switch (type) {
648	case MOD_LOAD:
649	case MOD_UNLOAD:
650		break;
651	default:
652		return (EOPNOTSUPP);
653	}
654	return (0);
655}
656
657static moduledata_t me_mod = {
658	"if_me",
659	memodevent,
660	0
661};
662
663DECLARE_MODULE(if_me, me_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
664MODULE_VERSION(if_me, 1);
665