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