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/udp.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 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "../port/error.h"
    7 
    8 #include        "ip.h"
    9 #include        "ipv6.h"
   10 
   11 
   12 #define DPRINT if(0)print
   13 
   14 enum
   15 {
   16         UDP_UDPHDR_SZ   = 8,
   17 
   18         UDP4_PHDR_OFF = 8,
   19         UDP4_PHDR_SZ = 12,
   20         UDP4_IPHDR_SZ = 20,
   21         UDP6_IPHDR_SZ = 40,
   22         UDP6_PHDR_SZ = 40,
   23         UDP6_PHDR_OFF = 0,
   24 
   25         IP_UDPPROTO     = 17,
   26         UDP_USEAD7      = 52,
   27 
   28         Udprxms         = 200,
   29         Udptickms       = 100,
   30         Udpmaxxmit      = 10,
   31 };
   32 
   33 typedef struct Udp4hdr Udp4hdr;
   34 struct Udp4hdr
   35 {
   36         /* ip header */
   37         uchar   vihl;           /* Version and header length */
   38         uchar   tos;            /* Type of service */
   39         uchar   length[2];      /* packet length */
   40         uchar   id[2];          /* Identification */
   41         uchar   frag[2];        /* Fragment information */
   42         uchar   Unused;
   43         uchar   udpproto;       /* Protocol */
   44         uchar   udpplen[2];     /* Header plus data length */
   45         uchar   udpsrc[IPv4addrlen];    /* Ip source */
   46         uchar   udpdst[IPv4addrlen];    /* Ip destination */
   47 
   48         /* udp header */
   49         uchar   udpsport[2];    /* Source port */
   50         uchar   udpdport[2];    /* Destination port */
   51         uchar   udplen[2];      /* data length */
   52         uchar   udpcksum[2];    /* Checksum */
   53 };
   54 
   55 typedef struct Udp6hdr Udp6hdr;
   56 struct Udp6hdr {
   57         uchar viclfl[4];
   58         uchar len[2];
   59         uchar nextheader;
   60         uchar hoplimit;
   61         uchar udpsrc[IPaddrlen];
   62         uchar udpdst[IPaddrlen];
   63 
   64         /* udp header */
   65         uchar   udpsport[2];    /* Source port */
   66         uchar   udpdport[2];    /* Destination port */
   67         uchar   udplen[2];      /* data length */
   68         uchar   udpcksum[2];    /* Checksum */
   69 };
   70 
   71 /* MIB II counters */
   72 typedef struct Udpstats Udpstats;
   73 struct Udpstats
   74 {
   75         ulong   udpInDatagrams;
   76         ulong   udpNoPorts;
   77         ulong   udpInErrors;
   78         ulong   udpOutDatagrams;
   79 };
   80 
   81 typedef struct Udppriv Udppriv;
   82 struct Udppriv
   83 {
   84         Ipht            ht;
   85 
   86         /* MIB counters */
   87         Udpstats        ustats;
   88 
   89         /* non-MIB stats */
   90         ulong           csumerr;                /* checksum errors */
   91         ulong           lenerr;                 /* short packet */
   92 };
   93 
   94 void (*etherprofiler)(char *name, int qlen);
   95 void udpkick(void *x, Block *bp);
   96 
   97 /*
   98  *  protocol specific part of Conv
   99  */
  100 typedef struct Udpcb Udpcb;
  101 struct Udpcb
  102 {
  103         QLock;
  104         uchar   headers;
  105 };
  106 
  107 static char*
  108 udpconnect(Conv *c, char **argv, int argc)
  109 {
  110         char *e;
  111         Udppriv *upriv;
  112 
  113         upriv = c->p->priv;
  114         e = Fsstdconnect(c, argv, argc);
  115         Fsconnected(c, e);
  116         if(e != nil)
  117                 return e;
  118 
  119         iphtadd(&upriv->ht, c);
  120         return nil;
  121 }
  122 
  123 
  124 static int
  125 udpstate(Conv *c, char *state, int n)
  126 {
  127         return snprint(state, n, "%s qin %d qout %d\n",
  128                 c->inuse ? "Open" : "Closed",
  129                 c->rq ? qlen(c->rq) : 0,
  130                 c->wq ? qlen(c->wq) : 0
  131         );
  132 }
  133 
  134 static char*
  135 udpannounce(Conv *c, char** argv, int argc)
  136 {
  137         char *e;
  138         Udppriv *upriv;
  139 
  140         upriv = c->p->priv;
  141         e = Fsstdannounce(c, argv, argc);
  142         if(e != nil)
  143                 return e;
  144         Fsconnected(c, nil);
  145         iphtadd(&upriv->ht, c);
  146 
  147         return nil;
  148 }
  149 
  150 static void
  151 udpcreate(Conv *c)
  152 {
  153         c->rq = qopen(128*1024, Qmsg, 0, 0);
  154         c->wq = qbypass(udpkick, c);
  155 }
  156 
  157 static void
  158 udpclose(Conv *c)
  159 {
  160         Udpcb *ucb;
  161         Udppriv *upriv;
  162 
  163         upriv = c->p->priv;
  164         iphtrem(&upriv->ht, c);
  165 
  166         c->state = 0;
  167         qclose(c->rq);
  168         qclose(c->wq);
  169         qclose(c->eq);
  170         ipmove(c->laddr, IPnoaddr);
  171         ipmove(c->raddr, IPnoaddr);
  172         c->lport = 0;
  173         c->rport = 0;
  174 
  175         ucb = (Udpcb*)c->ptcl;
  176         ucb->headers = 0;
  177 }
  178 
  179 void
  180 udpkick(void *x, Block *bp)
  181 {
  182         Conv *c = x;
  183         Udp4hdr *uh4;
  184         Udp6hdr *uh6;
  185         ushort rport;
  186         uchar laddr[IPaddrlen], raddr[IPaddrlen];
  187         Udpcb *ucb;
  188         int dlen, ptcllen;
  189         Udppriv *upriv;
  190         Fs *f;
  191         int version;
  192         Conv *rc;
  193 
  194         upriv = c->p->priv;
  195         f = c->p->f;
  196 
  197         netlog(c->p->f, Logudp, "udp: kick\n");
  198         if(bp == nil)
  199                 return;
  200 
  201         ucb = (Udpcb*)c->ptcl;
  202         switch(ucb->headers) {
  203         case 7:
  204                 /* get user specified addresses */
  205                 bp = pullupblock(bp, UDP_USEAD7);
  206                 if(bp == nil)
  207                         return;
  208                 ipmove(raddr, bp->rp);
  209                 bp->rp += IPaddrlen;
  210                 ipmove(laddr, bp->rp);
  211                 bp->rp += IPaddrlen;
  212                 /* pick interface closest to dest */
  213                 if(ipforme(f, laddr) != Runi)
  214                         findlocalip(f, laddr, raddr);
  215                 bp->rp += IPaddrlen;            /* Ignore ifc address */
  216                 rport = nhgets(bp->rp);
  217                 bp->rp += 2+2;                  /* Ignore local port */
  218                 break;
  219         default:
  220                 rport = 0;
  221                 break;
  222         }
  223 
  224         if(ucb->headers) {
  225                 if(memcmp(laddr, v4prefix, IPv4off) == 0
  226                 || ipcmp(laddr, IPnoaddr) == 0)
  227                         version = 4;
  228                 else
  229                         version = 6;
  230         } else {
  231                 if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
  232                         memcmp(c->laddr, v4prefix, IPv4off) == 0)
  233                         || ipcmp(c->raddr, IPnoaddr) == 0)
  234                         version = 4;
  235                 else
  236                         version = 6;
  237         }
  238 
  239         dlen = blocklen(bp);
  240 
  241         /* fill in pseudo header and compute checksum */
  242         switch(version){
  243         case V4:
  244                 bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ);
  245                 if(bp == nil)
  246                         return;
  247 
  248                 uh4 = (Udp4hdr *)(bp->rp);
  249                 ptcllen = dlen + UDP_UDPHDR_SZ;
  250                 uh4->Unused = 0;
  251                 uh4->udpproto = IP_UDPPROTO;
  252                 uh4->frag[0] = 0;
  253                 uh4->frag[1] = 0;
  254                 hnputs(uh4->udpplen, ptcllen);
  255                 if(ucb->headers) {
  256                         v6tov4(uh4->udpdst, raddr);
  257                         hnputs(uh4->udpdport, rport);
  258                         v6tov4(uh4->udpsrc, laddr);
  259                         rc = nil;
  260                 } else {
  261                         v6tov4(uh4->udpdst, c->raddr);
  262                         hnputs(uh4->udpdport, c->rport);
  263                         if(ipcmp(c->laddr, IPnoaddr) == 0)
  264                                 findlocalip(f, c->laddr, c->raddr);
  265                         v6tov4(uh4->udpsrc, c->laddr);
  266                         rc = c;
  267                 }
  268                 hnputs(uh4->udpsport, c->lport);
  269                 hnputs(uh4->udplen, ptcllen);
  270                 uh4->udpcksum[0] = 0;
  271                 uh4->udpcksum[1] = 0;
  272                 hnputs(uh4->udpcksum,
  273                        ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ));
  274                 uh4->vihl = IP_VER4;
  275                 ipoput4(f, bp, 0, c->ttl, c->tos, rc);
  276                 break;
  277 
  278         case V6:
  279                 bp = padblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ);
  280                 if(bp == nil)
  281                         return;
  282 
  283                 /*
  284                  * using the v6 ip header to create pseudo header
  285                  * first then reset it to the normal ip header
  286                  */
  287                 uh6 = (Udp6hdr *)(bp->rp);
  288                 memset(uh6, 0, 8);
  289                 ptcllen = dlen + UDP_UDPHDR_SZ;
  290                 hnputl(uh6->viclfl, ptcllen);
  291                 uh6->hoplimit = IP_UDPPROTO;
  292                 if(ucb->headers) {
  293                         ipmove(uh6->udpdst, raddr);
  294                         hnputs(uh6->udpdport, rport);
  295                         ipmove(uh6->udpsrc, laddr);
  296                         rc = nil;
  297                 } else {
  298                         ipmove(uh6->udpdst, c->raddr);
  299                         hnputs(uh6->udpdport, c->rport);
  300                         if(ipcmp(c->laddr, IPnoaddr) == 0)
  301                                 findlocalip(f, c->laddr, c->raddr);
  302                         ipmove(uh6->udpsrc, c->laddr);
  303                         rc = c;
  304                 }
  305                 hnputs(uh6->udpsport, c->lport);
  306                 hnputs(uh6->udplen, ptcllen);
  307                 uh6->udpcksum[0] = 0;
  308                 uh6->udpcksum[1] = 0;
  309                 hnputs(uh6->udpcksum,
  310                        ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ));
  311                 memset(uh6, 0, 8);
  312                 uh6->viclfl[0] = IP_VER6;
  313                 hnputs(uh6->len, ptcllen);
  314                 uh6->nextheader = IP_UDPPROTO;
  315                 ipoput6(f, bp, 0, c->ttl, c->tos, rc);
  316                 break;
  317 
  318         default:
  319                 panic("udpkick: version %d", version);
  320         }
  321         upriv->ustats.udpOutDatagrams++;
  322 }
  323 
  324 void
  325 udpiput(Proto *udp, Ipifc *ifc, Block *bp)
  326 {
  327         int len;
  328         Udp4hdr *uh4;
  329         Udp6hdr *uh6;
  330         Conv *c;
  331         Udpcb *ucb;
  332         uchar raddr[IPaddrlen], laddr[IPaddrlen];
  333         ushort rport, lport;
  334         Udppriv *upriv;
  335         Fs *f;
  336         int version;
  337         int ottl, oviclfl, olen;
  338         uchar *p;
  339 
  340         upriv = udp->priv;
  341         f = udp->f;
  342         upriv->ustats.udpInDatagrams++;
  343 
  344         uh4 = (Udp4hdr*)(bp->rp);
  345         version = ((uh4->vihl&0xF0)==IP_VER6) ? 6 : 4;
  346 
  347         /* Put back pseudo header for checksum
  348          * (remember old values for icmpnoconv()) */
  349         switch(version) {
  350         case V4:
  351                 ottl = uh4->Unused;
  352                 uh4->Unused = 0;
  353                 len = nhgets(uh4->udplen);
  354                 olen = nhgets(uh4->udpplen);
  355                 hnputs(uh4->udpplen, len);
  356 
  357                 v4tov6(raddr, uh4->udpsrc);
  358                 v4tov6(laddr, uh4->udpdst);
  359                 lport = nhgets(uh4->udpdport);
  360                 rport = nhgets(uh4->udpsport);
  361 
  362                 if(nhgets(uh4->udpcksum)) {
  363                         if(ptclcsum(bp, UDP4_PHDR_OFF, len+UDP4_PHDR_SZ)) {
  364                                 upriv->ustats.udpInErrors++;
  365                                 netlog(f, Logudp, "udp: checksum error %I\n", raddr);
  366                                 DPRINT("udp: checksum error %I\n", raddr);
  367                                 freeblist(bp);
  368                                 return;
  369                         }
  370                 }
  371                 uh4->Unused = ottl;
  372                 hnputs(uh4->udpplen, olen);
  373                 break;
  374         case V6:
  375                 uh6 = (Udp6hdr*)(bp->rp);
  376                 len = nhgets(uh6->udplen);
  377                 oviclfl = nhgetl(uh6->viclfl);
  378                 olen = nhgets(uh6->len);
  379                 ottl = uh6->hoplimit;
  380                 ipmove(raddr, uh6->udpsrc);
  381                 ipmove(laddr, uh6->udpdst);
  382                 lport = nhgets(uh6->udpdport);
  383                 rport = nhgets(uh6->udpsport);
  384                 memset(uh6, 0, 8);
  385                 hnputl(uh6->viclfl, len);
  386                 uh6->hoplimit = IP_UDPPROTO;
  387                 if(ptclcsum(bp, UDP6_PHDR_OFF, len+UDP6_PHDR_SZ)) {
  388                         upriv->ustats.udpInErrors++;
  389                         netlog(f, Logudp, "udp: checksum error %I\n", raddr);
  390                         DPRINT("udp: checksum error %I\n", raddr);
  391                         freeblist(bp);
  392                         return;
  393                 }
  394                 hnputl(uh6->viclfl, oviclfl);
  395                 hnputs(uh6->len, olen);
  396                 uh6->nextheader = IP_UDPPROTO;
  397                 uh6->hoplimit = ottl;
  398                 break;
  399         default:
  400                 panic("udpiput: version %d", version);
  401                 return; /* to avoid a warning */
  402         }
  403 
  404         qlock(udp);
  405 
  406         c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
  407         if(c == nil){
  408                 /* no conversation found */
  409                 upriv->ustats.udpNoPorts++;
  410                 qunlock(udp);
  411                 netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
  412                        laddr, lport);
  413 
  414                 switch(version){
  415                 case V4:
  416                         icmpnoconv(f, bp);
  417                         break;
  418                 case V6:
  419                         icmphostunr(f, ifc, bp, Icmp6_port_unreach, 0);
  420                         break;
  421                 default:
  422                         panic("udpiput2: version %d", version);
  423                 }
  424 
  425                 freeblist(bp);
  426                 return;
  427         }
  428         ucb = (Udpcb*)c->ptcl;
  429 
  430         if(c->state == Announced){
  431                 if(ucb->headers == 0){
  432                         /* create a new conversation */
  433                         if(ipforme(f, laddr) != Runi) {
  434                                 switch(version){
  435                                 case V4:
  436                                         v4tov6(laddr, ifc->lifc->local);
  437                                         break;
  438                                 case V6:
  439                                         ipmove(laddr, ifc->lifc->local);
  440                                         break;
  441                                 default:
  442                                         panic("udpiput3: version %d", version);
  443                                 }
  444                         }
  445                         c = Fsnewcall(c, raddr, rport, laddr, lport, version);
  446                         if(c == nil){
  447                                 qunlock(udp);
  448                                 freeblist(bp);
  449                                 return;
  450                         }
  451                         iphtadd(&upriv->ht, c);
  452                         ucb = (Udpcb*)c->ptcl;
  453                 }
  454         }
  455 
  456         qlock(c);
  457         qunlock(udp);
  458 
  459         /*
  460          * Trim the packet down to data size
  461          */
  462         len -= UDP_UDPHDR_SZ;
  463         switch(version){
  464         case V4:
  465                 bp = trimblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ, len);
  466                 break;
  467         case V6:
  468                 bp = trimblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ, len);
  469                 break;
  470         default:
  471                 bp = nil;
  472                 panic("udpiput4: version %d", version);
  473         }
  474         if(bp == nil){
  475                 qunlock(c);
  476                 netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
  477                        laddr, lport);
  478                 upriv->lenerr++;
  479                 return;
  480         }
  481 
  482         netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
  483                laddr, lport, len);
  484 
  485         switch(ucb->headers){
  486         case 7:
  487                 /* pass the src address */
  488                 bp = padblock(bp, UDP_USEAD7);
  489                 p = bp->rp;
  490                 ipmove(p, raddr); p += IPaddrlen;
  491                 ipmove(p, laddr); p += IPaddrlen;
  492                 ipmove(p, ifc->lifc->local); p += IPaddrlen;
  493                 hnputs(p, rport); p += 2;
  494                 hnputs(p, lport);
  495                 break;
  496         }
  497 
  498         if(bp->next)
  499                 bp = concatblock(bp);
  500 
  501         if(qfull(c->rq)){
  502                 qunlock(c);
  503                 netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
  504                        laddr, lport);
  505                 freeblist(bp);
  506                 return;
  507         }
  508 
  509         qpass(c->rq, bp);
  510         qunlock(c);
  511 
  512 }
  513 
  514 char*
  515 udpctl(Conv *c, char **f, int n)
  516 {
  517         Udpcb *ucb;
  518 
  519         ucb = (Udpcb*)c->ptcl;
  520         if(n == 1){
  521                 if(strcmp(f[0], "headers") == 0){
  522                         ucb->headers = 7;       /* new headers format */
  523                         return nil;
  524                 }
  525         }
  526         return "unknown control request";
  527 }
  528 
  529 void
  530 udpadvise(Proto *udp, Block *bp, char *msg)
  531 {
  532         Udp4hdr *h4;
  533         Udp6hdr *h6;
  534         uchar source[IPaddrlen], dest[IPaddrlen];
  535         ushort psource, pdest;
  536         Conv *s, **p;
  537         int version;
  538 
  539         h4 = (Udp4hdr*)(bp->rp);
  540         version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4;
  541 
  542         switch(version) {
  543         case V4:
  544                 v4tov6(dest, h4->udpdst);
  545                 v4tov6(source, h4->udpsrc);
  546                 psource = nhgets(h4->udpsport);
  547                 pdest = nhgets(h4->udpdport);
  548                 break;
  549         case V6:
  550                 h6 = (Udp6hdr*)(bp->rp);
  551                 ipmove(dest, h6->udpdst);
  552                 ipmove(source, h6->udpsrc);
  553                 psource = nhgets(h6->udpsport);
  554                 pdest = nhgets(h6->udpdport);
  555                 break;
  556         default:
  557                 panic("udpadvise: version %d", version);
  558                 return;  /* to avoid a warning */
  559         }
  560 
  561         /* Look for a connection */
  562         qlock(udp);
  563         for(p = udp->conv; *p; p++) {
  564                 s = *p;
  565                 if(s->rport == pdest)
  566                 if(s->lport == psource)
  567                 if(ipcmp(s->raddr, dest) == 0)
  568                 if(ipcmp(s->laddr, source) == 0){
  569                         if(s->ignoreadvice)
  570                                 break;
  571                         qlock(s);
  572                         qunlock(udp);
  573                         qhangup(s->rq, msg);
  574                         qhangup(s->wq, msg);
  575                         qunlock(s);
  576                         freeblist(bp);
  577                         return;
  578                 }
  579         }
  580         qunlock(udp);
  581         freeblist(bp);
  582 }
  583 
  584 int
  585 udpstats(Proto *udp, char *buf, int len)
  586 {
  587         Udppriv *upriv;
  588 
  589         upriv = udp->priv;
  590         return snprint(buf, len, "InDatagrams: %lud\nNoPorts: %lud\nInErrors: %lud\nOutDatagrams: %lud\n",
  591                 upriv->ustats.udpInDatagrams,
  592                 upriv->ustats.udpNoPorts,
  593                 upriv->ustats.udpInErrors,
  594                 upriv->ustats.udpOutDatagrams);
  595 }
  596 
  597 void
  598 udpinit(Fs *fs)
  599 {
  600         Proto *udp;
  601 
  602         udp = smalloc(sizeof(Proto));
  603         udp->priv = smalloc(sizeof(Udppriv));
  604         udp->name = "udp";
  605         udp->connect = udpconnect;
  606         udp->announce = udpannounce;
  607         udp->ctl = udpctl;
  608         udp->state = udpstate;
  609         udp->create = udpcreate;
  610         udp->close = udpclose;
  611         udp->rcv = udpiput;
  612         udp->advise = udpadvise;
  613         udp->stats = udpstats;
  614         udp->ipproto = IP_UDPPROTO;
  615         udp->nc = Nchans;
  616         udp->ptclsize = sizeof(Udpcb);
  617 
  618         Fsproto(fs, udp);
  619 }

Cache object: 6d431107ab920c667379200a8223caff


[ 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.