source: rtems-libbsd/freebsd/sys/net/if_gre.c @ e599318

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since e599318 was e599318, checked in by Sebastian Huber <sebastian.huber@…>, on 10/09/13 at 20:52:54

Update files to match FreeBSD layout

Add compatibility with Newlib header files. Some FreeBSD header files
are mapped by the translation script:

o rtems/bsd/sys/_types.h
o rtems/bsd/sys/errno.h
o rtems/bsd/sys/lock.h
o rtems/bsd/sys/param.h
o rtems/bsd/sys/resource.h
o rtems/bsd/sys/time.h
o rtems/bsd/sys/timespec.h
o rtems/bsd/sys/types.h
o rtems/bsd/sys/unistd.h

It is now possible to include <sys/socket.h> directly for example.

Generate one Makefile which builds everything including tests.

  • Property mode set to 100644
File size: 22.7 KB
Line 
1#include <machine/rtems-bsd-config.h>
2
3/*      $NetBSD: if_gre.c,v 1.49 2003/12/11 00:22:29 itojun Exp $ */
4/*       $FreeBSD$ */
5
6/*-
7 * Copyright (c) 1998 The NetBSD Foundation, Inc.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Heiko W.Rupp <hwr@pilhuhn.de>
12 *
13 * IPv6-over-GRE contributed by Gert Doering <gert@greenie.muc.de>
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 * 3. All advertising materials mentioning features or use of this software
24 *    must display the following acknowledgement:
25 *        This product includes software developed by the NetBSD
26 *        Foundation, Inc. and its contributors.
27 * 4. Neither the name of The NetBSD Foundation nor the names of its
28 *    contributors may be used to endorse or promote products derived
29 *    from this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
32 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
35 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGE.
42 */
43
44/*
45 * Encapsulate L3 protocols into IP
46 * See RFC 2784 (successor of RFC 1701 and 1702) for more details.
47 * If_gre is compatible with Cisco GRE tunnels, so you can
48 * have a NetBSD box as the other end of a tunnel interface of a Cisco
49 * router. See gre(4) for more details.
50 * Also supported:  IP in IP encaps (proto 55) as of RFC 2004
51 */
52
53#include <rtems/bsd/local/opt_atalk.h>
54#include <rtems/bsd/local/opt_inet.h>
55#include <rtems/bsd/local/opt_inet6.h>
56
57#include <rtems/bsd/sys/param.h>
58#include <sys/kernel.h>
59#include <sys/malloc.h>
60#include <sys/module.h>
61#include <sys/mbuf.h>
62#include <sys/priv.h>
63#include <sys/proc.h>
64#include <sys/protosw.h>
65#include <sys/socket.h>
66#include <sys/sockio.h>
67#include <sys/sysctl.h>
68#include <sys/systm.h>
69
70#include <net/ethernet.h>
71#include <net/if.h>
72#include <net/if_clone.h>
73#include <net/if_types.h>
74#include <net/route.h>
75#include <net/vnet.h>
76
77#ifdef INET
78#include <netinet/in.h>
79#include <netinet/in_systm.h>
80#include <netinet/in_var.h>
81#include <netinet/ip.h>
82#include <netinet/ip_gre.h>
83#include <netinet/ip_var.h>
84#include <netinet/ip_encap.h>
85#else
86#error "Huh? if_gre without inet?"
87#endif
88
89#include <net/bpf.h>
90
91#include <net/if_gre.h>
92
93/*
94 * It is not easy to calculate the right value for a GRE MTU.
95 * We leave this task to the admin and use the same default that
96 * other vendors use.
97 */
98#define GREMTU  1476
99
100#define GRENAME "gre"
101
102/*
103 * gre_mtx protects all global variables in if_gre.c.
104 * XXX: gre_softc data not protected yet.
105 */
106struct mtx gre_mtx;
107static MALLOC_DEFINE(M_GRE, GRENAME, "Generic Routing Encapsulation");
108
109struct gre_softc_head gre_softc_list;
110
111static int      gre_clone_create(struct if_clone *, int, caddr_t);
112static void     gre_clone_destroy(struct ifnet *);
113static int      gre_ioctl(struct ifnet *, u_long, caddr_t);
114static int      gre_output(struct ifnet *, struct mbuf *, struct sockaddr *,
115                    struct route *ro);
116
117IFC_SIMPLE_DECLARE(gre, 0);
118
119static int gre_compute_route(struct gre_softc *sc);
120
121static void     greattach(void);
122
123#ifdef INET
124extern struct domain inetdomain;
125static const struct protosw in_gre_protosw = {
126        .pr_type =              SOCK_RAW,
127        .pr_domain =            &inetdomain,
128        .pr_protocol =          IPPROTO_GRE,
129        .pr_flags =             PR_ATOMIC|PR_ADDR,
130        .pr_input =             gre_input,
131        .pr_output =            (pr_output_t *)rip_output,
132        .pr_ctlinput =          rip_ctlinput,
133        .pr_ctloutput =         rip_ctloutput,
134        .pr_usrreqs =           &rip_usrreqs
135};
136static const struct protosw in_mobile_protosw = {
137        .pr_type =              SOCK_RAW,
138        .pr_domain =            &inetdomain,
139        .pr_protocol =          IPPROTO_MOBILE,
140        .pr_flags =             PR_ATOMIC|PR_ADDR,
141        .pr_input =             gre_mobile_input,
142        .pr_output =            (pr_output_t *)rip_output,
143        .pr_ctlinput =          rip_ctlinput,
144        .pr_ctloutput =         rip_ctloutput,
145        .pr_usrreqs =           &rip_usrreqs
146};
147#endif
148
149SYSCTL_DECL(_net_link);
150SYSCTL_NODE(_net_link, IFT_TUNNEL, gre, CTLFLAG_RW, 0,
151    "Generic Routing Encapsulation");
152#ifndef MAX_GRE_NEST
153/*
154 * This macro controls the default upper limitation on nesting of gre tunnels.
155 * Since, setting a large value to this macro with a careless configuration
156 * may introduce system crash, we don't allow any nestings by default.
157 * If you need to configure nested gre tunnels, you can define this macro
158 * in your kernel configuration file.  However, if you do so, please be
159 * careful to configure the tunnels so that it won't make a loop.
160 */
161#define MAX_GRE_NEST 1
162#endif
163static int max_gre_nesting = MAX_GRE_NEST;
164SYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW,
165    &max_gre_nesting, 0, "Max nested tunnels");
166
167/* ARGSUSED */
168static void
169greattach(void)
170{
171
172        mtx_init(&gre_mtx, "gre_mtx", NULL, MTX_DEF);
173        LIST_INIT(&gre_softc_list);
174        if_clone_attach(&gre_cloner);
175}
176
177static int
178gre_clone_create(ifc, unit, params)
179        struct if_clone *ifc;
180        int unit;
181        caddr_t params;
182{
183        struct gre_softc *sc;
184
185        sc = malloc(sizeof(struct gre_softc), M_GRE, M_WAITOK | M_ZERO);
186
187        GRE2IFP(sc) = if_alloc(IFT_TUNNEL);
188        if (GRE2IFP(sc) == NULL) {
189                free(sc, M_GRE);
190                return (ENOSPC);
191        }
192
193        GRE2IFP(sc)->if_softc = sc;
194        if_initname(GRE2IFP(sc), ifc->ifc_name, unit);
195
196        GRE2IFP(sc)->if_snd.ifq_maxlen = ifqmaxlen;
197        GRE2IFP(sc)->if_addrlen = 0;
198        GRE2IFP(sc)->if_hdrlen = 24; /* IP + GRE */
199        GRE2IFP(sc)->if_mtu = GREMTU;
200        GRE2IFP(sc)->if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
201        GRE2IFP(sc)->if_output = gre_output;
202        GRE2IFP(sc)->if_ioctl = gre_ioctl;
203        sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
204        sc->g_proto = IPPROTO_GRE;
205        GRE2IFP(sc)->if_flags |= IFF_LINK0;
206        sc->encap = NULL;
207        sc->called = 0;
208        sc->gre_fibnum = curthread->td_proc->p_fibnum;
209        sc->wccp_ver = WCCP_V1;
210        sc->key = 0;
211        if_attach(GRE2IFP(sc));
212        bpfattach(GRE2IFP(sc), DLT_NULL, sizeof(u_int32_t));
213        mtx_lock(&gre_mtx);
214        LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
215        mtx_unlock(&gre_mtx);
216        return (0);
217}
218
219static void
220gre_clone_destroy(ifp)
221        struct ifnet *ifp;
222{
223        struct gre_softc *sc = ifp->if_softc;
224
225        mtx_lock(&gre_mtx);
226        LIST_REMOVE(sc, sc_list);
227        mtx_unlock(&gre_mtx);
228
229#ifdef INET
230        if (sc->encap != NULL)
231                encap_detach(sc->encap);
232#endif
233        bpfdetach(ifp);
234        if_detach(ifp);
235        if_free(ifp);
236        free(sc, M_GRE);
237}
238
239/*
240 * The output routine. Takes a packet and encapsulates it in the protocol
241 * given by sc->g_proto. See also RFC 1701 and RFC 2004
242 */
243static int
244gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
245           struct route *ro)
246{
247        int error = 0;
248        struct gre_softc *sc = ifp->if_softc;
249        struct greip *gh;
250        struct ip *ip;
251        u_short gre_ip_id = 0;
252        uint8_t gre_ip_tos = 0;
253        u_int16_t etype = 0;
254        struct mobile_h mob_h;
255        u_int32_t af;
256        int extra = 0;
257
258        /*
259         * gre may cause infinite recursion calls when misconfigured.
260         * We'll prevent this by introducing upper limit.
261         */
262        if (++(sc->called) > max_gre_nesting) {
263                printf("%s: gre_output: recursively called too many "
264                       "times(%d)\n", if_name(GRE2IFP(sc)), sc->called);
265                m_freem(m);
266                error = EIO;    /* is there better errno? */
267                goto end;
268        }
269
270        if (!((ifp->if_flags & IFF_UP) &&
271            (ifp->if_drv_flags & IFF_DRV_RUNNING)) ||
272            sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
273                m_freem(m);
274                error = ENETDOWN;
275                goto end;
276        }
277
278        gh = NULL;
279        ip = NULL;
280
281        /* BPF writes need to be handled specially. */
282        if (dst->sa_family == AF_UNSPEC) {
283                bcopy(dst->sa_data, &af, sizeof(af));
284                dst->sa_family = af;
285        }
286
287        if (bpf_peers_present(ifp->if_bpf)) {
288                af = dst->sa_family;
289                bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
290        }
291
292        m->m_flags &= ~(M_BCAST|M_MCAST);
293
294        if (sc->g_proto == IPPROTO_MOBILE) {
295                if (dst->sa_family == AF_INET) {
296                        struct mbuf *m0;
297                        int msiz;
298
299                        ip = mtod(m, struct ip *);
300
301                        /*
302                         * RFC2004 specifies that fragmented diagrams shouldn't
303                         * be encapsulated.
304                         */
305                        if (ip->ip_off & (IP_MF | IP_OFFMASK)) {
306                                _IF_DROP(&ifp->if_snd);
307                                m_freem(m);
308                                error = EINVAL;    /* is there better errno? */
309                                goto end;
310                        }
311                        memset(&mob_h, 0, MOB_HH_SIZ_L);
312                        mob_h.proto = (ip->ip_p) << 8;
313                        mob_h.odst = ip->ip_dst.s_addr;
314                        ip->ip_dst.s_addr = sc->g_dst.s_addr;
315
316                        /*
317                         * If the packet comes from our host, we only change
318                         * the destination address in the IP header.
319                         * Else we also need to save and change the source
320                         */
321                        if (in_hosteq(ip->ip_src, sc->g_src)) {
322                                msiz = MOB_HH_SIZ_S;
323                        } else {
324                                mob_h.proto |= MOB_HH_SBIT;
325                                mob_h.osrc = ip->ip_src.s_addr;
326                                ip->ip_src.s_addr = sc->g_src.s_addr;
327                                msiz = MOB_HH_SIZ_L;
328                        }
329                        mob_h.proto = htons(mob_h.proto);
330                        mob_h.hcrc = gre_in_cksum((u_int16_t *)&mob_h, msiz);
331
332                        if ((m->m_data - msiz) < m->m_pktdat) {
333                                /* need new mbuf */
334                                MGETHDR(m0, M_DONTWAIT, MT_DATA);
335                                if (m0 == NULL) {
336                                        _IF_DROP(&ifp->if_snd);
337                                        m_freem(m);
338                                        error = ENOBUFS;
339                                        goto end;
340                                }
341                                m0->m_next = m;
342                                m->m_data += sizeof(struct ip);
343                                m->m_len -= sizeof(struct ip);
344                                m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
345                                m0->m_len = msiz + sizeof(struct ip);
346                                m0->m_data += max_linkhdr;
347                                memcpy(mtod(m0, caddr_t), (caddr_t)ip,
348                                       sizeof(struct ip));
349                                m = m0;
350                        } else {  /* we have some space left in the old one */
351                                m->m_data -= msiz;
352                                m->m_len += msiz;
353                                m->m_pkthdr.len += msiz;
354                                bcopy(ip, mtod(m, caddr_t),
355                                        sizeof(struct ip));
356                        }
357                        ip = mtod(m, struct ip *);
358                        memcpy((caddr_t)(ip + 1), &mob_h, (unsigned)msiz);
359                        ip->ip_len = ntohs(ip->ip_len) + msiz;
360                } else {  /* AF_INET */
361                        _IF_DROP(&ifp->if_snd);
362                        m_freem(m);
363                        error = EINVAL;
364                        goto end;
365                }
366        } else if (sc->g_proto == IPPROTO_GRE) {
367                switch (dst->sa_family) {
368                case AF_INET:
369                        ip = mtod(m, struct ip *);
370                        gre_ip_tos = ip->ip_tos;
371                        gre_ip_id = ip->ip_id;
372                        if (sc->wccp_ver == WCCP_V2) {
373                                extra = sizeof(uint32_t);
374                                etype =  WCCP_PROTOCOL_TYPE;
375                        } else {
376                                etype = ETHERTYPE_IP;
377                        }
378                        break;
379#ifdef INET6
380                case AF_INET6:
381                        gre_ip_id = ip_newid();
382                        etype = ETHERTYPE_IPV6;
383                        break;
384#endif
385#ifdef NETATALK
386                case AF_APPLETALK:
387                        etype = ETHERTYPE_ATALK;
388                        break;
389#endif
390                default:
391                        _IF_DROP(&ifp->if_snd);
392                        m_freem(m);
393                        error = EAFNOSUPPORT;
394                        goto end;
395                }
396
397                /* Reserve space for GRE header + optional GRE key */
398                int hdrlen = sizeof(struct greip) + extra;
399                if (sc->key)
400                        hdrlen += sizeof(uint32_t);
401                M_PREPEND(m, hdrlen, M_DONTWAIT);
402        } else {
403                _IF_DROP(&ifp->if_snd);
404                m_freem(m);
405                error = EINVAL;
406                goto end;
407        }
408
409        if (m == NULL) {        /* mbuf allocation failed */
410                _IF_DROP(&ifp->if_snd);
411                error = ENOBUFS;
412                goto end;
413        }
414
415        M_SETFIB(m, sc->gre_fibnum); /* The envelope may use a different FIB */
416
417        gh = mtod(m, struct greip *);
418        if (sc->g_proto == IPPROTO_GRE) {
419                uint32_t *options = gh->gi_options;
420
421                memset((void *)gh, 0, sizeof(struct greip) + extra);
422                gh->gi_ptype = htons(etype);
423                gh->gi_flags = 0;
424
425                /* Add key option */
426                if (sc->key)
427                {
428                        gh->gi_flags |= htons(GRE_KP);
429                        *(options++) = htonl(sc->key);
430                }
431        }
432
433        gh->gi_pr = sc->g_proto;
434        if (sc->g_proto != IPPROTO_MOBILE) {
435                gh->gi_src = sc->g_src;
436                gh->gi_dst = sc->g_dst;
437                ((struct ip*)gh)->ip_v = IPPROTO_IPV4;
438                ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
439                ((struct ip*)gh)->ip_ttl = GRE_TTL;
440                ((struct ip*)gh)->ip_tos = gre_ip_tos;
441                ((struct ip*)gh)->ip_id = gre_ip_id;
442                gh->gi_len = m->m_pkthdr.len;
443        }
444
445        ifp->if_opackets++;
446        ifp->if_obytes += m->m_pkthdr.len;
447        /*
448         * Send it off and with IP_FORWARD flag to prevent it from
449         * overwriting the ip_id again.  ip_id is already set to the
450         * ip_id of the encapsulated packet.
451         */
452        error = ip_output(m, NULL, &sc->route, IP_FORWARDING,
453            (struct ip_moptions *)NULL, (struct inpcb *)NULL);
454  end:
455        sc->called = 0;
456        if (error)
457                ifp->if_oerrors++;
458        return (error);
459}
460
461static int
462gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
463{
464        struct ifreq *ifr = (struct ifreq *)data;
465        struct if_laddrreq *lifr = (struct if_laddrreq *)data;
466        struct in_aliasreq *aifr = (struct in_aliasreq *)data;
467        struct gre_softc *sc = ifp->if_softc;
468        int s;
469        struct sockaddr_in si;
470        struct sockaddr *sa = NULL;
471        int error, adj;
472        struct sockaddr_in sp, sm, dp, dm;
473        uint32_t key;
474
475        error = 0;
476        adj = 0;
477
478        s = splnet();
479        switch (cmd) {
480        case SIOCSIFADDR:
481                ifp->if_flags |= IFF_UP;
482                break;
483        case SIOCSIFDSTADDR:
484                break;
485        case SIOCSIFFLAGS:
486                /*
487                 * XXXRW: Isn't this priv_check() redundant to the ifnet
488                 * layer check?
489                 */
490                if ((error = priv_check(curthread, PRIV_NET_SETIFFLAGS)) != 0)
491                        break;
492                if ((ifr->ifr_flags & IFF_LINK0) != 0)
493                        sc->g_proto = IPPROTO_GRE;
494                else
495                        sc->g_proto = IPPROTO_MOBILE;
496                if ((ifr->ifr_flags & IFF_LINK2) != 0)
497                        sc->wccp_ver = WCCP_V2;
498                else
499                        sc->wccp_ver = WCCP_V1;
500                goto recompute;
501        case SIOCSIFMTU:
502                /*
503                 * XXXRW: Isn't this priv_check() redundant to the ifnet
504                 * layer check?
505                 */
506                if ((error = priv_check(curthread, PRIV_NET_SETIFMTU)) != 0)
507                        break;
508                if (ifr->ifr_mtu < 576) {
509                        error = EINVAL;
510                        break;
511                }
512                ifp->if_mtu = ifr->ifr_mtu;
513                break;
514        case SIOCGIFMTU:
515                ifr->ifr_mtu = GRE2IFP(sc)->if_mtu;
516                break;
517        case SIOCADDMULTI:
518                /*
519                 * XXXRW: Isn't this priv_checkr() redundant to the ifnet
520                 * layer check?
521                 */
522                if ((error = priv_check(curthread, PRIV_NET_ADDMULTI)) != 0)
523                        break;
524                if (ifr == 0) {
525                        error = EAFNOSUPPORT;
526                        break;
527                }
528                switch (ifr->ifr_addr.sa_family) {
529#ifdef INET
530                case AF_INET:
531                        break;
532#endif
533#ifdef INET6
534                case AF_INET6:
535                        break;
536#endif
537                default:
538                        error = EAFNOSUPPORT;
539                        break;
540                }
541                break;
542        case SIOCDELMULTI:
543                /*
544                 * XXXRW: Isn't this priv_check() redundant to the ifnet
545                 * layer check?
546                 */
547                if ((error = priv_check(curthread, PRIV_NET_DELIFGROUP)) != 0)
548                        break;
549                if (ifr == 0) {
550                        error = EAFNOSUPPORT;
551                        break;
552                }
553                switch (ifr->ifr_addr.sa_family) {
554#ifdef INET
555                case AF_INET:
556                        break;
557#endif
558#ifdef INET6
559                case AF_INET6:
560                        break;
561#endif
562                default:
563                        error = EAFNOSUPPORT;
564                        break;
565                }
566                break;
567        case GRESPROTO:
568                /*
569                 * XXXRW: Isn't this priv_check() redundant to the ifnet
570                 * layer check?
571                 */
572                if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0)
573                        break;
574                sc->g_proto = ifr->ifr_flags;
575                switch (sc->g_proto) {
576                case IPPROTO_GRE:
577                        ifp->if_flags |= IFF_LINK0;
578                        break;
579                case IPPROTO_MOBILE:
580                        ifp->if_flags &= ~IFF_LINK0;
581                        break;
582                default:
583                        error = EPROTONOSUPPORT;
584                        break;
585                }
586                goto recompute;
587        case GREGPROTO:
588                ifr->ifr_flags = sc->g_proto;
589                break;
590        case GRESADDRS:
591        case GRESADDRD:
592                error = priv_check(curthread, PRIV_NET_GRE);
593                if (error)
594                        return (error);
595                /*
596                 * set tunnel endpoints, compute a less specific route
597                 * to the remote end and mark if as up
598                 */
599                sa = &ifr->ifr_addr;
600                if (cmd == GRESADDRS)
601                        sc->g_src = (satosin(sa))->sin_addr;
602                if (cmd == GRESADDRD)
603                        sc->g_dst = (satosin(sa))->sin_addr;
604        recompute:
605#ifdef INET
606                if (sc->encap != NULL) {
607                        encap_detach(sc->encap);
608                        sc->encap = NULL;
609                }
610#endif
611                if ((sc->g_src.s_addr != INADDR_ANY) &&
612                    (sc->g_dst.s_addr != INADDR_ANY)) {
613                        bzero(&sp, sizeof(sp));
614                        bzero(&sm, sizeof(sm));
615                        bzero(&dp, sizeof(dp));
616                        bzero(&dm, sizeof(dm));
617                        sp.sin_len = sm.sin_len = dp.sin_len = dm.sin_len =
618                            sizeof(struct sockaddr_in);
619                        sp.sin_family = sm.sin_family = dp.sin_family =
620                            dm.sin_family = AF_INET;
621                        sp.sin_addr = sc->g_src;
622                        dp.sin_addr = sc->g_dst;
623                        sm.sin_addr.s_addr = dm.sin_addr.s_addr =
624                            INADDR_BROADCAST;
625#ifdef INET
626                        sc->encap = encap_attach(AF_INET, sc->g_proto,
627                            sintosa(&sp), sintosa(&sm), sintosa(&dp),
628                            sintosa(&dm), (sc->g_proto == IPPROTO_GRE) ?
629                                &in_gre_protosw : &in_mobile_protosw, sc);
630                        if (sc->encap == NULL)
631                                printf("%s: unable to attach encap\n",
632                                    if_name(GRE2IFP(sc)));
633#endif
634                        if (sc->route.ro_rt != 0) /* free old route */
635                                RTFREE(sc->route.ro_rt);
636                        if (gre_compute_route(sc) == 0)
637                                ifp->if_drv_flags |= IFF_DRV_RUNNING;
638                        else
639                                ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
640                }
641                break;
642        case GREGADDRS:
643                memset(&si, 0, sizeof(si));
644                si.sin_family = AF_INET;
645                si.sin_len = sizeof(struct sockaddr_in);
646                si.sin_addr.s_addr = sc->g_src.s_addr;
647                sa = sintosa(&si);
648                ifr->ifr_addr = *sa;
649                break;
650        case GREGADDRD:
651                memset(&si, 0, sizeof(si));
652                si.sin_family = AF_INET;
653                si.sin_len = sizeof(struct sockaddr_in);
654                si.sin_addr.s_addr = sc->g_dst.s_addr;
655                sa = sintosa(&si);
656                ifr->ifr_addr = *sa;
657                break;
658        case SIOCSIFPHYADDR:
659                /*
660                 * XXXRW: Isn't this priv_check() redundant to the ifnet
661                 * layer check?
662                 */
663                if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0)
664                        break;
665                if (aifr->ifra_addr.sin_family != AF_INET ||
666                    aifr->ifra_dstaddr.sin_family != AF_INET) {
667                        error = EAFNOSUPPORT;
668                        break;
669                }
670                if (aifr->ifra_addr.sin_len != sizeof(si) ||
671                    aifr->ifra_dstaddr.sin_len != sizeof(si)) {
672                        error = EINVAL;
673                        break;
674                }
675                sc->g_src = aifr->ifra_addr.sin_addr;
676                sc->g_dst = aifr->ifra_dstaddr.sin_addr;
677                goto recompute;
678        case SIOCSLIFPHYADDR:
679                /*
680                 * XXXRW: Isn't this priv_check() redundant to the ifnet
681                 * layer check?
682                 */
683                if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0)
684                        break;
685                if (lifr->addr.ss_family != AF_INET ||
686                    lifr->dstaddr.ss_family != AF_INET) {
687                        error = EAFNOSUPPORT;
688                        break;
689                }
690                if (lifr->addr.ss_len != sizeof(si) ||
691                    lifr->dstaddr.ss_len != sizeof(si)) {
692                        error = EINVAL;
693                        break;
694                }
695                sc->g_src = (satosin(&lifr->addr))->sin_addr;
696                sc->g_dst =
697                    (satosin(&lifr->dstaddr))->sin_addr;
698                goto recompute;
699        case SIOCDIFPHYADDR:
700                /*
701                 * XXXRW: Isn't this priv_check() redundant to the ifnet
702                 * layer check?
703                 */
704                if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0)
705                        break;
706                sc->g_src.s_addr = INADDR_ANY;
707                sc->g_dst.s_addr = INADDR_ANY;
708                goto recompute;
709        case SIOCGLIFPHYADDR:
710                if (sc->g_src.s_addr == INADDR_ANY ||
711                    sc->g_dst.s_addr == INADDR_ANY) {
712                        error = EADDRNOTAVAIL;
713                        break;
714                }
715                memset(&si, 0, sizeof(si));
716                si.sin_family = AF_INET;
717                si.sin_len = sizeof(struct sockaddr_in);
718                si.sin_addr.s_addr = sc->g_src.s_addr;
719                memcpy(&lifr->addr, &si, sizeof(si));
720                si.sin_addr.s_addr = sc->g_dst.s_addr;
721                memcpy(&lifr->dstaddr, &si, sizeof(si));
722                break;
723        case SIOCGIFPSRCADDR:
724#ifdef INET6
725        case SIOCGIFPSRCADDR_IN6:
726#endif
727                if (sc->g_src.s_addr == INADDR_ANY) {
728                        error = EADDRNOTAVAIL;
729                        break;
730                }
731                memset(&si, 0, sizeof(si));
732                si.sin_family = AF_INET;
733                si.sin_len = sizeof(struct sockaddr_in);
734                si.sin_addr.s_addr = sc->g_src.s_addr;
735                bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
736                break;
737        case SIOCGIFPDSTADDR:
738#ifdef INET6
739        case SIOCGIFPDSTADDR_IN6:
740#endif
741                if (sc->g_dst.s_addr == INADDR_ANY) {
742                        error = EADDRNOTAVAIL;
743                        break;
744                }
745                memset(&si, 0, sizeof(si));
746                si.sin_family = AF_INET;
747                si.sin_len = sizeof(struct sockaddr_in);
748                si.sin_addr.s_addr = sc->g_dst.s_addr;
749                bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
750                break;
751        case GRESKEY:
752                error = priv_check(curthread, PRIV_NET_GRE);
753                if (error)
754                        break;
755                error = copyin(ifr->ifr_data, &key, sizeof(key));
756                if (error)
757                        break;
758                /* adjust MTU for option header */
759                if (key == 0 && sc->key != 0)           /* clear */
760                        adj += sizeof(key);
761                else if (key != 0 && sc->key == 0)      /* set */
762                        adj -= sizeof(key);
763
764                if (ifp->if_mtu + adj < 576) {
765                        error = EINVAL;
766                        break;
767                }
768                ifp->if_mtu += adj;
769                sc->key = key;
770                break;
771        case GREGKEY:
772                error = copyout(&sc->key, ifr->ifr_data, sizeof(sc->key));
773                break;
774
775        default:
776                error = EINVAL;
777                break;
778        }
779
780        splx(s);
781        return (error);
782}
783
784/*
785 * computes a route to our destination that is not the one
786 * which would be taken by ip_output(), as this one will loop back to
787 * us. If the interface is p2p as  a--->b, then a routing entry exists
788 * If we now send a packet to b (e.g. ping b), this will come down here
789 * gets src=a, dst=b tacked on and would from ip_output() sent back to
790 * if_gre.
791 * Goal here is to compute a route to b that is less specific than
792 * a-->b. We know that this one exists as in normal operation we have
793 * at least a default route which matches.
794 */
795static int
796gre_compute_route(struct gre_softc *sc)
797{
798        struct route *ro;
799
800        ro = &sc->route;
801
802        memset(ro, 0, sizeof(struct route));
803        ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
804        ro->ro_dst.sa_family = AF_INET;
805        ro->ro_dst.sa_len = sizeof(ro->ro_dst);
806
807        /*
808         * toggle last bit, so our interface is not found, but a less
809         * specific route. I'd rather like to specify a shorter mask,
810         * but this is not possible. Should work though. XXX
811         * XXX MRT Use a different FIB for the tunnel to solve this problem.
812         */
813        if ((GRE2IFP(sc)->if_flags & IFF_LINK1) == 0) {
814                ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr ^=
815                    htonl(0x01);
816        }
817
818#ifdef DIAGNOSTIC
819        printf("%s: searching for a route to %s", if_name(GRE2IFP(sc)),
820            inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr));
821#endif
822
823        rtalloc_fib(ro, sc->gre_fibnum);
824
825        /*
826         * check if this returned a route at all and this route is no
827         * recursion to ourself
828         */
829        if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp->if_softc == sc) {
830#ifdef DIAGNOSTIC
831                if (ro->ro_rt == NULL)
832                        printf(" - no route found!\n");
833                else
834                        printf(" - route loops back to ourself!\n");
835#endif
836                return EADDRNOTAVAIL;
837        }
838
839        /*
840         * now change it back - else ip_output will just drop
841         * the route and search one to this interface ...
842         */
843        if ((GRE2IFP(sc)->if_flags & IFF_LINK1) == 0)
844                ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
845
846#ifdef DIAGNOSTIC
847        printf(", choosing %s with gateway %s", if_name(ro->ro_rt->rt_ifp),
848            inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr));
849        printf("\n");
850#endif
851
852        return 0;
853}
854
855/*
856 * do a checksum of a buffer - much like in_cksum, which operates on
857 * mbufs.
858 */
859u_int16_t
860gre_in_cksum(u_int16_t *p, u_int len)
861{
862        u_int32_t sum = 0;
863        int nwords = len >> 1;
864
865        while (nwords-- != 0)
866                sum += *p++;
867
868        if (len & 1) {
869                union {
870                        u_short w;
871                        u_char c[2];
872                } u;
873                u.c[0] = *(u_char *)p;
874                u.c[1] = 0;
875                sum += u.w;
876        }
877
878        /* end-around-carry */
879        sum = (sum >> 16) + (sum & 0xffff);
880        sum += (sum >> 16);
881        return (~sum);
882}
883
884static int
885gremodevent(module_t mod, int type, void *data)
886{
887
888        switch (type) {
889        case MOD_LOAD:
890                greattach();
891                break;
892        case MOD_UNLOAD:
893                if_clone_detach(&gre_cloner);
894                mtx_destroy(&gre_mtx);
895                break;
896        default:
897                return EOPNOTSUPP;
898        }
899        return 0;
900}
901
902static moduledata_t gre_mod = {
903        "if_gre",
904        gremodevent,
905        0
906};
907
908DECLARE_MODULE(if_gre, gre_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
909MODULE_VERSION(if_gre, 1);
Note: See TracBrowser for help on using the repository browser.