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