The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ip/gre.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Generic Routing Encapsulation over IPv4, rfc1702
    3  */
    4 #include "u.h"
    5 #include "../port/lib.h"
    6 #include "mem.h"
    7 #include "dat.h"
    8 #include "fns.h"
    9 #include "../port/error.h"
   10 
   11 #include "ip.h"
   12 
   13 enum
   14 {
   15         GRE_IPONLY      = 12,           /* size of ip header */
   16         GRE_IPPLUSGRE   = 12,           /* minimum size of GRE header */
   17         IP_GREPROTO     = 47,
   18 
   19         GRErxms         = 200,
   20         GREtickms       = 100,
   21         GREmaxxmit      = 10,
   22 };
   23 
   24 typedef struct GREhdr
   25 {
   26         /* ip header */
   27         uchar   vihl;           /* Version and header length */
   28         uchar   tos;            /* Type of service */
   29         uchar   len[2];         /* packet length (including headers) */
   30         uchar   id[2];          /* Identification */
   31         uchar   frag[2];        /* Fragment information */
   32         uchar   Unused; 
   33         uchar   proto;          /* Protocol */
   34         uchar   cksum[2];       /* checksum */
   35         uchar   src[4];         /* Ip source */
   36         uchar   dst[4];         /* Ip destination */
   37 
   38         /* gre header */
   39         uchar   flags[2];
   40         uchar   eproto[2];      /* encapsulation protocol */
   41 } GREhdr;
   42 
   43 typedef struct GREpriv GREpriv;
   44 struct GREpriv
   45 {
   46         int             raw;                    /* Raw GRE mode */
   47 
   48         /* non-MIB stats */
   49         ulong           csumerr;                /* checksum errors */
   50         ulong           lenerr;                 /* short packet */
   51 };
   52 
   53 static void grekick(void *x, Block *bp);
   54 
   55 static char*
   56 greconnect(Conv *c, char **argv, int argc)
   57 {
   58         Proto *p;
   59         char *err;
   60         Conv *tc, **cp, **ecp;
   61 
   62         err = Fsstdconnect(c, argv, argc);
   63         if(err != nil)
   64                 return err;
   65 
   66         /* make sure noone's already connected to this other sys */
   67         p = c->p;
   68         qlock(p);
   69         ecp = &p->conv[p->nc];
   70         for(cp = p->conv; cp < ecp; cp++){
   71                 tc = *cp;
   72                 if(tc == nil)
   73                         break;
   74                 if(tc == c)
   75                         continue;
   76                 if(tc->rport == c->rport && ipcmp(tc->raddr, c->raddr) == 0){
   77                         err = "already connected to that addr/proto";
   78                         ipmove(c->laddr, IPnoaddr);
   79                         ipmove(c->raddr, IPnoaddr);
   80                         break;
   81                 }
   82         }
   83         qunlock(p);
   84 
   85         if(err != nil)
   86                 return err;
   87         Fsconnected(c, nil);
   88 
   89         return nil;
   90 }
   91 
   92 static void
   93 grecreate(Conv *c)
   94 {
   95         c->rq = qopen(64*1024, Qmsg, 0, c);
   96         c->wq = qbypass(grekick, c);
   97 }
   98 
   99 static int
  100 grestate(Conv *c, char *state, int n)
  101 {
  102         USED(c);
  103         return snprint(state, n, "%s\n", "Datagram");
  104 }
  105 
  106 static char*
  107 greannounce(Conv*, char**, int)
  108 {
  109         return "pktifc does not support announce";
  110 }
  111 
  112 static void
  113 greclose(Conv *c)
  114 {
  115         qclose(c->rq);
  116         qclose(c->wq);
  117         qclose(c->eq);
  118         ipmove(c->laddr, IPnoaddr);
  119         ipmove(c->raddr, IPnoaddr);
  120         c->lport = 0;
  121         c->rport = 0;
  122 }
  123 
  124 int drop;
  125 
  126 static void
  127 grekick(void *x, Block *bp)
  128 {
  129         Conv *c = x;
  130         GREhdr *ghp;
  131         uchar laddr[IPaddrlen], raddr[IPaddrlen];
  132 
  133         if(bp == nil)
  134                 return;
  135 
  136         /* Make space to fit ip header (gre header already there) */
  137         bp = padblock(bp, GRE_IPONLY);
  138         if(bp == nil)
  139                 return;
  140 
  141         /* make sure the message has a GRE header */
  142         bp = pullupblock(bp, GRE_IPONLY+GRE_IPPLUSGRE);
  143         if(bp == nil)
  144                 return;
  145 
  146         ghp = (GREhdr *)(bp->rp);
  147         ghp->vihl = IP_VER4;
  148 
  149         if(!((GREpriv*)c->p->priv)->raw){
  150                 v4tov6(raddr, ghp->dst);
  151                 if(ipcmp(raddr, v4prefix) == 0)
  152                         memmove(ghp->dst, c->raddr + IPv4off, IPv4addrlen);
  153                 v4tov6(laddr, ghp->src);
  154                 if(ipcmp(laddr, v4prefix) == 0){
  155                         if(ipcmp(c->laddr, IPnoaddr) == 0)
  156                                 findlocalip(c->p->f, c->laddr, raddr); /* pick interface closest to dest */
  157                         memmove(ghp->src, c->laddr + IPv4off, IPv4addrlen);
  158                 }
  159                 hnputs(ghp->eproto, c->rport);
  160         }
  161 
  162         ghp->proto = IP_GREPROTO;
  163         ghp->frag[0] = 0;
  164         ghp->frag[1] = 0;
  165 
  166         ipoput4(c->p->f, bp, 0, c->ttl, c->tos, nil);
  167 }
  168 
  169 static void
  170 greiput(Proto *gre, Ipifc*, Block *bp)
  171 {
  172         int len;
  173         GREhdr *ghp;
  174         Conv *c, **p;
  175         ushort eproto;
  176         uchar raddr[IPaddrlen];
  177         GREpriv *gpriv;
  178 
  179         gpriv = gre->priv;
  180         ghp = (GREhdr*)(bp->rp);
  181 
  182         v4tov6(raddr, ghp->src);
  183         eproto = nhgets(ghp->eproto);
  184         qlock(gre);
  185 
  186         /* Look for a conversation structure for this port and address */
  187         c = nil;
  188         for(p = gre->conv; *p; p++) {
  189                 c = *p;
  190                 if(c->inuse == 0)
  191                         continue;
  192                 if(c->rport == eproto && 
  193                         (gpriv->raw || ipcmp(c->raddr, raddr) == 0))
  194                         break;
  195         }
  196 
  197         if(*p == nil) {
  198                 qunlock(gre);
  199                 freeblist(bp);
  200                 return;
  201         }
  202 
  203         qunlock(gre);
  204 
  205         /*
  206          * Trim the packet down to data size
  207          */
  208         len = nhgets(ghp->len) - GRE_IPONLY;
  209         if(len < GRE_IPPLUSGRE){
  210                 freeblist(bp);
  211                 return;
  212         }
  213         bp = trimblock(bp, GRE_IPONLY, len);
  214         if(bp == nil){
  215                 gpriv->lenerr++;
  216                 return;
  217         }
  218 
  219         /*
  220          *  Can't delimit packet so pull it all into one block.
  221          */
  222         if(qlen(c->rq) > 64*1024)
  223                 freeblist(bp);
  224         else{
  225                 bp = concatblock(bp);
  226                 if(bp == 0)
  227                         panic("greiput");
  228                 qpass(c->rq, bp);
  229         }
  230 }
  231 
  232 int
  233 grestats(Proto *gre, char *buf, int len)
  234 {
  235         GREpriv *gpriv;
  236 
  237         gpriv = gre->priv;
  238 
  239         return snprint(buf, len, "gre: len %lud\n", gpriv->lenerr);
  240 }
  241 
  242 char*
  243 grectl(Conv *c, char **f, int n)
  244 {
  245         GREpriv *gpriv;
  246 
  247         gpriv = c->p->priv;
  248         if(n == 1){
  249                 if(strcmp(f[0], "raw") == 0){
  250                         gpriv->raw = 1;
  251                         return nil;
  252                 }
  253                 else if(strcmp(f[0], "cooked") == 0){
  254                         gpriv->raw = 0;
  255                         return nil;
  256                 }
  257         }
  258         return "unknown control request";
  259 }
  260 
  261 void
  262 greinit(Fs *fs)
  263 {
  264         Proto *gre;
  265 
  266         gre = smalloc(sizeof(Proto));
  267         gre->priv = smalloc(sizeof(GREpriv));
  268         gre->name = "gre";
  269         gre->connect = greconnect;
  270         gre->announce = greannounce;
  271         gre->state = grestate;
  272         gre->create = grecreate;
  273         gre->close = greclose;
  274         gre->rcv = greiput;
  275         gre->ctl = grectl;
  276         gre->advise = nil;
  277         gre->stats = grestats;
  278         gre->ipproto = IP_GREPROTO;
  279         gre->nc = 64;
  280         gre->ptclsize = 0;
  281 
  282         Fsproto(fs, gre);
  283 }

Cache object: e05586c30c5f32182ca33dd34d28e6f2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.