]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_gif.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / net / if_gif.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
9bccf70c
A
25/* $FreeBSD: src/sys/net/if_gif.c,v 1.4.2.6 2001/07/24 19:10:18 brooks Exp $ */
26/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */
1c79356b
A
27
28/*
29 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
30 * All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. Neither the name of the project nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
1c79356b
A
57#include <sys/param.h>
58#include <sys/systm.h>
59#include <sys/kernel.h>
60#include <sys/malloc.h>
61#include <sys/mbuf.h>
62#include <sys/socket.h>
63#include <sys/sockio.h>
64#include <sys/errno.h>
65#include <sys/time.h>
66#include <sys/syslog.h>
9bccf70c 67#include <sys/protosw.h>
1c79356b
A
68#include <kern/cpu_number.h>
69
70#include <net/if.h>
71#include <net/if_types.h>
72#include <net/netisr.h>
73#include <net/route.h>
74#include <net/bpf.h>
75
1c79356b
A
76#include <netinet/in.h>
77#include <netinet/in_systm.h>
1c79356b 78#include <netinet/ip.h>
9bccf70c
A
79#if INET
80#include <netinet/in_var.h>
1c79356b 81#include <netinet/in_gif.h>
9bccf70c 82#include <netinet/ip_var.h>
1c79356b
A
83#endif /* INET */
84
85#if INET6
1c79356b
A
86#include <netinet6/in6_var.h>
87#include <netinet/ip6.h>
88#include <netinet6/ip6_var.h>
89#include <netinet6/in6_gif.h>
90#include <netinet6/ip6protosw.h>
91#endif /* INET6 */
92
93#include <netinet/ip_encap.h>
94#include <net/dlil.h>
95#include <net/if_gif.h>
96
1c79356b
A
97#include <net/net_osdep.h>
98
9bccf70c
A
99#define GIFNAME "gif"
100#define GIFDEV "if_gif"
101#define GIF_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */
1c79356b 102
9bccf70c
A
103#ifndef __APPLE__
104static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
105#endif
106
107TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs);
108
109#ifdef __APPLE__
110void gifattach __P((void));
1c79356b 111int gif_pre_output __P((struct ifnet *, register struct mbuf **, struct sockaddr *,
9bccf70c
A
112 caddr_t, char *, char *, u_long));
113static void gif_create_dev(void);
114static int gif_encapcheck(const struct mbuf*, int, int, void*);
115
116
117int ngif = 0; /* number of interfaces */
118#endif
119
120#if INET
121struct protosw in_gif_protosw =
122{ SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
123 in_gif_input, 0, 0, 0,
124 0,
125 0, 0, 0, 0,
126 0,
127 &rip_usrreqs
128};
129#endif
130#if INET6
131struct ip6protosw in6_gif_protosw =
132{ SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
133 in6_gif_input,
134 0, 0, 0,
135 0,
136 0, 0, 0, 0,
137 0,
138 &rip6_usrreqs
139};
140#endif
1c79356b 141
1c79356b
A
142#ifndef MAX_GIF_NEST
143/*
144 * This macro controls the upper limitation on nesting of gif tunnels.
145 * Since, setting a large value to this macro with a careless configuration
146 * may introduce system crash, we don't allow any nestings by default.
147 * If you need to configure nested gif tunnels, you can define this macro
148 * in your kernel configuration file. However, if you do so, please be
149 * careful to configure the tunnels so that it won't make a loop.
150 */
151#define MAX_GIF_NEST 1
152#endif
153static int max_gif_nesting = MAX_GIF_NEST;
154
155
156
9bccf70c
A
157#ifdef __APPLE__
158/*
159 * Theory of operation: initially, one gif interface is created.
160 * Any time a gif interface is configured, if there are no other
161 * unconfigured gif interfaces, a new gif interface is created.
162 * BSD uses the clone mechanism to dynamically create more
163 * gif interfaces.
164 *
165 * We have some extra glue to support DLIL.
166 */
167
168/* GIF interface module support */
1c79356b
A
169int gif_demux(ifp, m, frame_header, proto)
170 struct ifnet *ifp;
171 struct mbuf *m;
172 char *frame_header;
173 struct if_proto **proto;
174{
9bccf70c
A
175 struct gif_softc* gif = (struct gif_softc*)ifp->if_softc;
176
177 /* Only one protocol may be attached to a gif interface. */
178 *proto = gif->gif_proto;
179
180 return 0;
1c79356b
A
181}
182
1c79356b
A
183static
184int gif_add_if(struct ifnet *ifp)
9bccf70c
A
185{
186 ifp->if_demux = gif_demux;
1c79356b
A
187 ifp->if_framer = 0;
188 return 0;
189}
9bccf70c 190
1c79356b
A
191static
192int gif_del_if(struct ifnet *ifp)
193{
194 return 0;
195}
196
197static
198int gif_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag)
9bccf70c
A
199{
200 /* Only one protocol may be attached at a time */
201 struct gif_softc* gif = (struct gif_softc*)proto->ifp;
1c79356b 202
9bccf70c
A
203 if (gif->gif_proto != NULL)
204 printf("gif_add_proto: request add_proto for gif%d\n", gif->gif_if.if_unit);
1c79356b 205
9bccf70c 206 gif->gif_proto = proto;
1c79356b 207
9bccf70c 208 return 0;
1c79356b
A
209}
210
211static
212int gif_del_proto(struct if_proto *proto, u_long dl_tag)
9bccf70c
A
213{
214 if (((struct gif_softc*)proto->ifp)->gif_proto == proto)
215 ((struct gif_softc*)proto->ifp)->gif_proto = NULL;
216 else
217 return ENOENT;
1c79356b 218
9bccf70c 219 return 0;
1c79356b
A
220}
221
222int gif_shutdown()
223{
9bccf70c 224 return 0;
1c79356b
A
225}
226
227void gif_reg_if_mods()
228{
229 struct dlil_ifmod_reg_str gif_ifmod;
230
9bccf70c 231 bzero(&gif_ifmod, sizeof(gif_ifmod));
1c79356b
A
232 gif_ifmod.add_if = gif_add_if;
233 gif_ifmod.del_if = gif_del_if;
234 gif_ifmod.add_proto = gif_add_proto;
235 gif_ifmod.del_proto = gif_del_proto;
236 gif_ifmod.ifmod_ioctl = 0;
237 gif_ifmod.shutdown = gif_shutdown;
238
239 if (dlil_reg_if_modules(APPLE_IF_FAM_GIF, &gif_ifmod))
240 panic("Couldn't register gif modules\n");
241
9bccf70c 242}
1c79356b 243
9bccf70c
A
244/* Glue code to attach inet to a gif interface through DLIL */
245
246u_long gif_attach_proto_family(struct ifnet *ifp, int af)
1c79356b
A
247{
248 struct dlil_proto_reg_str reg;
249 struct dlil_demux_desc desc;
250 u_long dl_tag=0;
251 short native=0;
9bccf70c
A
252 int stat;
253
254 /* Check if we're already attached */
255 stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, af, &dl_tag);
256 if (stat == 0)
257 return dl_tag;
1c79356b
A
258
259 TAILQ_INIT(&reg.demux_desc_head);
260 desc.type = DLIL_DESC_RAW;
261 desc.variants.bitmask.proto_id_length = 0;
262 desc.variants.bitmask.proto_id = 0;
263 desc.variants.bitmask.proto_id_mask = 0;
264 desc.native_type = (char *) &native;
265 TAILQ_INSERT_TAIL(&reg.demux_desc_head, &desc, next);
266 reg.interface_family = ifp->if_family;
267 reg.unit_number = ifp->if_unit;
268 reg.input = gif_input;
269 reg.pre_output = gif_pre_output;
270 reg.event = 0;
271 reg.offer = 0;
9bccf70c 272 reg.ioctl = 0;
1c79356b 273 reg.default_proto = 0;
9bccf70c 274 reg.protocol_family = af;
1c79356b
A
275
276 stat = dlil_attach_protocol(&reg, &dl_tag);
277 if (stat) {
9bccf70c 278 panic("gif_attach_proto_family can't attach interface fam=%d\n", af);
1c79356b
A
279 }
280
281 return dl_tag;
282}
283
9bccf70c
A
284u_long gif_detach_proto_family(struct ifnet *ifp, int af)
285{
286 u_long ip_dl_tag = 0;
287 int stat;
288
289 stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, af, &ip_dl_tag);
290 if (stat == 0) {
291 stat = dlil_detach_protocol(ip_dl_tag);
292 if (stat) {
293 printf("WARNING: gif_detach can't detach IP fam=%d from interface\n", af);
294 }
295 }
296 return (stat);
297}
298
299#endif
300
301/* Function to setup the first gif interface */
1c79356b 302void
9bccf70c 303gifattach(void)
1c79356b 304{
9bccf70c
A
305 /* Init the list of interfaces */
306 TAILQ_INIT(&gifs);
1c79356b
A
307
308 gif_reg_if_mods(); /* DLIL modules */
309
9bccf70c
A
310 /* Create first device */
311 gif_create_dev();
312}
313
314/* Creates another gif device if there are none free */
315static void
316gif_create_dev(void)
317{
318 struct gif_softc *sc;
319
320
321 /* Can't create more than GIF_MAXUNIT */
322 if (ngif >= GIF_MAXUNIT)
323 return;
324
325 /* Check for unused gif interface */
326 TAILQ_FOREACH(sc, &gifs, gif_link) {
327 /* If unused, return, no need to create a new interface */
328 if ((sc->gif_if.if_flags & IFF_RUNNING) == 0)
329 return;
330 }
331
332 sc = _MALLOC(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
333 if (sc == NULL) {
334 log(LOG_ERR, "gifattach: failed to allocate gif%d\n", ngif);
335 return;
336 }
337
338 bzero(sc, sizeof(struct gif_softc));
339 sc->gif_if.if_softc = sc;
340 sc->gif_if.if_name = GIFNAME;
341 sc->gif_if.if_unit = ngif;
342
343 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
344#ifdef INET
345 sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
346 gif_encapcheck, &in_gif_protosw, sc);
347 if (sc->encap_cookie4 == NULL) {
348 printf("%s: unable to attach encap4\n", if_name(&sc->gif_if));
349 FREE(sc, M_DEVBUF);
350 return;
351 }
352#endif
353#ifdef INET6
354 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
355 gif_encapcheck, (struct protosw*)&in6_gif_protosw, sc);
356 if (sc->encap_cookie6 == NULL) {
357 if (sc->encap_cookie4) {
358 encap_detach(sc->encap_cookie4);
359 sc->encap_cookie4 = NULL;
360 }
361 printf("%s: unable to attach encap6\n", if_name(&sc->gif_if));
362 FREE(sc, M_DEVBUF);
363 return;
364 }
365#endif
366
367 sc->gif_if.if_family= APPLE_IF_FAM_GIF;
368 sc->gif_if.if_mtu = GIF_MTU;
369 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
1c79356b 370#if 0
9bccf70c
A
371 /* turn off ingress filter */
372 sc->gif_if.if_flags |= IFF_LINK2;
1c79356b 373#endif
9bccf70c
A
374 sc->gif_if.if_ioctl = gif_ioctl;
375 sc->gif_if.if_output = NULL; /* pre_output returns error or EJUSTRETURN */
376 sc->gif_if.if_type = IFT_GIF;
377 dlil_if_attach(&sc->gif_if);
378 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
379 TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
380 ngif++;
381}
382
383static int
384gif_encapcheck(m, off, proto, arg)
385 const struct mbuf *m;
386 int off;
387 int proto;
388 void *arg;
389{
390 struct ip ip;
391 struct gif_softc *sc;
392
393 sc = (struct gif_softc *)arg;
394 if (sc == NULL)
395 return 0;
396
397 if ((sc->gif_if.if_flags & IFF_UP) == 0)
398 return 0;
399
400 /* no physical address */
401 if (!sc->gif_psrc || !sc->gif_pdst)
402 return 0;
403
404 switch (proto) {
405#if INET
406 case IPPROTO_IPV4:
407 break;
1c79356b 408#endif
9bccf70c
A
409#if INET6
410 case IPPROTO_IPV6:
411 break;
1c79356b 412#endif
9bccf70c
A
413 default:
414 return 0;
1c79356b 415 }
1c79356b 416
9bccf70c
A
417 /* LINTED const cast */
418 m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
419
420 switch (ip.ip_v) {
421#if INET
422 case 4:
423 if (sc->gif_psrc->sa_family != AF_INET ||
424 sc->gif_pdst->sa_family != AF_INET)
425 return 0;
426 return gif_encapcheck4(m, off, proto, arg);
427#endif
428#if INET6
429 case 6:
430 if (sc->gif_psrc->sa_family != AF_INET6 ||
431 sc->gif_pdst->sa_family != AF_INET6)
432 return 0;
433 return gif_encapcheck6(m, off, proto, arg);
1c79356b 434#endif
9bccf70c
A
435 default:
436 return 0;
437 }
438}
1c79356b
A
439
440int
441gif_pre_output(ifp, m0, dst, rt, frame, address, dl_tag)
442 struct ifnet *ifp;
443 struct mbuf **m0;
444 struct sockaddr *dst;
9bccf70c 445 caddr_t rt;
1c79356b
A
446 char *frame;
447 char *address;
448 u_long dl_tag;
449{
9bccf70c 450 struct gif_softc *sc = (struct gif_softc*)ifp;
1c79356b
A
451 register struct mbuf * m = *m0;
452 int error = 0;
453 static int called = 0; /* XXX: MUTEX */
454
455 /*
456 * gif may cause infinite recursion calls when misconfigured.
457 * We'll prevent this by introducing upper limit.
458 * XXX: this mechanism may introduce another problem about
459 * mutual exclusion of the variable CALLED, especially if we
460 * use kernel thread.
461 */
462 if (++called > max_gif_nesting) {
463 log(LOG_NOTICE,
464 "gif_output: recursively called too many times(%d)\n",
465 called);
1c79356b
A
466 error = EIO; /* is there better errno? */
467 goto end;
468 }
469
470 getmicrotime(&ifp->if_lastchange);
471 m->m_flags &= ~(M_BCAST|M_MCAST);
472 if (!(ifp->if_flags & IFF_UP) ||
1c79356b 473 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
1c79356b 474 error = ENETDOWN;
1c79356b
A
475 goto end;
476 }
477
1c79356b
A
478 if (ifp->if_bpf) {
479 /*
480 * We need to prepend the address family as
481 * a four byte field. Cons up a dummy header
482 * to pacify bpf. This is safe because bpf
483 * will only read from the mbuf (i.e., it won't
484 * try to free it or keep a pointer a to it).
485 */
486 struct mbuf m0;
9bccf70c 487 u_int32_t af = dst->sa_family;
1c79356b
A
488
489 m0.m_next = m;
490 m0.m_len = 4;
491 m0.m_data = (char *)&af;
492
1c79356b 493 bpf_mtap(ifp, &m0);
1c79356b 494 }
1c79356b
A
495 ifp->if_opackets++;
496 ifp->if_obytes += m->m_pkthdr.len;
1c79356b 497
9bccf70c
A
498 /* inner AF-specific encapsulation */
499
500 /* XXX should we check if our outer source is legal? */
501
502 /* dispatch to output logic based on outer AF */
1c79356b
A
503 switch (sc->gif_psrc->sa_family) {
504#if INET
505 case AF_INET:
9bccf70c 506 error = in_gif_output(ifp, dst->sa_family, m, (struct rtentry*)rt);
1c79356b
A
507 break;
508#endif
509#if INET6
510 case AF_INET6:
9bccf70c 511 error = in6_gif_output(ifp, dst->sa_family, m, (struct rtentry*)rt);
1c79356b
A
512 break;
513#endif
514 default:
1c79356b 515 error = ENETDOWN;
9bccf70c 516 goto end;
1c79356b 517 }
1c79356b
A
518
519 end:
520 called = 0; /* reset recursion counter */
9bccf70c
A
521 if (error)
522 ifp->if_oerrors++;
523 if (error == 0)
524 error = EJUSTRETURN; /* if no error, packet got sent already */
525 return error;
1c79356b
A
526}
527
9bccf70c
A
528int
529gif_input(m, frame_header, gifp, dl_tag, sync_ok)
1c79356b 530 struct mbuf *m;
9bccf70c
A
531 char* frame_header;
532 struct ifnet* gifp;
533 u_long dl_tag;
534 int sync_ok;
1c79356b
A
535{
536 int s, isr;
9bccf70c
A
537 struct ifqueue *ifq = 0;
538 int af;
1c79356b
A
539
540 if (gifp == NULL) {
541 /* just in case */
542 m_freem(m);
543 return;
544 }
545
9bccf70c
A
546 /* Assume packet is of type of protocol attached to this interface */
547 af = ((struct gif_softc*)(gifp->if_softc))->gif_proto->protocol_family;
548
1c79356b
A
549 if (m->m_pkthdr.rcvif)
550 m->m_pkthdr.rcvif = gifp;
551
1c79356b
A
552 if (gifp->if_bpf) {
553 /*
554 * We need to prepend the address family as
555 * a four byte field. Cons up a dummy header
556 * to pacify bpf. This is safe because bpf
557 * will only read from the mbuf (i.e., it won't
558 * try to free it or keep a pointer a to it).
559 */
560 struct mbuf m0;
9bccf70c 561 u_int32_t af1 = af;
1c79356b
A
562
563 m0.m_next = m;
564 m0.m_len = 4;
9bccf70c 565 m0.m_data = (char *)&af1;
1c79356b 566
1c79356b 567 bpf_mtap(gifp, &m0);
1c79356b 568 }
1c79356b
A
569
570 /*
571 * Put the packet to the network layer input queue according to the
572 * specified address family.
573 * Note: older versions of gif_input directly called network layer
574 * input functions, e.g. ip6_input, here. We changed the policy to
575 * prevent too many recursive calls of such input functions, which
576 * might cause kernel panic. But the change may introduce another
577 * problem; if the input queue is full, packets are discarded.
578 * We believed it rarely occurs and changed the policy. If we find
579 * it occurs more times than we thought, we may change the policy
580 * again.
581 */
582 switch (af) {
583#if INET
584 case AF_INET:
585 ifq = &ipintrq;
586 isr = NETISR_IP;
587 break;
588#endif
589#if INET6
590 case AF_INET6:
591 ifq = &ip6intrq;
592 isr = NETISR_IPV6;
593 break;
594#endif
595 default:
596 m_freem(m);
9bccf70c 597 return (EJUSTRETURN);
1c79356b
A
598 }
599
600 s = splimp();
601 if (IF_QFULL(ifq)) {
602 IF_DROP(ifq); /* update statistics */
603 m_freem(m);
604 splx(s);
9bccf70c 605 return (EJUSTRETURN);
1c79356b
A
606 }
607 IF_ENQUEUE(ifq, m);
608 /* we need schednetisr since the address family may change */
609 schednetisr(isr);
610 gifp->if_ipackets++;
611 gifp->if_ibytes += m->m_pkthdr.len;
612 splx(s);
613
9bccf70c 614 return (0);
1c79356b
A
615}
616
617/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
618int
619gif_ioctl(ifp, cmd, data)
620 struct ifnet *ifp;
621 u_long cmd;
9bccf70c 622 void* data;
1c79356b
A
623{
624 struct gif_softc *sc = (struct gif_softc*)ifp;
625 struct ifreq *ifr = (struct ifreq*)data;
626 int error = 0, size;
627 struct sockaddr *dst, *src;
9bccf70c
A
628 struct sockaddr *sa;
629 int s;
630 struct ifnet *ifp2;
1c79356b
A
631 struct gif_softc *sc2;
632
633 switch (cmd) {
634 case SIOCSIFADDR:
635 break;
636
637 case SIOCSIFDSTADDR:
638 break;
639
640 case SIOCADDMULTI:
641 case SIOCDELMULTI:
1c79356b
A
642 break;
643
644#ifdef SIOCSIFMTU /* xxx */
1c79356b
A
645 case SIOCGIFMTU:
646 break;
9bccf70c 647
1c79356b
A
648 case SIOCSIFMTU:
649 {
1c79356b
A
650 u_long mtu;
651 mtu = ifr->ifr_mtu;
1c79356b
A
652 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
653 return (EINVAL);
654 }
655 ifp->if_mtu = mtu;
656 }
657 break;
1c79356b
A
658#endif /* SIOCSIFMTU */
659
660 case SIOCSIFPHYADDR:
661#if INET6
662 case SIOCSIFPHYADDR_IN6:
663#endif /* INET6 */
9bccf70c
A
664 case SIOCSLIFPHYADDR:
665 switch (cmd) {
666#if INET
667 case SIOCSIFPHYADDR:
668 src = (struct sockaddr *)
669 &(((struct in_aliasreq *)data)->ifra_addr);
670 dst = (struct sockaddr *)
671 &(((struct in_aliasreq *)data)->ifra_dstaddr);
672 break;
673#endif
674#if INET6
675 case SIOCSIFPHYADDR_IN6:
676 src = (struct sockaddr *)
677 &(((struct in6_aliasreq *)data)->ifra_addr);
678 dst = (struct sockaddr *)
679 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
680 break;
681#endif
682 case SIOCSLIFPHYADDR:
683 src = (struct sockaddr *)
684 &(((struct if_laddrreq *)data)->addr);
685 dst = (struct sockaddr *)
686 &(((struct if_laddrreq *)data)->dstaddr);
687 }
688
689 /* sa_family must be equal */
690 if (src->sa_family != dst->sa_family)
691 return EINVAL;
692
693 /* validate sa_len */
694 switch (src->sa_family) {
695#if INET
696 case AF_INET:
697 if (src->sa_len != sizeof(struct sockaddr_in))
698 return EINVAL;
699 break;
700#endif
701#if INET6
702 case AF_INET6:
703 if (src->sa_len != sizeof(struct sockaddr_in6))
704 return EINVAL;
705 break;
706#endif
707 default:
708 return EAFNOSUPPORT;
709 }
710 switch (dst->sa_family) {
711#if INET
712 case AF_INET:
713 if (dst->sa_len != sizeof(struct sockaddr_in))
714 return EINVAL;
715 break;
716#endif
717#if INET6
718 case AF_INET6:
719 if (dst->sa_len != sizeof(struct sockaddr_in6))
720 return EINVAL;
721 break;
722#endif
723 default:
724 return EAFNOSUPPORT;
725 }
726
727 /* check sa_family looks sane for the cmd */
728 switch (cmd) {
729 case SIOCSIFPHYADDR:
730 if (src->sa_family == AF_INET)
731 break;
732 return EAFNOSUPPORT;
733#if INET6
734 case SIOCSIFPHYADDR_IN6:
735 if (src->sa_family == AF_INET6)
736 break;
737 return EAFNOSUPPORT;
738#endif /* INET6 */
739 case SIOCSLIFPHYADDR:
740 /* checks done in the above */
741 break;
742 }
743
744 TAILQ_FOREACH(ifp2, &ifnet, if_link) {
745 if (strcmp(ifp2->if_name, GIFNAME) != 0)
746 continue;
747 sc2 = ifp2->if_softc;
1c79356b
A
748 if (sc2 == sc)
749 continue;
750 if (!sc2->gif_pdst || !sc2->gif_psrc)
751 continue;
9bccf70c
A
752 if (sc2->gif_pdst->sa_family != dst->sa_family ||
753 sc2->gif_pdst->sa_len != dst->sa_len ||
754 sc2->gif_psrc->sa_family != src->sa_family ||
755 sc2->gif_psrc->sa_len != src->sa_len)
756 continue;
757#ifndef XBONEHACK
758 /* can't configure same pair of address onto two gifs */
759 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
1c79356b
A
760 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
761 error = EADDRNOTAVAIL;
762 goto bad;
763 }
9bccf70c 764#endif
1c79356b 765
9bccf70c
A
766 /* can't configure multiple multi-dest interfaces */
767#define multidest(x) \
768 (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
1c79356b 769#if INET6
9bccf70c
A
770#define multidest6(x) \
771 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
772#endif
773 if (dst->sa_family == AF_INET &&
774 multidest(dst) && multidest(sc2->gif_pdst)) {
775 error = EADDRNOTAVAIL;
776 goto bad;
777 }
778#if INET6
779 if (dst->sa_family == AF_INET6 &&
780 multidest6(dst) && multidest6(sc2->gif_pdst)) {
781 error = EADDRNOTAVAIL;
782 goto bad;
783 }
784#endif
1c79356b 785 }
9bccf70c
A
786
787 if (sc->gif_psrc)
788 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
789 sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR, M_WAITOK);
790 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
791 sc->gif_psrc = sa;
792
793 if (sc->gif_pdst)
794 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
795 sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR, M_WAITOK);
796 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
797 sc->gif_pdst = sa;
798
799 ifp->if_flags |= IFF_RUNNING;
800
801 gif_attach_proto_family(ifp, src->sa_family);
802
803 s = splimp();
804 if_up(ifp); /* mark interface UP and send up RTM_IFINFO */
805#ifdef __APPLE__
806 /* Make sure at least one unused device is still available */
807 gif_create_dev();
808#endif
809 splx(s);
810
811 error = 0;
1c79356b 812 break;
9bccf70c
A
813
814#ifdef SIOCDIFPHYADDR
815 case SIOCDIFPHYADDR:
816 if (sc->gif_psrc) {
817 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
818 sc->gif_psrc = NULL;
819 }
820 if (sc->gif_pdst) {
821 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
822 sc->gif_pdst = NULL;
823 }
824 /* change the IFF_{UP, RUNNING} flag as well? */
825 break;
826#endif
1c79356b
A
827
828 case SIOCGIFPSRCADDR:
829#if INET6
830 case SIOCGIFPSRCADDR_IN6:
831#endif /* INET6 */
832 if (sc->gif_psrc == NULL) {
833 error = EADDRNOTAVAIL;
834 goto bad;
835 }
836 src = sc->gif_psrc;
9bccf70c 837 switch (cmd) {
1c79356b 838#if INET
9bccf70c 839 case SIOCGIFPSRCADDR:
1c79356b 840 dst = &ifr->ifr_addr;
9bccf70c 841 size = sizeof(ifr->ifr_addr);
1c79356b
A
842 break;
843#endif /* INET */
844#if INET6
9bccf70c 845 case SIOCGIFPSRCADDR_IN6:
1c79356b
A
846 dst = (struct sockaddr *)
847 &(((struct in6_ifreq *)data)->ifr_addr);
9bccf70c 848 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
1c79356b
A
849 break;
850#endif /* INET6 */
851 default:
852 error = EADDRNOTAVAIL;
853 goto bad;
854 }
9bccf70c
A
855 if (src->sa_len > size)
856 return EINVAL;
857 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
1c79356b
A
858 break;
859
860 case SIOCGIFPDSTADDR:
861#if INET6
862 case SIOCGIFPDSTADDR_IN6:
863#endif /* INET6 */
864 if (sc->gif_pdst == NULL) {
865 error = EADDRNOTAVAIL;
866 goto bad;
867 }
868 src = sc->gif_pdst;
9bccf70c 869 switch (cmd) {
1c79356b 870#if INET
9bccf70c 871 case SIOCGIFPDSTADDR:
1c79356b 872 dst = &ifr->ifr_addr;
9bccf70c 873 size = sizeof(ifr->ifr_addr);
1c79356b
A
874 break;
875#endif /* INET */
876#if INET6
9bccf70c 877 case SIOCGIFPDSTADDR_IN6:
1c79356b
A
878 dst = (struct sockaddr *)
879 &(((struct in6_ifreq *)data)->ifr_addr);
9bccf70c 880 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
1c79356b
A
881 break;
882#endif /* INET6 */
883 default:
884 error = EADDRNOTAVAIL;
885 goto bad;
886 }
9bccf70c
A
887 if (src->sa_len > size)
888 return EINVAL;
889 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
1c79356b
A
890 break;
891
9bccf70c
A
892 case SIOCGLIFPHYADDR:
893 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
894 error = EADDRNOTAVAIL;
1c79356b 895 goto bad;
1c79356b 896 }
9bccf70c
A
897
898 /* copy src */
899 src = sc->gif_psrc;
900 dst = (struct sockaddr *)
901 &(((struct if_laddrreq *)data)->addr);
902 size = sizeof(((struct if_laddrreq *)data)->addr);
903 if (src->sa_len > size)
904 return EINVAL;
905 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
906
907 /* copy dst */
908 src = sc->gif_pdst;
909 dst = (struct sockaddr *)
910 &(((struct if_laddrreq *)data)->dstaddr);
911 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
912 if (src->sa_len > size)
913 return EINVAL;
914 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
915 break;
916
917 case SIOCSIFFLAGS:
918 /* if_ioctl() takes care of it */
1c79356b
A
919 break;
920
921 default:
9bccf70c 922 error = EOPNOTSUPP;
1c79356b
A
923 break;
924 }
925 bad:
926 return error;
927}
9bccf70c
A
928
929void
930gif_delete_tunnel(sc)
931 struct gif_softc *sc;
932{
933 /* XXX: NetBSD protects this function with splsoftnet() */
934
935 if (sc->gif_psrc) {
936 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
937 sc->gif_psrc = NULL;
938 }
939 if (sc->gif_pdst) {
940 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
941 sc->gif_pdst = NULL;
942 }
943 /* change the IFF_UP flag as well? */
944}