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/igmp.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 enum
   11 {
   12         IGMP_IPHDRSIZE  = 20,           /* size of ip header */
   13         IGMP_HDRSIZE    = 8,            /* size of IGMP header */
   14         IP_IGMPPROTO    = 2,
   15 
   16         IGMPquery       = 1,
   17         IGMPreport      = 2,
   18 
   19         MSPTICK         = 100,
   20         MAXTIMEOUT      = 10000/MSPTICK,        /* at most 10 secs for a response */
   21 };
   22 
   23 typedef struct IGMPpkt IGMPpkt;
   24 struct IGMPpkt
   25 {
   26         /* ip header */
   27         byte    vihl;           /* Version and header length */
   28         byte    tos;            /* Type of service */
   29         byte    len[2];         /* packet length (including headers) */
   30         byte    id[2];          /* Identification */
   31         byte    frag[2];        /* Fragment information */
   32         byte    Unused; 
   33         byte    proto;          /* Protocol */
   34         byte    cksum[2];       /* checksum of ip portion */
   35         byte    src[IPaddrlen];         /* Ip source */
   36         byte    dst[IPaddrlen];         /* Ip destination */
   37 
   38         /* igmp header */
   39         byte    vertype;        /* version and type */
   40         byte    unused;
   41         byte    igmpcksum[2];           /* checksum of igmp portion */
   42         byte    group[IPaddrlen];       /* multicast group */
   43 };
   44 
   45 /*
   46  *  lists for group reports
   47  */
   48 typedef struct IGMPrep IGMPrep;
   49 struct IGMPrep
   50 {
   51         IGMPrep         *next;
   52         Media           *m;
   53         int             ticks;
   54         Multicast       *multi;
   55 };
   56 
   57 typedef struct IGMP IGMP;
   58 struct IGMP
   59 {
   60         Lock;
   61         Rendez  r;
   62         IGMPrep *reports;
   63 };
   64 
   65 IGMP igmpalloc;
   66 
   67         Proto   igmp;
   68 extern  Fs      fs;
   69 
   70 static struct Stats
   71 {
   72         ulong   inqueries;
   73         ulong   outqueries;
   74         ulong   inreports;
   75         ulong   outreports;
   76 } stats;
   77 
   78 void
   79 igmpsendreport(Media *m, byte *addr)
   80 {
   81         IGMPpkt *p;
   82         Block *bp;
   83 
   84         bp = allocb(sizeof(IGMPpkt));
   85         if(bp == nil)
   86                 return;
   87         p = (IGMPpkt*)bp->wp;
   88         p->vihl = IP_VER4;
   89         bp->wp += sizeof(IGMPpkt);
   90         memset(bp->rp, 0, sizeof(IGMPpkt));
   91         hnputl(p->src, Mediagetaddr(m));
   92         hnputl(p->dst, Ipallsys);
   93         p->vertype = (1<<4) | IGMPreport;
   94         p->proto = IP_IGMPPROTO;
   95         memmove(p->group, addr, IPaddrlen);
   96         hnputs(p->igmpcksum, ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE));
   97         netlog(Logigmp, "igmpreport %I\n", p->group);
   98         stats.outreports++;
   99         ipoput4(bp, 0, 1, DFLTTOS, nil);        /* TTL of 1 */
  100 }
  101 
  102 static int
  103 isreport(void *a)
  104 {
  105         USED(a);
  106         return igmpalloc.reports != 0;
  107 }
  108 
  109 
  110 void
  111 igmpproc(void *a)
  112 {
  113         IGMPrep *rp, **lrp;
  114         Multicast *mp, **lmp;
  115         byte ip[IPaddrlen];
  116 
  117         USED(a);
  118 
  119         for(;;){
  120                 sleep(&igmpalloc.r, isreport, 0);
  121                 for(;;){
  122                         lock(&igmpalloc);
  123 
  124                         if(igmpalloc.reports == nil)
  125                                 break;
  126         
  127                         /* look for a single report */
  128                         lrp = &igmpalloc.reports;
  129                         mp = nil;
  130                         for(rp = *lrp; rp; rp = *lrp){
  131                                 rp->ticks++;
  132                                 lmp = &rp->multi;
  133                                 for(mp = *lmp; mp; mp = *lmp){
  134                                         if(rp->ticks >= mp->timeout){
  135                                                 *lmp = mp->next;
  136                                                 break;
  137                                         }
  138                                         lmp = &mp->next;
  139                                 }
  140                                 if(mp != nil)
  141                                         break;
  142 
  143                                 if(rp->multi != nil){
  144                                         lrp = &rp->next;
  145                                         continue;
  146                                 } else {
  147                                         *lrp = rp->next;
  148                                         free(rp);
  149                                 }
  150                         }
  151                         unlock(&igmpalloc);
  152 
  153                         if(mp){
  154                                 /* do a single report and try again */
  155                                 hnputl(ip, mp->addr);
  156                                 igmpsendreport(rp->m, ip);
  157                                 free(mp);
  158                                 continue;
  159                         }
  160 
  161                         tsleep(&up->sleep, return0, 0, MSPTICK);
  162                 }
  163                 unlock(&igmpalloc);
  164         }
  165 
  166 }
  167 
  168 void
  169 igmpiput(Media *m, Ipifc *, Block *bp)
  170 {
  171         int n;
  172         IGMPpkt *ghp;
  173         Ipaddr group;
  174         IGMPrep *rp, **lrp;
  175         Multicast *mp, **lmp;
  176 
  177         ghp = (IGMPpkt*)(bp->rp);
  178         netlog(Logigmp, "igmpiput: %d %I\n", ghp->vertype, ghp->group);
  179 
  180         n = blocklen(bp);
  181         if(n < IGMP_IPHDRSIZE+IGMP_HDRSIZE){
  182                 netlog(Logigmp, "igmpiput: bad len\n");
  183                 goto error;
  184         }
  185         if((ghp->vertype>>4) != 1){
  186                 netlog(Logigmp, "igmpiput: bad igmp type\n");
  187                 goto error;
  188         }
  189         if(ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE)){
  190                 netlog(Logigmp, "igmpiput: checksum error %I\n", ghp->src);
  191                 goto error;
  192         }
  193 
  194         group = nhgetl(ghp->group);
  195         
  196         lock(&igmpalloc);
  197         switch(ghp->vertype & 0xf){
  198         case IGMPquery:
  199                 /*
  200                  *  start reporting groups that we're a member of.
  201                  */
  202                 stats.inqueries++;
  203                 for(rp = igmpalloc.reports; rp; rp = rp->next)
  204                         if(rp->m == m)
  205                                 break;
  206                 if(rp != nil)
  207                         break;  /* already reporting */
  208 
  209                 mp = Mediacopymulti(m);
  210                 if(mp == nil)
  211                         break;
  212 
  213                 rp = malloc(sizeof(*rp));
  214                 if(rp == nil)
  215                         break;
  216 
  217                 rp->m = m;
  218                 rp->multi = mp;
  219                 rp->ticks = 0;
  220                 for(; mp; mp = mp->next)
  221                         mp->timeout = nrand(MAXTIMEOUT);
  222                 rp->next = igmpalloc.reports;
  223                 igmpalloc.reports = rp;
  224 
  225                 wakeup(&igmpalloc.r);
  226 
  227                 break;
  228         case IGMPreport:
  229                 /*
  230                  *  find report list for this medium
  231                  */
  232                 stats.inreports++;
  233                 lrp = &igmpalloc.reports;
  234                 for(rp = *lrp; rp; rp = *lrp){
  235                         if(rp->m == m)
  236                                 break;
  237                         lrp = &rp->next;
  238                 }
  239                 if(rp == nil)
  240                         break;
  241 
  242                 /*
  243                  *  if someone else has reported a group,
  244                  *  we don't have to.
  245                  */
  246                 lmp = &rp->multi;
  247                 for(mp = *lmp; mp; mp = *lmp){
  248                         if(mp->addr == group){
  249                                 *lmp = mp->next;
  250                                 free(mp);
  251                                 break;
  252                         }
  253                         lmp = &mp->next;
  254                 }
  255 
  256                 break;
  257         }
  258         unlock(&igmpalloc);
  259 
  260 error:
  261         freeb(bp);
  262 }
  263 
  264 int
  265 igmpstats(char *buf, int len)
  266 {
  267         return snprint(buf, len, "\trcvd %d %d\n\tsent %d %d\n",
  268                 stats.inqueries, stats.inreports,
  269                 stats.outqueries, stats.outreports);
  270 }
  271 
  272 void
  273 igmpinit(Fs *fs)
  274 {
  275         igmp.name = "igmp";
  276         igmp.connect = nil;
  277         igmp.announce = nil;
  278         igmp.ctl = nil;
  279         igmp.state = nil;
  280         igmp.close = nil;
  281         igmp.rcv = igmpiput;
  282         igmp.stats = igmpstats;
  283         igmp.ipproto = IP_IGMPPROTO;
  284         igmp.nc = 0;
  285         igmp.ptclsize = 0;
  286 
  287         igmpreportfn = igmpsendreport;
  288         kproc("igmpproc", igmpproc, 0);
  289 
  290         Fsproto(fs, &igmp);
  291 }

Cache object: 02b19d43ec53fc29374737eb0934368c


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