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/icmp.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 
   10 typedef struct Icmp {
   11         uchar   vihl;           /* Version and header length */
   12         uchar   tos;            /* Type of service */
   13         uchar   length[2];      /* packet length */
   14         uchar   id[2];          /* Identification */
   15         uchar   frag[2];        /* Fragment information */
   16         uchar   ttl;            /* Time to live */
   17         uchar   proto;          /* Protocol */
   18         uchar   ipcksum[2];     /* Header checksum */
   19         uchar   src[4];         /* Ip source */
   20         uchar   dst[4];         /* Ip destination */
   21         uchar   type;
   22         uchar   code;
   23         uchar   cksum[2];
   24         uchar   icmpid[2];
   25         uchar   seq[2];
   26         uchar   data[1];
   27 } Icmp;
   28 
   29 enum {                  /* Packet Types */
   30         EchoReply       = 0,
   31         Unreachable     = 3,
   32         SrcQuench       = 4,
   33         Redirect        = 5,
   34         EchoRequest     = 8,
   35         TimeExceed      = 11,
   36         InParmProblem   = 12,
   37         Timestamp       = 13,
   38         TimestampReply  = 14,
   39         InfoRequest     = 15,
   40         InfoReply       = 16,
   41         AddrMaskRequest = 17,
   42         AddrMaskReply   = 18,
   43 
   44         Maxtype         = 18,
   45 };
   46 
   47 enum
   48 {
   49         MinAdvise       = 24,   /* minimum needed for us to advise another protocol */ 
   50 };
   51 
   52 char *icmpnames[Maxtype+1] =
   53 {
   54 [EchoReply]             "EchoReply",
   55 [Unreachable]           "Unreachable",
   56 [SrcQuench]             "SrcQuench",
   57 [Redirect]              "Redirect",
   58 [EchoRequest]           "EchoRequest",
   59 [TimeExceed]            "TimeExceed",
   60 [InParmProblem]         "InParmProblem",
   61 [Timestamp]             "Timestamp",
   62 [TimestampReply]        "TimestampReply",
   63 [InfoRequest]           "InfoRequest",
   64 [InfoReply]             "InfoReply",
   65 [AddrMaskRequest]       "AddrMaskRequest",
   66 [AddrMaskReply  ]       "AddrMaskReply  ",
   67 };
   68 
   69 enum {
   70         IP_ICMPPROTO    = 1,
   71         ICMP_IPSIZE     = 20,
   72         ICMP_HDRSIZE    = 8,
   73 };
   74 
   75 enum
   76 {
   77         InMsgs,
   78         InErrors,
   79         OutMsgs,
   80         CsumErrs,
   81         LenErrs,
   82         HlenErrs,
   83 
   84         Nstats,
   85 };
   86 
   87 static char *statnames[Nstats] =
   88 {
   89 [InMsgs]        "InMsgs",
   90 [InErrors]      "InErrors",
   91 [OutMsgs]       "OutMsgs",
   92 [CsumErrs]      "CsumErrs",
   93 [LenErrs]       "LenErrs",
   94 [HlenErrs]      "HlenErrs",
   95 };
   96 
   97 typedef struct Icmppriv Icmppriv;
   98 struct Icmppriv
   99 {
  100         ulong   stats[Nstats];
  101 
  102         /* message counts */
  103         ulong   in[Maxtype+1];
  104         ulong   out[Maxtype+1];
  105 };
  106 
  107 static void icmpkick(void *x, Block*);
  108 
  109 static void
  110 icmpcreate(Conv *c)
  111 {
  112         c->rq = qopen(64*1024, Qmsg, 0, c);
  113         c->wq = qbypass(icmpkick, c);
  114 }
  115 
  116 extern char*
  117 icmpconnect(Conv *c, char **argv, int argc)
  118 {
  119         char *e;
  120 
  121         e = Fsstdconnect(c, argv, argc);
  122         if(e != nil)
  123                 return e;
  124         Fsconnected(c, e);
  125 
  126         return nil;
  127 }
  128 
  129 extern int
  130 icmpstate(Conv *c, char *state, int n)
  131 {
  132         USED(c);
  133         return snprint(state, n, "%s qin %d qout %d\n",
  134                 "Datagram",
  135                 c->rq ? qlen(c->rq) : 0,
  136                 c->wq ? qlen(c->wq) : 0
  137         );
  138 }
  139 
  140 extern char*
  141 icmpannounce(Conv *c, char **argv, int argc)
  142 {
  143         char *e;
  144 
  145         e = Fsstdannounce(c, argv, argc);
  146         if(e != nil)
  147                 return e;
  148         Fsconnected(c, nil);
  149 
  150         return nil;
  151 }
  152 
  153 extern void
  154 icmpclose(Conv *c)
  155 {
  156         qclose(c->rq);
  157         qclose(c->wq);
  158         ipmove(c->laddr, IPnoaddr);
  159         ipmove(c->raddr, IPnoaddr);
  160         c->lport = 0;
  161 }
  162 
  163 static void
  164 icmpkick(void *x, Block *bp)
  165 {
  166         Conv *c = x;
  167         Icmp *p;
  168         Icmppriv *ipriv;
  169 
  170         if(bp == nil)
  171                 return;
  172 
  173         if(blocklen(bp) < ICMP_IPSIZE + ICMP_HDRSIZE){
  174                 freeblist(bp);
  175                 return;
  176         }
  177         p = (Icmp *)(bp->rp);
  178         p->vihl = IP_VER4;
  179         ipriv = c->p->priv;
  180         if(p->type <= Maxtype)  
  181                 ipriv->out[p->type]++;
  182         
  183         v6tov4(p->dst, c->raddr);
  184         v6tov4(p->src, c->laddr);
  185         p->proto = IP_ICMPPROTO;
  186         hnputs(p->icmpid, c->lport);
  187         memset(p->cksum, 0, sizeof(p->cksum));
  188         hnputs(p->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE));
  189         ipriv->stats[OutMsgs]++;
  190         ipoput4(c->p->f, bp, 0, c->ttl, c->tos, nil);
  191 }
  192 
  193 extern void
  194 icmpttlexceeded(Fs *f, uchar *ia, Block *bp)
  195 {
  196         Block   *nbp;
  197         Icmp    *p, *np;
  198 
  199         p = (Icmp *)bp->rp;
  200 
  201         netlog(f, Logicmp, "sending icmpttlexceeded -> %V\n", p->src);
  202         nbp = allocb(ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8);
  203         nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8;
  204         np = (Icmp *)nbp->rp;
  205         np->vihl = IP_VER4;
  206         memmove(np->dst, p->src, sizeof(np->dst));
  207         v6tov4(np->src, ia);
  208         memmove(np->data, bp->rp, ICMP_IPSIZE + 8);
  209         np->type = TimeExceed;
  210         np->code = 0;
  211         np->proto = IP_ICMPPROTO;
  212         hnputs(np->icmpid, 0);
  213         hnputs(np->seq, 0);
  214         memset(np->cksum, 0, sizeof(np->cksum));
  215         hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE));
  216         ipoput4(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  217 
  218 }
  219 
  220 static void
  221 icmpunreachable(Fs *f, Block *bp, int code, int seq)
  222 {
  223         Block   *nbp;
  224         Icmp    *p, *np;
  225         int     i;
  226         uchar   addr[IPaddrlen];
  227 
  228         p = (Icmp *)bp->rp;
  229 
  230         /* only do this for unicast sources and destinations */
  231         v4tov6(addr, p->dst);
  232         i = ipforme(f, addr);
  233         if((i&Runi) == 0)
  234                 return;
  235         v4tov6(addr, p->src);
  236         i = ipforme(f, addr);
  237         if(i != 0 && (i&Runi) == 0)
  238                 return;
  239 
  240         netlog(f, Logicmp, "sending icmpnoconv -> %V\n", p->src);
  241         nbp = allocb(ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8);
  242         nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8;
  243         np = (Icmp *)nbp->rp;
  244         np->vihl = IP_VER4;
  245         memmove(np->dst, p->src, sizeof(np->dst));
  246         memmove(np->src, p->dst, sizeof(np->src));
  247         memmove(np->data, bp->rp, ICMP_IPSIZE + 8);
  248         np->type = Unreachable;
  249         np->code = code;
  250         np->proto = IP_ICMPPROTO;
  251         hnputs(np->icmpid, 0);
  252         hnputs(np->seq, seq);
  253         memset(np->cksum, 0, sizeof(np->cksum));
  254         hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE));
  255         ipoput4(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  256 }
  257 
  258 extern void
  259 icmpnoconv(Fs *f, Block *bp)
  260 {
  261         icmpunreachable(f, bp, 3, 0);
  262 }
  263 
  264 extern void
  265 icmpcantfrag(Fs *f, Block *bp, int mtu)
  266 {
  267         icmpunreachable(f, bp, 4, mtu);
  268 }
  269 
  270 static void
  271 goticmpkt(Proto *icmp, Block *bp)
  272 {
  273         Conv    **c, *s;
  274         Icmp    *p;
  275         uchar   dst[IPaddrlen];
  276         ushort  recid;
  277 
  278         p = (Icmp *) bp->rp;
  279         v4tov6(dst, p->src);
  280         recid = nhgets(p->icmpid);
  281 
  282         for(c = icmp->conv; *c; c++) {
  283                 s = *c;
  284                 if(s->lport == recid)
  285                 if(ipcmp(s->raddr, dst) == 0){
  286                         bp = concatblock(bp);
  287                         if(bp != nil)
  288                                 qpass(s->rq, bp);
  289                         return;
  290                 }
  291         }
  292         freeblist(bp);
  293 }
  294 
  295 static Block *
  296 mkechoreply(Block *bp)
  297 {
  298         Icmp    *q;
  299         uchar   ip[4];
  300 
  301         q = (Icmp *)bp->rp;
  302         q->vihl = IP_VER4;
  303         memmove(ip, q->src, sizeof(q->dst));
  304         memmove(q->src, q->dst, sizeof(q->src));
  305         memmove(q->dst, ip,  sizeof(q->dst));
  306         q->type = EchoReply;
  307         memset(q->cksum, 0, sizeof(q->cksum));
  308         hnputs(q->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE));
  309 
  310         return bp;
  311 }
  312 
  313 static char *unreachcode[] =
  314 {
  315 [0]     "net unreachable",
  316 [1]     "host unreachable",
  317 [2]     "protocol unreachable",
  318 [3]     "port unreachable",
  319 [4]     "fragmentation needed and DF set",
  320 [5]     "source route failed",
  321 };
  322 
  323 static void
  324 icmpiput(Proto *icmp, Ipifc*, Block *bp)
  325 {
  326         int     n, iplen;
  327         Icmp    *p;
  328         Block   *r;
  329         Proto   *pr;
  330         char    *msg;
  331         char    m2[128];
  332         Icmppriv *ipriv;
  333 
  334         ipriv = icmp->priv;
  335         
  336         ipriv->stats[InMsgs]++;
  337 
  338         p = (Icmp *)bp->rp;
  339         netlog(icmp->f, Logicmp, "icmpiput %d %d\n", p->type, p->code);
  340         n = blocklen(bp);
  341         if(n < ICMP_IPSIZE+ICMP_HDRSIZE){
  342                 ipriv->stats[InErrors]++;
  343                 ipriv->stats[HlenErrs]++;
  344                 netlog(icmp->f, Logicmp, "icmp hlen %d\n", n);
  345                 goto raise;
  346         }
  347         iplen = nhgets(p->length);
  348         if(iplen > n || (iplen % 1)){
  349                 ipriv->stats[LenErrs]++;
  350                 ipriv->stats[InErrors]++;
  351                 netlog(icmp->f, Logicmp, "icmp length %d\n", iplen);
  352                 goto raise;
  353         }
  354         if(ptclcsum(bp, ICMP_IPSIZE, iplen - ICMP_IPSIZE)){
  355                 ipriv->stats[InErrors]++;
  356                 ipriv->stats[CsumErrs]++;
  357                 netlog(icmp->f, Logicmp, "icmp checksum error\n");
  358                 goto raise;
  359         }
  360         if(p->type <= Maxtype)
  361                 ipriv->in[p->type]++;
  362 
  363         switch(p->type) {
  364         case EchoRequest:
  365                 if (iplen < n)
  366                         bp = trimblock(bp, 0, iplen);
  367                 r = mkechoreply(bp);
  368                 ipriv->out[EchoReply]++;
  369                 ipoput4(icmp->f, r, 0, MAXTTL, DFLTTOS, nil);
  370                 break;
  371         case Unreachable:
  372                 if(p->code > 5)
  373                         msg = unreachcode[1];
  374                 else
  375                         msg = unreachcode[p->code];
  376 
  377                 bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
  378                 if(blocklen(bp) < MinAdvise){
  379                         ipriv->stats[LenErrs]++;
  380                         goto raise;
  381                 }
  382                 p = (Icmp *)bp->rp;
  383                 pr = Fsrcvpcolx(icmp->f, p->proto);
  384                 if(pr != nil && pr->advise != nil) {
  385                         (*pr->advise)(pr, bp, msg);
  386                         return;
  387                 }
  388 
  389                 bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE;
  390                 goticmpkt(icmp, bp);
  391                 break;
  392         case TimeExceed:
  393                 if(p->code == 0){
  394                         sprint(m2, "ttl exceeded at %V", p->src);
  395 
  396                         bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
  397                         if(blocklen(bp) < MinAdvise){
  398                                 ipriv->stats[LenErrs]++;
  399                                 goto raise;
  400                         }
  401                         p = (Icmp *)bp->rp;
  402                         pr = Fsrcvpcolx(icmp->f, p->proto);
  403                         if(pr != nil && pr->advise != nil) {
  404                                 (*pr->advise)(pr, bp, m2);
  405                                 return;
  406                         }
  407                         bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE;
  408                 }
  409 
  410                 goticmpkt(icmp, bp);
  411                 break;
  412         default:
  413                 goticmpkt(icmp, bp);
  414                 break;
  415         }
  416         return;
  417 
  418 raise:
  419         freeblist(bp);
  420 }
  421 
  422 void
  423 icmpadvise(Proto *icmp, Block *bp, char *msg)
  424 {
  425         Conv    **c, *s;
  426         Icmp    *p;
  427         uchar   dst[IPaddrlen];
  428         ushort  recid;
  429 
  430         p = (Icmp *) bp->rp;
  431         v4tov6(dst, p->dst);
  432         recid = nhgets(p->icmpid);
  433 
  434         for(c = icmp->conv; *c; c++) {
  435                 s = *c;
  436                 if(s->lport == recid)
  437                 if(ipcmp(s->raddr, dst) == 0){
  438                         qhangup(s->rq, msg);
  439                         qhangup(s->wq, msg);
  440                         break;
  441                 }
  442         }
  443         freeblist(bp);
  444 }
  445 
  446 int
  447 icmpstats(Proto *icmp, char *buf, int len)
  448 {
  449         Icmppriv *priv;
  450         char *p, *e;
  451         int i;
  452 
  453         priv = icmp->priv;
  454         p = buf;
  455         e = p+len;
  456         for(i = 0; i < Nstats; i++)
  457                 p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]);
  458         for(i = 0; i <= Maxtype; i++){
  459                 if(icmpnames[i])
  460                         p = seprint(p, e, "%s: %lud %lud\n", icmpnames[i], priv->in[i], priv->out[i]);
  461                 else
  462                         p = seprint(p, e, "%d: %lud %lud\n", i, priv->in[i], priv->out[i]);
  463         }
  464         return p - buf;
  465 }
  466         
  467 void
  468 icmpinit(Fs *fs)
  469 {
  470         Proto *icmp;
  471 
  472         icmp = smalloc(sizeof(Proto));
  473         icmp->priv = smalloc(sizeof(Icmppriv));
  474         icmp->name = "icmp";
  475         icmp->connect = icmpconnect;
  476         icmp->announce = icmpannounce;
  477         icmp->state = icmpstate;
  478         icmp->create = icmpcreate;
  479         icmp->close = icmpclose;
  480         icmp->rcv = icmpiput;
  481         icmp->stats = icmpstats;
  482         icmp->ctl = nil;
  483         icmp->advise = icmpadvise;
  484         icmp->gc = nil;
  485         icmp->ipproto = IP_ICMPPROTO;
  486         icmp->nc = 128;
  487         icmp->ptclsize = 0;
  488 
  489         Fsproto(fs, icmp);
  490 }

Cache object: b22ba4e8235b7cf31d69a9e5f070fb57


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