1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * Copyright (c) 2018 Andrey V. Elsukov <ae@FreeBSD.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	$KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $
33 */
34
35#include <sys/cdefs.h>
36#include "opt_inet.h"
37#include "opt_inet6.h"
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/lock.h>
43#include <sys/malloc.h>
44#include <sys/mbuf.h>
45#include <sys/module.h>
46#include <sys/rmlock.h>
47#include <sys/socket.h>
48#include <sys/sockio.h>
49#include <sys/sx.h>
50#include <sys/errno.h>
51#include <sys/time.h>
52#include <sys/sysctl.h>
53#include <sys/syslog.h>
54#include <sys/priv.h>
55#include <sys/proc.h>
56#include <sys/conf.h>
57#include <machine/cpu.h>
58
59#include <net/if.h>
60#include <net/if_var.h>
61#include <net/if_private.h>
62#include <net/if_clone.h>
63#include <net/if_types.h>
64#include <net/netisr.h>
65#include <net/route.h>
66#include <net/bpf.h>
67#include <net/vnet.h>
68
69#include <netinet/in.h>
70#include <netinet/in_systm.h>
71#include <netinet/ip.h>
72#include <netinet/ip_ecn.h>
73#ifdef	INET
74#include <netinet/in_var.h>
75#include <netinet/ip_var.h>
76#endif	/* INET */
77
78#ifdef INET6
79#ifndef INET
80#include <netinet/in.h>
81#endif
82#include <netinet6/in6_var.h>
83#include <netinet/ip6.h>
84#include <netinet6/ip6_ecn.h>
85#include <netinet6/ip6_var.h>
86#endif /* INET6 */
87
88#include <netinet/ip_encap.h>
89#include <net/ethernet.h>
90#include <net/if_bridgevar.h>
91#include <net/if_gif.h>
92
93#include <security/mac/mac_framework.h>
94
95static const char gifname[] = "gif";
96
97MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
98static struct sx gif_ioctl_sx;
99SX_SYSINIT(gif_ioctl_sx, &gif_ioctl_sx, "gif_ioctl");
100
101void	(*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
102void	(*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
103void	(*ng_gif_attach_p)(struct ifnet *ifp);
104void	(*ng_gif_detach_p)(struct ifnet *ifp);
105
106#ifdef VIMAGE
107static void	gif_reassign(struct ifnet *, struct vnet *, char *);
108#endif
109static void	gif_delete_tunnel(struct gif_softc *);
110static int	gif_ioctl(struct ifnet *, u_long, caddr_t);
111static int	gif_transmit(struct ifnet *, struct mbuf *);
112static void	gif_qflush(struct ifnet *);
113static int	gif_clone_create(struct if_clone *, int, caddr_t);
114static void	gif_clone_destroy(struct ifnet *);
115VNET_DEFINE_STATIC(struct if_clone *, gif_cloner);
116#define	V_gif_cloner	VNET(gif_cloner)
117
118SYSCTL_DECL(_net_link);
119static SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
120    "Generic Tunnel Interface");
121#ifndef MAX_GIF_NEST
122/*
123 * This macro controls the default upper limitation on nesting of gif tunnels.
124 * Since, setting a large value to this macro with a careless configuration
125 * may introduce system crash, we don't allow any nestings by default.
126 * If you need to configure nested gif tunnels, you can define this macro
127 * in your kernel configuration file.  However, if you do so, please be
128 * careful to configure the tunnels so that it won't make a loop.
129 */
130#define MAX_GIF_NEST 1
131#endif
132VNET_DEFINE_STATIC(int, max_gif_nesting) = MAX_GIF_NEST;
133#define	V_max_gif_nesting	VNET(max_gif_nesting)
134SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_VNET | CTLFLAG_RW,
135    &VNET_NAME(max_gif_nesting), 0, "Max nested tunnels");
136
137static int
138gif_clone_create(struct if_clone *ifc, int unit, caddr_t params)
139{
140	struct gif_softc *sc;
141
142	sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO);
143	sc->gif_fibnum = curthread->td_proc->p_fibnum;
144	GIF2IFP(sc) = if_alloc(IFT_GIF);
145	GIF2IFP(sc)->if_softc = sc;
146	if_initname(GIF2IFP(sc), gifname, unit);
147
148	GIF2IFP(sc)->if_addrlen = 0;
149	GIF2IFP(sc)->if_mtu    = GIF_MTU;
150	GIF2IFP(sc)->if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
151	GIF2IFP(sc)->if_ioctl  = gif_ioctl;
152	GIF2IFP(sc)->if_transmit = gif_transmit;
153	GIF2IFP(sc)->if_qflush = gif_qflush;
154	GIF2IFP(sc)->if_output = gif_output;
155#ifdef VIMAGE
156	GIF2IFP(sc)->if_reassign = gif_reassign;
157#endif
158	GIF2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE;
159	GIF2IFP(sc)->if_capenable |= IFCAP_LINKSTATE;
160	if_attach(GIF2IFP(sc));
161	bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t));
162	if (ng_gif_attach_p != NULL)
163		(*ng_gif_attach_p)(GIF2IFP(sc));
164
165	return (0);
166}
167
168#ifdef VIMAGE
169static void
170gif_reassign(struct ifnet *ifp, struct vnet *new_vnet __unused,
171    char *unused __unused)
172{
173	struct gif_softc *sc;
174
175	sx_xlock(&gif_ioctl_sx);
176	sc = ifp->if_softc;
177	if (sc != NULL)
178		gif_delete_tunnel(sc);
179	sx_xunlock(&gif_ioctl_sx);
180}
181#endif /* VIMAGE */
182
183static void
184gif_clone_destroy(struct ifnet *ifp)
185{
186	struct gif_softc *sc;
187
188	sx_xlock(&gif_ioctl_sx);
189	sc = ifp->if_softc;
190	gif_delete_tunnel(sc);
191	if (ng_gif_detach_p != NULL)
192		(*ng_gif_detach_p)(ifp);
193	bpfdetach(ifp);
194	if_detach(ifp);
195	ifp->if_softc = NULL;
196	sx_xunlock(&gif_ioctl_sx);
197
198	GIF_WAIT();
199	if_free(ifp);
200	free(sc, M_GIF);
201}
202
203static void
204vnet_gif_init(const void *unused __unused)
205{
206
207	V_gif_cloner = if_clone_simple(gifname, gif_clone_create,
208	    gif_clone_destroy, 0);
209#ifdef INET
210	in_gif_init();
211#endif
212#ifdef INET6
213	in6_gif_init();
214#endif
215}
216VNET_SYSINIT(vnet_gif_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
217    vnet_gif_init, NULL);
218
219static void
220vnet_gif_uninit(const void *unused __unused)
221{
222
223	if_clone_detach(V_gif_cloner);
224#ifdef INET
225	in_gif_uninit();
226#endif
227#ifdef INET6
228	in6_gif_uninit();
229#endif
230}
231VNET_SYSUNINIT(vnet_gif_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
232    vnet_gif_uninit, NULL);
233
234static int
235gifmodevent(module_t mod, int type, void *data)
236{
237
238	switch (type) {
239	case MOD_LOAD:
240	case MOD_UNLOAD:
241		break;
242	default:
243		return (EOPNOTSUPP);
244	}
245	return (0);
246}
247
248static moduledata_t gif_mod = {
249	"if_gif",
250	gifmodevent,
251	0
252};
253
254DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
255MODULE_VERSION(if_gif, 1);
256
257struct gif_list *
258gif_hashinit(void)
259{
260	struct gif_list *hash;
261	int i;
262
263	hash = malloc(sizeof(struct gif_list) * GIF_HASH_SIZE,
264	    M_GIF, M_WAITOK);
265	for (i = 0; i < GIF_HASH_SIZE; i++)
266		CK_LIST_INIT(&hash[i]);
267
268	return (hash);
269}
270
271void
272gif_hashdestroy(struct gif_list *hash)
273{
274
275	free(hash, M_GIF);
276}
277
278#define	MTAG_GIF	1080679712
279static int
280gif_transmit(struct ifnet *ifp, struct mbuf *m)
281{
282	struct gif_softc *sc;
283	struct etherip_header *eth;
284#ifdef INET
285	struct ip *ip;
286#endif
287#ifdef INET6
288	struct ip6_hdr *ip6;
289	uint32_t t;
290#endif
291	uint32_t af;
292	uint8_t proto, ecn;
293	int error;
294
295	NET_EPOCH_ASSERT();
296#ifdef MAC
297	error = mac_ifnet_check_transmit(ifp, m);
298	if (error) {
299		m_freem(m);
300		goto err;
301	}
302#endif
303	error = ENETDOWN;
304	sc = ifp->if_softc;
305	if ((ifp->if_flags & IFF_MONITOR) != 0 ||
306	    (ifp->if_flags & IFF_UP) == 0 ||
307	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
308	    sc->gif_family == 0 ||
309	    (error = if_tunnel_check_nesting(ifp, m, MTAG_GIF,
310		V_max_gif_nesting)) != 0) {
311		m_freem(m);
312		goto err;
313	}
314	/* Now pull back the af that we stashed in the csum_data. */
315	if (ifp->if_bridge)
316		af = AF_LINK;
317	else
318		af = m->m_pkthdr.csum_data;
319	m->m_flags &= ~(M_BCAST|M_MCAST);
320	M_SETFIB(m, sc->gif_fibnum);
321	BPF_MTAP2(ifp, &af, sizeof(af), m);
322	if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
323	if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
324	/* inner AF-specific encapsulation */
325	ecn = 0;
326	switch (af) {
327#ifdef INET
328	case AF_INET:
329		proto = IPPROTO_IPV4;
330		if (m->m_len < sizeof(struct ip))
331			m = m_pullup(m, sizeof(struct ip));
332		if (m == NULL) {
333			error = ENOBUFS;
334			goto err;
335		}
336		ip = mtod(m, struct ip *);
337		ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
338		    ECN_NOCARE, &ecn, &ip->ip_tos);
339		break;
340#endif
341#ifdef INET6
342	case AF_INET6:
343		proto = IPPROTO_IPV6;
344		if (m->m_len < sizeof(struct ip6_hdr))
345			m = m_pullup(m, sizeof(struct ip6_hdr));
346		if (m == NULL) {
347			error = ENOBUFS;
348			goto err;
349		}
350		t = 0;
351		ip6 = mtod(m, struct ip6_hdr *);
352		ip6_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
353		    ECN_NOCARE, &t, &ip6->ip6_flow);
354		ecn = (ntohl(t) >> 20) & 0xff;
355		break;
356#endif
357	case AF_LINK:
358		proto = IPPROTO_ETHERIP;
359		M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT);
360		if (m == NULL) {
361			error = ENOBUFS;
362			goto err;
363		}
364		eth = mtod(m, struct etherip_header *);
365		eth->eip_resvh = 0;
366		eth->eip_ver = ETHERIP_VERSION;
367		eth->eip_resvl = 0;
368		break;
369	default:
370		error = EAFNOSUPPORT;
371		m_freem(m);
372		goto err;
373	}
374	/* XXX should we check if our outer source is legal? */
375	/* dispatch to output logic based on outer AF */
376	switch (sc->gif_family) {
377#ifdef INET
378	case AF_INET:
379		error = in_gif_output(ifp, m, proto, ecn);
380		break;
381#endif
382#ifdef INET6
383	case AF_INET6:
384		error = in6_gif_output(ifp, m, proto, ecn);
385		break;
386#endif
387	default:
388		m_freem(m);
389	}
390err:
391	if (error)
392		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
393	return (error);
394}
395
396static void
397gif_qflush(struct ifnet *ifp __unused)
398{
399
400}
401
402int
403gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
404	struct route *ro)
405{
406	uint32_t af;
407
408	KASSERT(ifp->if_bridge == NULL,
409	    ("%s: unexpectedly called with bridge attached", __func__));
410
411	/* BPF writes need to be handled specially. */
412	if (dst->sa_family == AF_UNSPEC || dst->sa_family == pseudo_AF_HDRCMPLT)
413		memcpy(&af, dst->sa_data, sizeof(af));
414	else
415		af = RO_GET_FAMILY(ro, dst);
416	/*
417	 * Now save the af in the inbound pkt csum data, this is a cheat since
418	 * we are using the inbound csum_data field to carry the af over to
419	 * the gif_transmit() routine, avoiding using yet another mtag.
420	 */
421	m->m_pkthdr.csum_data = af;
422	return (ifp->if_transmit(ifp, m));
423}
424
425void
426gif_input(struct mbuf *m, struct ifnet *ifp, int proto, uint8_t ecn)
427{
428	struct etherip_header *eip;
429#ifdef INET
430	struct ip *ip;
431#endif
432#ifdef INET6
433	struct ip6_hdr *ip6;
434	uint32_t t;
435#endif
436	struct ether_header *eh;
437	struct ifnet *oldifp;
438	int isr, n, af;
439
440	NET_EPOCH_ASSERT();
441
442	if (ifp == NULL) {
443		/* just in case */
444		m_freem(m);
445		return;
446	}
447	m->m_pkthdr.rcvif = ifp;
448	m_clrprotoflags(m);
449	switch (proto) {
450#ifdef INET
451	case IPPROTO_IPV4:
452		af = AF_INET;
453		if (m->m_len < sizeof(struct ip))
454			m = m_pullup(m, sizeof(struct ip));
455		if (m == NULL)
456			goto drop;
457		ip = mtod(m, struct ip *);
458		if (ip_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
459		    ECN_NOCARE, &ecn, &ip->ip_tos) == 0) {
460			m_freem(m);
461			goto drop;
462		}
463		break;
464#endif
465#ifdef INET6
466	case IPPROTO_IPV6:
467		af = AF_INET6;
468		if (m->m_len < sizeof(struct ip6_hdr))
469			m = m_pullup(m, sizeof(struct ip6_hdr));
470		if (m == NULL)
471			goto drop;
472		t = htonl((uint32_t)ecn << 20);
473		ip6 = mtod(m, struct ip6_hdr *);
474		if (ip6_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED:
475		    ECN_NOCARE, &t, &ip6->ip6_flow) == 0) {
476			m_freem(m);
477			goto drop;
478		}
479		break;
480#endif
481	case IPPROTO_ETHERIP:
482		af = AF_LINK;
483		break;
484	default:
485		m_freem(m);
486		goto drop;
487	}
488
489#ifdef MAC
490	mac_ifnet_create_mbuf(ifp, m);
491#endif
492
493	if (bpf_peers_present(ifp->if_bpf)) {
494		uint32_t af1 = af;
495		bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m);
496	}
497
498	if ((ifp->if_flags & IFF_MONITOR) != 0) {
499		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
500		if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
501		m_freem(m);
502		return;
503	}
504
505	if (ng_gif_input_p != NULL) {
506		(*ng_gif_input_p)(ifp, &m, af);
507		if (m == NULL)
508			goto drop;
509	}
510
511	/*
512	 * Put the packet to the network layer input queue according to the
513	 * specified address family.
514	 * Note: older versions of gif_input directly called network layer
515	 * input functions, e.g. ip6_input, here.  We changed the policy to
516	 * prevent too many recursive calls of such input functions, which
517	 * might cause kernel panic.  But the change may introduce another
518	 * problem; if the input queue is full, packets are discarded.
519	 * The kernel stack overflow really happened, and we believed
520	 * queue-full rarely occurs, so we changed the policy.
521	 */
522	switch (af) {
523#ifdef INET
524	case AF_INET:
525		isr = NETISR_IP;
526		break;
527#endif
528#ifdef INET6
529	case AF_INET6:
530		isr = NETISR_IPV6;
531		break;
532#endif
533	case AF_LINK:
534		n = sizeof(struct etherip_header) +
535		    sizeof(struct ether_header);
536		if (n > m->m_len)
537			m = m_pullup(m, n);
538		if (m == NULL)
539			goto drop;
540		eip = mtod(m, struct etherip_header *);
541		if (eip->eip_ver != ETHERIP_VERSION) {
542			/* discard unknown versions */
543			m_freem(m);
544			goto drop;
545		}
546
547		m_adj_decap(m, sizeof(struct etherip_header));
548
549		m->m_flags &= ~(M_BCAST|M_MCAST);
550		m->m_pkthdr.rcvif = ifp;
551
552		if (ifp->if_bridge) {
553			oldifp = ifp;
554			eh = mtod(m, struct ether_header *);
555			if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
556				if (ETHER_IS_BROADCAST(eh->ether_dhost))
557					m->m_flags |= M_BCAST;
558				else
559					m->m_flags |= M_MCAST;
560				if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1);
561			}
562			BRIDGE_INPUT(ifp, m);
563
564			if (m != NULL && ifp != oldifp) {
565				/*
566				 * The bridge gave us back itself or one of the
567				 * members for which the frame is addressed.
568				 */
569				ether_demux(ifp, m);
570				return;
571			}
572		}
573		if (m != NULL)
574			m_freem(m);
575		return;
576
577	default:
578		if (ng_gif_input_orphan_p != NULL)
579			(*ng_gif_input_orphan_p)(ifp, m, af);
580		else
581			m_freem(m);
582		return;
583	}
584
585	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
586	if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
587	M_SETFIB(m, ifp->if_fib);
588	netisr_dispatch(isr, m);
589	return;
590drop:
591	if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
592}
593
594static int
595gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
596{
597	struct ifreq *ifr = (struct ifreq*)data;
598	struct gif_softc *sc;
599	u_int options;
600	int error;
601
602	switch (cmd) {
603	case SIOCSIFADDR:
604		ifp->if_flags |= IFF_UP;
605	case SIOCADDMULTI:
606	case SIOCDELMULTI:
607	case SIOCGIFMTU:
608	case SIOCSIFFLAGS:
609		return (0);
610	case SIOCSIFMTU:
611		if (ifr->ifr_mtu < GIF_MTU_MIN ||
612		    ifr->ifr_mtu > GIF_MTU_MAX)
613			return (EINVAL);
614		else
615			ifp->if_mtu = ifr->ifr_mtu;
616		return (0);
617	}
618	sx_xlock(&gif_ioctl_sx);
619	sc = ifp->if_softc;
620	if (sc == NULL) {
621		error = ENXIO;
622		goto bad;
623	}
624	error = 0;
625	switch (cmd) {
626	case SIOCDIFPHYADDR:
627		if (sc->gif_family == 0)
628			break;
629		gif_delete_tunnel(sc);
630		break;
631#ifdef INET
632	case SIOCSIFPHYADDR:
633	case SIOCGIFPSRCADDR:
634	case SIOCGIFPDSTADDR:
635		error = in_gif_ioctl(sc, cmd, data);
636		break;
637#endif
638#ifdef INET6
639	case SIOCSIFPHYADDR_IN6:
640	case SIOCGIFPSRCADDR_IN6:
641	case SIOCGIFPDSTADDR_IN6:
642		error = in6_gif_ioctl(sc, cmd, data);
643		break;
644#endif
645	case SIOCGTUNFIB:
646		ifr->ifr_fib = sc->gif_fibnum;
647		break;
648	case SIOCSTUNFIB:
649		if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0)
650			break;
651		if (ifr->ifr_fib >= rt_numfibs)
652			error = EINVAL;
653		else
654			sc->gif_fibnum = ifr->ifr_fib;
655		break;
656	case GIFGOPTS:
657		options = sc->gif_options;
658		error = copyout(&options, ifr_data_get_ptr(ifr),
659		    sizeof(options));
660		break;
661	case GIFSOPTS:
662		if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0)
663			break;
664		error = copyin(ifr_data_get_ptr(ifr), &options,
665		    sizeof(options));
666		if (error)
667			break;
668		if (options & ~GIF_OPTMASK) {
669			error = EINVAL;
670			break;
671		}
672		if (sc->gif_options != options) {
673			switch (sc->gif_family) {
674#ifdef INET
675			case AF_INET:
676				error = in_gif_setopts(sc, options);
677				break;
678#endif
679#ifdef INET6
680			case AF_INET6:
681				error = in6_gif_setopts(sc, options);
682				break;
683#endif
684			default:
685				/* No need to invoke AF-handler */
686				sc->gif_options = options;
687			}
688		}
689		break;
690	default:
691		error = EINVAL;
692		break;
693	}
694	if (error == 0 && sc->gif_family != 0) {
695		if (
696#ifdef INET
697		    cmd == SIOCSIFPHYADDR ||
698#endif
699#ifdef INET6
700		    cmd == SIOCSIFPHYADDR_IN6 ||
701#endif
702		    0) {
703			if_link_state_change(ifp, LINK_STATE_UP);
704		}
705	}
706bad:
707	sx_xunlock(&gif_ioctl_sx);
708	return (error);
709}
710
711static void
712gif_delete_tunnel(struct gif_softc *sc)
713{
714
715	sx_assert(&gif_ioctl_sx, SA_XLOCKED);
716	if (sc->gif_family != 0) {
717		CK_LIST_REMOVE(sc, srchash);
718		CK_LIST_REMOVE(sc, chain);
719		/* Wait until it become safe to free gif_hdr */
720		GIF_WAIT();
721		free(sc->gif_hdr, M_GIF);
722	}
723	sc->gif_family = 0;
724	GIF2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
725	if_link_state_change(GIF2IFP(sc), LINK_STATE_DOWN);
726}
727