Do a major clean-up of the BUSDMA architecture. A large number of
[dragonfly.git] / sys / net / gif / if_gif.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
78195a76
MD
28 *
29 * $FreeBSD: src/sys/net/if_gif.c,v 1.4.2.15 2002/11/08 16:57:13 ume Exp $
1f7ab7c9 30 * $DragonFly: src/sys/net/gif/if_gif.c,v 1.18 2006/10/25 20:56:02 dillon Exp $
78195a76 31 * $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $
984263bc
MD
32 */
33
34#include "opt_inet.h"
35#include "opt_inet6.h"
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
1f7ab7c9 40#include <sys/bus.h>
984263bc
MD
41#include <sys/malloc.h>
42#include <sys/mbuf.h>
43#include <sys/socket.h>
44#include <sys/sockio.h>
45#include <sys/errno.h>
46#include <sys/time.h>
47#include <sys/sysctl.h>
48#include <sys/syslog.h>
49#include <sys/protosw.h>
50#include <sys/conf.h>
0b31d406 51#include <sys/thread2.h>
1f7ab7c9 52
984263bc
MD
53#include <machine/cpu.h>
54
55#include <net/if.h>
56#include <net/if_types.h>
57#include <net/netisr.h>
58#include <net/route.h>
59#include <net/bpf.h>
60
61#include <netinet/in.h>
62#include <netinet/in_systm.h>
63#include <netinet/ip.h>
64#ifdef INET
65#include <netinet/in_var.h>
66#include <netinet/in_gif.h>
67#include <netinet/ip_var.h>
984263bc
MD
68#endif /* INET */
69
70#ifdef INET6
71#ifndef INET
72#include <netinet/in.h>
73#endif
74#include <netinet6/in6_var.h>
75#include <netinet/ip6.h>
76#include <netinet6/ip6_var.h>
77#include <netinet6/in6_gif.h>
78#include <netinet6/ip6protosw.h>
79#endif /* INET6 */
80
81#include <netinet/ip_encap.h>
1f2de5d4 82#include "if_gif.h"
984263bc
MD
83
84#include <net/net_osdep.h>
85
86#define GIFNAME "gif"
984263bc
MD
87
88static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
984263bc
MD
89LIST_HEAD(, gif_softc) gif_softc_list;
90
b7b982e2 91int gif_clone_create (struct if_clone *, int);
158abb01 92void gif_clone_destroy (struct ifnet *);
984263bc 93
b7b982e2
MD
94struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif", gif_clone_create,
95 gif_clone_destroy, 0, IF_MAXUNIT);
984263bc 96
158abb01 97static int gifmodevent (module_t, int, void *);
984263bc
MD
98
99SYSCTL_DECL(_net_link);
100SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
101 "Generic Tunnel Interface");
102#ifndef MAX_GIF_NEST
103/*
104 * This macro controls the default upper limitation on nesting of gif tunnels.
105 * Since, setting a large value to this macro with a careless configuration
106 * may introduce system crash, we don't allow any nestings by default.
107 * If you need to configure nested gif tunnels, you can define this macro
108 * in your kernel configuration file. However, if you do so, please be
109 * careful to configure the tunnels so that it won't make a loop.
110 */
111#define MAX_GIF_NEST 1
112#endif
113static int max_gif_nesting = MAX_GIF_NEST;
114SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
115 &max_gif_nesting, 0, "Max nested tunnels");
116
117/*
118 * By default, we disallow creation of multiple tunnels between the same
119 * pair of addresses. Some applications require this functionality so
120 * we allow control over this check here.
121 */
122#ifdef XBONEHACK
123static int parallel_tunnels = 1;
124#else
125static int parallel_tunnels = 0;
126#endif
127SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
128 &parallel_tunnels, 0, "Allow parallel tunnels?");
129
130int
bf8c57c6 131gif_clone_create(struct if_clone *ifc, int unit)
984263bc 132{
984263bc 133 struct gif_softc *sc;
984263bc 134
efda3bd0 135 sc = kmalloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
984263bc
MD
136 bzero(sc, sizeof(struct gif_softc));
137
138 sc->gif_if.if_softc = sc;
cdb7d804 139 if_initname(&(sc->gif_if), GIFNAME, unit);
984263bc
MD
140
141 gifattach0(sc);
142
143 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
144 return (0);
145}
146
147void
bf8c57c6 148gifattach0(struct gif_softc *sc)
984263bc
MD
149{
150
151 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
152
153 sc->gif_if.if_addrlen = 0;
154 sc->gif_if.if_mtu = GIF_MTU;
155 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
156#if 0
157 /* turn off ingress filter */
158 sc->gif_if.if_flags |= IFF_LINK2;
159#endif
160 sc->gif_if.if_ioctl = gif_ioctl;
161 sc->gif_if.if_output = gif_output;
162 sc->gif_if.if_type = IFT_GIF;
163 sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
78195a76 164 if_attach(&sc->gif_if, NULL);
984263bc
MD
165 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
166}
167
168void
bf8c57c6 169gif_clone_destroy(struct ifnet *ifp)
984263bc
MD
170{
171 int err;
172 struct gif_softc *sc = ifp->if_softc;
173
174 gif_delete_tunnel(&sc->gif_if);
175 LIST_REMOVE(sc, gif_list);
176#ifdef INET6
177 if (sc->encap_cookie6 != NULL) {
178 err = encap_detach(sc->encap_cookie6);
179 KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
180 }
181#endif
182#ifdef INET
183 if (sc->encap_cookie4 != NULL) {
184 err = encap_detach(sc->encap_cookie4);
185 KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
186 }
187#endif
188
189 bpfdetach(ifp);
190 if_detach(ifp);
191
efda3bd0 192 kfree(sc, M_GIF);
984263bc
MD
193}
194
195static int
bf8c57c6 196gifmodevent(module_t mod, int type, void *data)
984263bc 197{
984263bc
MD
198
199 switch (type) {
200 case MOD_LOAD:
984263bc
MD
201 LIST_INIT(&gif_softc_list);
202 if_clone_attach(&gif_cloner);
203
204#ifdef INET6
205 ip6_gif_hlim = GIF_HLIM;
206#endif
207
208 break;
209 case MOD_UNLOAD:
210 if_clone_detach(&gif_cloner);
211
212 while (!LIST_EMPTY(&gif_softc_list))
213 gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
214
984263bc
MD
215#ifdef INET6
216 ip6_gif_hlim = 0;
217#endif
218 break;
219 }
220 return 0;
221}
222
223static moduledata_t gif_mod = {
224 "if_gif",
225 gifmodevent,
226 0
227};
228
229DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
230
231int
bf8c57c6 232gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
984263bc
MD
233{
234 struct ip ip;
235 struct gif_softc *sc;
236
237 sc = (struct gif_softc *)arg;
238 if (sc == NULL)
239 return 0;
240
241 if ((sc->gif_if.if_flags & IFF_UP) == 0)
242 return 0;
243
244 /* no physical address */
245 if (!sc->gif_psrc || !sc->gif_pdst)
246 return 0;
247
248 switch (proto) {
249#ifdef INET
250 case IPPROTO_IPV4:
251 break;
252#endif
253#ifdef INET6
254 case IPPROTO_IPV6:
255 break;
256#endif
257 default:
258 return 0;
259 }
260
261 /* Bail on short packets */
262 if (m->m_pkthdr.len < sizeof(ip))
263 return 0;
264
f15db79e 265 m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
984263bc
MD
266
267 switch (ip.ip_v) {
268#ifdef INET
269 case 4:
270 if (sc->gif_psrc->sa_family != AF_INET ||
271 sc->gif_pdst->sa_family != AF_INET)
272 return 0;
273 return gif_encapcheck4(m, off, proto, arg);
274#endif
275#ifdef INET6
276 case 6:
277 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
278 return 0;
279 if (sc->gif_psrc->sa_family != AF_INET6 ||
280 sc->gif_pdst->sa_family != AF_INET6)
281 return 0;
282 return gif_encapcheck6(m, off, proto, arg);
283#endif
284 default:
285 return 0;
286 }
287}
288
bf8c57c6
SW
289/*
290 * Parameters:
291 * rt: added in net2
292 */
984263bc 293int
bf8c57c6
SW
294gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
295 struct rtentry *rt)
984263bc
MD
296{
297 struct gif_softc *sc = (struct gif_softc*)ifp;
298 int error = 0;
299 static int called = 0; /* XXX: MUTEX */
300
301 /*
302 * gif may cause infinite recursion calls when misconfigured.
303 * We'll prevent this by introducing upper limit.
304 * XXX: this mechanism may introduce another problem about
305 * mutual exclusion of the variable CALLED, especially if we
306 * use kernel thread.
307 */
308 if (++called > max_gif_nesting) {
309 log(LOG_NOTICE,
310 "gif_output: recursively called too many times(%d)\n",
311 called);
312 m_freem(m);
313 error = EIO; /* is there better errno? */
314 goto end;
315 }
316
317 m->m_flags &= ~(M_BCAST|M_MCAST);
318 if (!(ifp->if_flags & IFF_UP) ||
319 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
320 m_freem(m);
321 error = ENETDOWN;
322 goto end;
323 }
324
325 if (ifp->if_bpf) {
326 /*
327 * We need to prepend the address family as
1f8e62c9 328 * a four byte field.
984263bc 329 */
1f8e62c9
JS
330 uint32_t af = dst->sa_family;
331
332 bpf_ptap(ifp->if_bpf, m, &af, sizeof(4));
984263bc
MD
333 }
334 ifp->if_opackets++;
335 ifp->if_obytes += m->m_pkthdr.len;
336
337 /* inner AF-specific encapsulation */
338
339 /* XXX should we check if our outer source is legal? */
340
341 /* dispatch to output logic based on outer AF */
342 switch (sc->gif_psrc->sa_family) {
343#ifdef INET
344 case AF_INET:
345 error = in_gif_output(ifp, dst->sa_family, m);
346 break;
347#endif
348#ifdef INET6
349 case AF_INET6:
350 error = in6_gif_output(ifp, dst->sa_family, m);
351 break;
352#endif
353 default:
354 m_freem(m);
355 error = ENETDOWN;
356 goto end;
357 }
358
359 end:
360 called = 0; /* reset recursion counter */
361 if (error)
362 ifp->if_oerrors++;
363 return error;
364}
365
366void
bf8c57c6 367gif_input(struct mbuf *m, int af, struct ifnet *ifp)
984263bc 368{
8bde602d 369 int isr;
984263bc
MD
370
371 if (ifp == NULL) {
372 /* just in case */
373 m_freem(m);
374 return;
375 }
376
377 m->m_pkthdr.rcvif = ifp;
378
379 if (ifp->if_bpf) {
380 /*
381 * We need to prepend the address family as
1f8e62c9 382 * a four byte field.
984263bc 383 */
1f8e62c9
JS
384 uint32_t af1 = af;
385
386 bpf_ptap(ifp->if_bpf, m, &af1, sizeof(af1));
984263bc
MD
387 }
388
389 /*
390 * Put the packet to the network layer input queue according to the
391 * specified address family.
392 * Note: older versions of gif_input directly called network layer
393 * input functions, e.g. ip6_input, here. We changed the policy to
394 * prevent too many recursive calls of such input functions, which
395 * might cause kernel panic. But the change may introduce another
396 * problem; if the input queue is full, packets are discarded.
397 * The kernel stack overflow really happened, and we believed
398 * queue-full rarely occurs, so we changed the policy.
399 */
400 switch (af) {
401#ifdef INET
402 case AF_INET:
984263bc
MD
403 isr = NETISR_IP;
404 break;
405#endif
406#ifdef INET6
407 case AF_INET6:
984263bc
MD
408 isr = NETISR_IPV6;
409 break;
410#endif
411 default:
412 m_freem(m);
413 return;
414 }
415
984263bc
MD
416 ifp->if_ipackets++;
417 ifp->if_ibytes += m->m_pkthdr.len;
8bde602d 418 netisr_dispatch(isr, m);
984263bc
MD
419
420 return;
421}
422
423/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
424int
bf8c57c6 425gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
984263bc
MD
426{
427 struct gif_softc *sc = (struct gif_softc*)ifp;
428 struct ifreq *ifr = (struct ifreq*)data;
429 int error = 0, size;
430 struct sockaddr *dst, *src;
431#ifdef SIOCSIFMTU /* xxx */
432 u_long mtu;
433#endif
434
435 switch (cmd) {
436 case SIOCSIFADDR:
437 ifp->if_flags |= IFF_UP;
438 break;
439
440 case SIOCSIFDSTADDR:
441 break;
442
443 case SIOCADDMULTI:
444 case SIOCDELMULTI:
445 break;
446
447#ifdef SIOCSIFMTU /* xxx */
448 case SIOCGIFMTU:
449 break;
450
451 case SIOCSIFMTU:
452 mtu = ifr->ifr_mtu;
453 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
454 return (EINVAL);
455 ifp->if_mtu = mtu;
456 break;
457#endif /* SIOCSIFMTU */
458
459#ifdef INET
460 case SIOCSIFPHYADDR:
461#endif
462#ifdef INET6
463 case SIOCSIFPHYADDR_IN6:
464#endif /* INET6 */
465 case SIOCSLIFPHYADDR:
466 switch (cmd) {
467#ifdef INET
468 case SIOCSIFPHYADDR:
469 src = (struct sockaddr *)
470 &(((struct in_aliasreq *)data)->ifra_addr);
471 dst = (struct sockaddr *)
472 &(((struct in_aliasreq *)data)->ifra_dstaddr);
473 break;
474#endif
475#ifdef INET6
476 case SIOCSIFPHYADDR_IN6:
477 src = (struct sockaddr *)
478 &(((struct in6_aliasreq *)data)->ifra_addr);
479 dst = (struct sockaddr *)
480 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
481 break;
482#endif
483 case SIOCSLIFPHYADDR:
484 src = (struct sockaddr *)
485 &(((struct if_laddrreq *)data)->addr);
486 dst = (struct sockaddr *)
487 &(((struct if_laddrreq *)data)->dstaddr);
488 break;
489 default:
490 return EINVAL;
491 }
492
493 /* sa_family must be equal */
494 if (src->sa_family != dst->sa_family)
495 return EINVAL;
496
497 /* validate sa_len */
498 switch (src->sa_family) {
499#ifdef INET
500 case AF_INET:
501 if (src->sa_len != sizeof(struct sockaddr_in))
502 return EINVAL;
503 break;
504#endif
505#ifdef INET6
506 case AF_INET6:
507 if (src->sa_len != sizeof(struct sockaddr_in6))
508 return EINVAL;
509 break;
510#endif
511 default:
512 return EAFNOSUPPORT;
513 }
514 switch (dst->sa_family) {
515#ifdef INET
516 case AF_INET:
517 if (dst->sa_len != sizeof(struct sockaddr_in))
518 return EINVAL;
519 break;
520#endif
521#ifdef INET6
522 case AF_INET6:
523 if (dst->sa_len != sizeof(struct sockaddr_in6))
524 return EINVAL;
525 break;
526#endif
527 default:
528 return EAFNOSUPPORT;
529 }
530
531 /* check sa_family looks sane for the cmd */
532 switch (cmd) {
533 case SIOCSIFPHYADDR:
534 if (src->sa_family == AF_INET)
535 break;
536 return EAFNOSUPPORT;
537#ifdef INET6
538 case SIOCSIFPHYADDR_IN6:
539 if (src->sa_family == AF_INET6)
540 break;
541 return EAFNOSUPPORT;
542#endif /* INET6 */
543 case SIOCSLIFPHYADDR:
544 /* checks done in the above */
545 break;
546 }
547
548 error = gif_set_tunnel(&sc->gif_if, src, dst);
549 break;
550
551#ifdef SIOCDIFPHYADDR
552 case SIOCDIFPHYADDR:
553 gif_delete_tunnel(&sc->gif_if);
554 break;
555#endif
556
557 case SIOCGIFPSRCADDR:
558#ifdef INET6
559 case SIOCGIFPSRCADDR_IN6:
560#endif /* INET6 */
561 if (sc->gif_psrc == NULL) {
562 error = EADDRNOTAVAIL;
563 goto bad;
564 }
565 src = sc->gif_psrc;
566 switch (cmd) {
567#ifdef INET
568 case SIOCGIFPSRCADDR:
569 dst = &ifr->ifr_addr;
570 size = sizeof(ifr->ifr_addr);
571 break;
572#endif /* INET */
573#ifdef INET6
574 case SIOCGIFPSRCADDR_IN6:
575 dst = (struct sockaddr *)
576 &(((struct in6_ifreq *)data)->ifr_addr);
577 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
578 break;
579#endif /* INET6 */
580 default:
581 error = EADDRNOTAVAIL;
582 goto bad;
583 }
584 if (src->sa_len > size)
585 return EINVAL;
586 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
587 break;
588
589 case SIOCGIFPDSTADDR:
590#ifdef INET6
591 case SIOCGIFPDSTADDR_IN6:
592#endif /* INET6 */
593 if (sc->gif_pdst == NULL) {
594 error = EADDRNOTAVAIL;
595 goto bad;
596 }
597 src = sc->gif_pdst;
598 switch (cmd) {
599#ifdef INET
600 case SIOCGIFPDSTADDR:
601 dst = &ifr->ifr_addr;
602 size = sizeof(ifr->ifr_addr);
603 break;
604#endif /* INET */
605#ifdef INET6
606 case SIOCGIFPDSTADDR_IN6:
607 dst = (struct sockaddr *)
608 &(((struct in6_ifreq *)data)->ifr_addr);
609 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
610 break;
611#endif /* INET6 */
612 default:
613 error = EADDRNOTAVAIL;
614 goto bad;
615 }
616 if (src->sa_len > size)
617 return EINVAL;
618 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
619 break;
620
621 case SIOCGLIFPHYADDR:
622 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
623 error = EADDRNOTAVAIL;
624 goto bad;
625 }
626
627 /* copy src */
628 src = sc->gif_psrc;
629 dst = (struct sockaddr *)
630 &(((struct if_laddrreq *)data)->addr);
631 size = sizeof(((struct if_laddrreq *)data)->addr);
632 if (src->sa_len > size)
633 return EINVAL;
634 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
635
636 /* copy dst */
637 src = sc->gif_pdst;
638 dst = (struct sockaddr *)
639 &(((struct if_laddrreq *)data)->dstaddr);
640 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
641 if (src->sa_len > size)
642 return EINVAL;
643 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
644 break;
645
646 case SIOCSIFFLAGS:
647 /* if_ioctl() takes care of it */
648 break;
649
650 default:
651 error = EINVAL;
652 break;
653 }
654 bad:
655 return error;
656}
657
658int
bf8c57c6 659gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
984263bc
MD
660{
661 struct gif_softc *sc = (struct gif_softc *)ifp;
662 struct gif_softc *sc2;
663 struct sockaddr *osrc, *odst, *sa;
984263bc
MD
664 int error = 0;
665
0b31d406 666 crit_enter();
984263bc
MD
667
668 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
669 if (sc2 == sc)
670 continue;
671 if (!sc2->gif_pdst || !sc2->gif_psrc)
672 continue;
673 if (sc2->gif_pdst->sa_family != dst->sa_family ||
674 sc2->gif_pdst->sa_len != dst->sa_len ||
675 sc2->gif_psrc->sa_family != src->sa_family ||
676 sc2->gif_psrc->sa_len != src->sa_len)
677 continue;
678
679 /*
680 * Disallow parallel tunnels unless instructed
681 * otherwise.
682 */
683 if (!parallel_tunnels &&
684 bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
685 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
686 error = EADDRNOTAVAIL;
687 goto bad;
688 }
689
690 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
691 }
692
693 /* XXX we can detach from both, but be polite just in case */
694 if (sc->gif_psrc)
695 switch (sc->gif_psrc->sa_family) {
696#ifdef INET
697 case AF_INET:
3bf25ce1 698 in_gif_detach(sc);
984263bc
MD
699 break;
700#endif
701#ifdef INET6
702 case AF_INET6:
3bf25ce1 703 in6_gif_detach(sc);
984263bc
MD
704 break;
705#endif
706 }
707
708 osrc = sc->gif_psrc;
efda3bd0 709 sa = (struct sockaddr *)kmalloc(src->sa_len, M_IFADDR, M_WAITOK);
984263bc
MD
710 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
711 sc->gif_psrc = sa;
712
713 odst = sc->gif_pdst;
efda3bd0 714 sa = (struct sockaddr *)kmalloc(dst->sa_len, M_IFADDR, M_WAITOK);
984263bc
MD
715 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
716 sc->gif_pdst = sa;
717
718 switch (sc->gif_psrc->sa_family) {
719#ifdef INET
720 case AF_INET:
721 error = in_gif_attach(sc);
722 break;
723#endif
724#ifdef INET6
725 case AF_INET6:
726 error = in6_gif_attach(sc);
727 break;
728#endif
729 }
730 if (error) {
731 /* rollback */
efda3bd0
MD
732 kfree((caddr_t)sc->gif_psrc, M_IFADDR);
733 kfree((caddr_t)sc->gif_pdst, M_IFADDR);
984263bc
MD
734 sc->gif_psrc = osrc;
735 sc->gif_pdst = odst;
736 goto bad;
737 }
738
739 if (osrc)
efda3bd0 740 kfree((caddr_t)osrc, M_IFADDR);
984263bc 741 if (odst)
efda3bd0 742 kfree((caddr_t)odst, M_IFADDR);
984263bc
MD
743
744 if (sc->gif_psrc && sc->gif_pdst)
745 ifp->if_flags |= IFF_RUNNING;
746 else
747 ifp->if_flags &= ~IFF_RUNNING;
0b31d406 748 crit_exit();
984263bc
MD
749
750 return 0;
751
752 bad:
753 if (sc->gif_psrc && sc->gif_pdst)
754 ifp->if_flags |= IFF_RUNNING;
755 else
756 ifp->if_flags &= ~IFF_RUNNING;
0b31d406 757 crit_exit();
984263bc
MD
758
759 return error;
760}
761
762void
bf8c57c6 763gif_delete_tunnel(struct ifnet *ifp)
984263bc
MD
764{
765 struct gif_softc *sc = (struct gif_softc *)ifp;
984263bc 766
0b31d406 767 crit_enter();
984263bc
MD
768
769 if (sc->gif_psrc) {
efda3bd0 770 kfree((caddr_t)sc->gif_psrc, M_IFADDR);
984263bc
MD
771 sc->gif_psrc = NULL;
772 }
773 if (sc->gif_pdst) {
efda3bd0 774 kfree((caddr_t)sc->gif_pdst, M_IFADDR);
984263bc
MD
775 sc->gif_pdst = NULL;
776 }
777 /* it is safe to detach from both */
778#ifdef INET
3bf25ce1 779 in_gif_detach(sc);
984263bc
MD
780#endif
781#ifdef INET6
3bf25ce1 782 in6_gif_detach(sc);
984263bc
MD
783#endif
784
785 if (sc->gif_psrc && sc->gif_pdst)
786 ifp->if_flags |= IFF_RUNNING;
787 else
788 ifp->if_flags &= ~IFF_RUNNING;
0b31d406 789 crit_exit();
984263bc 790}