xref: /openbsd/sys/net/if_gif.c (revision 404b540a)
1 /*	$OpenBSD: if_gif.c,v 1.51 2008/11/24 14:55:53 claudio Exp $	*/
2 /*	$KAME: if_gif.c,v 1.43 2001/02/20 08:51:07 itojun Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
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 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/mbuf.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <sys/syslog.h>
40 
41 #include <net/if.h>
42 #include <net/if_types.h>
43 #include <net/route.h>
44 #include <net/bpf.h>
45 
46 #ifdef	INET
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/in_var.h>
50 #include <netinet/in_gif.h>
51 #include <netinet/ip.h>
52 #endif	/* INET */
53 
54 #ifdef INET6
55 #ifndef INET
56 #include <netinet/in.h>
57 #endif
58 #include <netinet/ip6.h>
59 #include <netinet6/in6_gif.h>
60 #endif /* INET6 */
61 
62 #include <net/if_gif.h>
63 
64 #include "bpfilter.h"
65 #include "bridge.h"
66 
67 void	gifattach(int);
68 int	gif_clone_create(struct if_clone *, int);
69 int	gif_clone_destroy(struct ifnet *);
70 
71 /*
72  * gif global variable definitions
73  */
74 struct gif_softc_head gif_softc_list;
75 struct if_clone gif_cloner =
76     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
77 
78 /* ARGSUSED */
79 void
80 gifattach(int count)
81 {
82 	LIST_INIT(&gif_softc_list);
83 	if_clone_attach(&gif_cloner);
84 }
85 
86 int
87 gif_clone_create(struct if_clone *ifc, int unit)
88 {
89 	struct gif_softc *sc;
90 	int s;
91 
92 	sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO);
93 	if (!sc)
94 		return (ENOMEM);
95 
96 	snprintf(sc->gif_if.if_xname, sizeof sc->gif_if.if_xname,
97 	     "%s%d", ifc->ifc_name, unit);
98 	sc->gif_if.if_mtu    = GIF_MTU;
99 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
100 	sc->gif_if.if_ioctl  = gif_ioctl;
101 	sc->gif_if.if_start  = gif_start;
102 	sc->gif_if.if_output = gif_output;
103 	sc->gif_if.if_type   = IFT_GIF;
104 	IFQ_SET_MAXLEN(&sc->gif_if.if_snd, ifqmaxlen);
105 	IFQ_SET_READY(&sc->gif_if.if_snd);
106 	sc->gif_if.if_softc = sc;
107 	if_attach(&sc->gif_if);
108 	if_alloc_sadl(&sc->gif_if);
109 
110 #if NBPFILTER > 0
111 	bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL,
112 	    sizeof(u_int));
113 #endif
114 	s = splnet();
115 	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
116 	splx(s);
117 
118 	return (0);
119 }
120 
121 int
122 gif_clone_destroy(struct ifnet *ifp)
123 {
124 	struct gif_softc *sc = ifp->if_softc;
125 	int s;
126 
127 	s = splnet();
128 	LIST_REMOVE(sc, gif_list);
129 	splx(s);
130 
131 	if_detach(ifp);
132 
133 	if (sc->gif_psrc)
134 		free((caddr_t)sc->gif_psrc, M_IFADDR);
135 	sc->gif_psrc = NULL;
136 	if (sc->gif_pdst)
137 		free((caddr_t)sc->gif_pdst, M_IFADDR);
138 	sc->gif_pdst = NULL;
139 	free(sc, M_DEVBUF);
140 	return (0);
141 }
142 
143 void
144 gif_start(struct ifnet *ifp)
145 {
146 	struct gif_softc *sc = (struct gif_softc*)ifp;
147 	struct mbuf *m;
148 	struct m_tag *mtag;
149 	int family;
150 	int s;
151 	u_int8_t tp;
152 
153 	/* is interface up and running? */
154 	if ((ifp->if_flags & (IFF_OACTIVE | IFF_UP)) != IFF_UP ||
155 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL)
156 		return;
157 
158 	/* are the tunnel endpoints valid? */
159 #ifdef INET
160 	if (sc->gif_psrc->sa_family != AF_INET)
161 #endif
162 #ifdef INET6
163 		if (sc->gif_psrc->sa_family != AF_INET6)
164 #endif
165 			return;
166 
167 	while (1) {
168 		s = splnet();
169 		IFQ_DEQUEUE(&ifp->if_snd, m);
170 		splx(s);
171 
172 		if (m == NULL)
173 			break;
174 
175 		/*
176 		 * gif may cause infinite recursion calls when misconfigured.
177 		 * We'll prevent this by detecting loops.
178 		 */
179 		for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag;
180 		    mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) {
181 			if (!bcmp((caddr_t)(mtag + 1), &ifp,
182 			    sizeof(struct ifnet *))) {
183 				IF_DROP(&ifp->if_snd);
184 				log(LOG_NOTICE, "gif_output: "
185 				    "recursively called too many times\n");
186 				m_freem(m);
187 				break;
188 			}
189 		}
190 		if (mtag)
191 			continue;
192 
193 		mtag = m_tag_get(PACKET_TAG_GIF, sizeof(caddr_t), M_NOWAIT);
194 		if (mtag == NULL) {
195 			m_freem(m);
196 			break;
197 		}
198 		bcopy(&ifp, mtag + 1, sizeof(caddr_t));
199 		m_tag_prepend(m, mtag);
200 
201 		/*
202 		 * Remove multicast and broadcast flags or encapsulated packet
203 		 * ends up as multicast or broadcast packet.
204 		 */
205 		m->m_flags &= ~(M_BCAST|M_MCAST);
206 
207 		/* extract address family */
208 		family = AF_UNSPEC;
209 		tp = *mtod(m, u_int8_t *);
210 		tp = (tp >> 4) & 0xff;  /* Get the IP version number. */
211 #ifdef INET
212 		if (tp == IPVERSION)
213 			family = AF_INET;
214 #endif
215 #ifdef INET6
216 		if (tp == (IPV6_VERSION >> 4))
217 			family = AF_INET6;
218 #endif
219 
220 #if NBRIDGE > 0
221 		/*
222 		 * Check if the packet is comming via bridge and needs
223 		 * etherip encapsulation or not.
224 		 */
225 		if (ifp->if_bridge && (m->m_flags & M_PROTO1)) {
226 			m->m_flags &= ~M_PROTO1;
227 			family = AF_LINK;
228 		}
229 #endif
230 
231 #if NBPFILTER > 0
232 		if (ifp->if_bpf)
233 			bpf_mtap_af(ifp->if_bpf, family, m, BPF_DIRECTION_OUT);
234 #endif
235 		ifp->if_opackets++;
236 		ifp->if_obytes += m->m_pkthdr.len;
237 
238 		switch (sc->gif_psrc->sa_family) {
239 #ifdef INET
240 		case AF_INET:
241 			in_gif_output(ifp, family, m);
242 			break;
243 #endif
244 #ifdef INET6
245 		case AF_INET6:
246 			in6_gif_output(ifp, family, m);
247 			break;
248 #endif
249 		default:
250 			m_freem(m);
251 			break;
252 		}
253 	}
254 }
255 
256 int
257 gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
258     struct rtentry *rt)
259 {
260 	struct gif_softc *sc = (struct gif_softc*)ifp;
261 	int error = 0;
262 	int s;
263 
264 	if (!(ifp->if_flags & IFF_UP) ||
265 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
266 		m_freem(m);
267 		error = ENETDOWN;
268 		goto end;
269 	}
270 
271 	switch (sc->gif_psrc->sa_family) {
272 #ifdef INET
273 	case AF_INET:
274 		break;
275 #endif
276 #ifdef INET6
277 	case AF_INET6:
278 		break;
279 #endif
280 	default:
281 		m_freem(m);
282 		error = ENETDOWN;
283 		goto end;
284 	}
285 
286 	s = splnet();
287 	/*
288 	 * Queue message on interface, and start output if interface
289 	 * not yet active.
290 	 */
291 	IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
292 	if (error) {
293 		/* mbuf is already freed */
294 		splx(s);
295 		return (error);
296 	}
297 	if_start(ifp);
298 	splx(s);
299 	return (error);
300 
301 end:
302 	if (error)
303 		ifp->if_oerrors++;
304 	return (error);
305 }
306 
307 int
308 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
309 {
310 	struct gif_softc *sc  = (struct gif_softc*)ifp;
311 	struct ifreq     *ifr = (struct ifreq*)data;
312 	int error = 0, size;
313 	struct sockaddr *dst, *src;
314 	struct sockaddr *sa;
315 	int s;
316 	struct gif_softc *sc2;
317 
318 	switch (cmd) {
319 	case SIOCSIFADDR:
320 		break;
321 
322 	case SIOCSIFDSTADDR:
323 		break;
324 
325 	case SIOCADDMULTI:
326 	case SIOCDELMULTI:
327 		switch (ifr->ifr_addr.sa_family) {
328 #ifdef INET
329 		case AF_INET:	/* IP supports Multicast */
330 			break;
331 #endif /* INET */
332 #ifdef INET6
333 		case AF_INET6:	/* IP6 supports Multicast */
334 			break;
335 #endif /* INET6 */
336 		default:  /* Other protocols doesn't support Multicast */
337 			error = EAFNOSUPPORT;
338 			break;
339 		}
340 		break;
341 
342 	case SIOCSIFPHYADDR:
343 #ifdef INET6
344 	case SIOCSIFPHYADDR_IN6:
345 #endif /* INET6 */
346 	case SIOCSLIFPHYADDR:
347 		switch (cmd) {
348 #ifdef INET
349 		case SIOCSIFPHYADDR:
350 			src = (struct sockaddr *)
351 				&(((struct in_aliasreq *)data)->ifra_addr);
352 			dst = (struct sockaddr *)
353 				&(((struct in_aliasreq *)data)->ifra_dstaddr);
354 			break;
355 #endif
356 #ifdef INET6
357 		case SIOCSIFPHYADDR_IN6:
358 			src = (struct sockaddr *)
359 				&(((struct in6_aliasreq *)data)->ifra_addr);
360 			dst = (struct sockaddr *)
361 				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
362 			break;
363 #endif
364 		case SIOCSLIFPHYADDR:
365 			src = (struct sockaddr *)
366 				&(((struct if_laddrreq *)data)->addr);
367 			dst = (struct sockaddr *)
368 				&(((struct if_laddrreq *)data)->dstaddr);
369 			break;
370 		default:
371 			return (EINVAL);
372 		}
373 
374 		/* sa_family must be equal */
375 		if (src->sa_family != dst->sa_family)
376 			return (EINVAL);
377 
378 		/* validate sa_len */
379 		switch (src->sa_family) {
380 #ifdef INET
381 		case AF_INET:
382 			if (src->sa_len != sizeof(struct sockaddr_in))
383 				return (EINVAL);
384 			break;
385 #endif
386 #ifdef INET6
387 		case AF_INET6:
388 			if (src->sa_len != sizeof(struct sockaddr_in6))
389 				return (EINVAL);
390 			break;
391 #endif
392 		default:
393 			return (EAFNOSUPPORT);
394 		}
395 		switch (dst->sa_family) {
396 #ifdef INET
397 		case AF_INET:
398 			if (dst->sa_len != sizeof(struct sockaddr_in))
399 				return (EINVAL);
400 			break;
401 #endif
402 #ifdef INET6
403 		case AF_INET6:
404 			if (dst->sa_len != sizeof(struct sockaddr_in6))
405 				return (EINVAL);
406 			break;
407 #endif
408 		default:
409 			return (EAFNOSUPPORT);
410 		}
411 
412 		/* check sa_family looks sane for the cmd */
413 		switch (cmd) {
414 		case SIOCSIFPHYADDR:
415 			if (src->sa_family == AF_INET)
416 				break;
417 			return (EAFNOSUPPORT);
418 #ifdef INET6
419 		case SIOCSIFPHYADDR_IN6:
420 			if (src->sa_family == AF_INET6)
421 				break;
422 			return (EAFNOSUPPORT);
423 #endif /* INET6 */
424 		case SIOCSLIFPHYADDR:
425 			/* checks done in the above */
426 			break;
427 		}
428 
429 		LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
430 			if (sc2 == sc)
431 				continue;
432 			if (!sc2->gif_pdst || !sc2->gif_psrc)
433 				continue;
434 			if (sc2->gif_pdst->sa_family != dst->sa_family ||
435 			    sc2->gif_pdst->sa_len != dst->sa_len ||
436 			    sc2->gif_psrc->sa_family != src->sa_family ||
437 			    sc2->gif_psrc->sa_len != src->sa_len)
438 				continue;
439 			/* can't configure same pair of address onto two gifs */
440 			if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
441 			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
442 				error = EADDRNOTAVAIL;
443 				goto bad;
444 			}
445 
446 			/* can't configure multiple multi-dest interfaces */
447 #define multidest(x) \
448 	(((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
449 #ifdef INET6
450 #define multidest6(x) \
451 	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
452 #endif
453 			if (dst->sa_family == AF_INET &&
454 			    multidest(dst) && multidest(sc2->gif_pdst)) {
455 				error = EADDRNOTAVAIL;
456 				goto bad;
457 			}
458 #ifdef INET6
459 			if (dst->sa_family == AF_INET6 &&
460 			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
461 				error = EADDRNOTAVAIL;
462 				goto bad;
463 			}
464 #endif
465 		}
466 
467 		if (sc->gif_psrc)
468 			free((caddr_t)sc->gif_psrc, M_IFADDR);
469 		sa = malloc(src->sa_len, M_IFADDR, M_WAITOK);
470 		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
471 		sc->gif_psrc = sa;
472 
473 		if (sc->gif_pdst)
474 			free((caddr_t)sc->gif_pdst, M_IFADDR);
475 		sa = malloc(dst->sa_len, M_IFADDR, M_WAITOK);
476 		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
477 		sc->gif_pdst = sa;
478 
479 		s = splnet();
480 		ifp->if_flags |= IFF_RUNNING;
481 		if_up(ifp);		/* send up RTM_IFINFO */
482 		splx(s);
483 
484 		error = 0;
485 		break;
486 
487 #ifdef SIOCDIFPHYADDR
488 	case SIOCDIFPHYADDR:
489 		if (sc->gif_psrc) {
490 			free((caddr_t)sc->gif_psrc, M_IFADDR);
491 			sc->gif_psrc = NULL;
492 		}
493 		if (sc->gif_pdst) {
494 			free((caddr_t)sc->gif_pdst, M_IFADDR);
495 			sc->gif_pdst = NULL;
496 		}
497 		/* change the IFF_{UP, RUNNING} flag as well? */
498 		break;
499 #endif
500 
501 	case SIOCGIFPSRCADDR:
502 #ifdef INET6
503 	case SIOCGIFPSRCADDR_IN6:
504 #endif /* INET6 */
505 		if (sc->gif_psrc == NULL) {
506 			error = EADDRNOTAVAIL;
507 			goto bad;
508 		}
509 		src = sc->gif_psrc;
510 		switch (cmd) {
511 #ifdef INET
512 		case SIOCGIFPSRCADDR:
513 			dst = &ifr->ifr_addr;
514 			size = sizeof(ifr->ifr_addr);
515 			break;
516 #endif /* INET */
517 #ifdef INET6
518 		case SIOCGIFPSRCADDR_IN6:
519 			dst = (struct sockaddr *)
520 				&(((struct in6_ifreq *)data)->ifr_addr);
521 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
522 			break;
523 #endif /* INET6 */
524 		default:
525 			error = EADDRNOTAVAIL;
526 			goto bad;
527 		}
528 		if (src->sa_len > size)
529 			return (EINVAL);
530 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
531 		break;
532 
533 	case SIOCGIFPDSTADDR:
534 #ifdef INET6
535 	case SIOCGIFPDSTADDR_IN6:
536 #endif /* INET6 */
537 		if (sc->gif_pdst == NULL) {
538 			error = EADDRNOTAVAIL;
539 			goto bad;
540 		}
541 		src = sc->gif_pdst;
542 		switch (cmd) {
543 #ifdef INET
544 		case SIOCGIFPDSTADDR:
545 			dst = &ifr->ifr_addr;
546 			size = sizeof(ifr->ifr_addr);
547 			break;
548 #endif /* INET */
549 #ifdef INET6
550 		case SIOCGIFPDSTADDR_IN6:
551 			dst = (struct sockaddr *)
552 				&(((struct in6_ifreq *)data)->ifr_addr);
553 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
554 			break;
555 #endif /* INET6 */
556 		default:
557 			error = EADDRNOTAVAIL;
558 			goto bad;
559 		}
560 		if (src->sa_len > size)
561 			return (EINVAL);
562 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
563 		break;
564 
565 	case SIOCGLIFPHYADDR:
566 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
567 			error = EADDRNOTAVAIL;
568 			goto bad;
569 		}
570 
571 		/* copy src */
572 		src = sc->gif_psrc;
573 		dst = (struct sockaddr *)
574 			&(((struct if_laddrreq *)data)->addr);
575 		size = sizeof(((struct if_laddrreq *)data)->addr);
576 		if (src->sa_len > size)
577 			return (EINVAL);
578 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
579 
580 		/* copy dst */
581 		src = sc->gif_pdst;
582 		dst = (struct sockaddr *)
583 			&(((struct if_laddrreq *)data)->dstaddr);
584 		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
585 		if (src->sa_len > size)
586 			return (EINVAL);
587 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
588 		break;
589 
590 	case SIOCSIFFLAGS:
591 		/* if_ioctl() takes care of it */
592 		break;
593 
594 	case SIOCSIFMTU:
595 		if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
596 			error = EINVAL;
597 		else
598 			ifp->if_mtu = ifr->ifr_mtu;
599 		break;
600 
601 	default:
602 		error = ENOTTY;
603 		break;
604 	}
605  bad:
606 	return (error);
607 }
608