gre.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       gre.c (5099B)
       ---
            1 /*
            2  * Generic Routing Encapsulation over IPv4, rfc1702
            3  */
            4 #include "u.h"
            5 #include "lib.h"
            6 #include "mem.h"
            7 #include "dat.h"
            8 #include "fns.h"
            9 #include "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 }