2 * igmp - internet group management protocol
6 #include "../port/lib.h"
10 #include "../port/error.h"
16 IGMP_IPHDRSIZE = 20, /* size of ip header */
17 IGMP_HDRSIZE = 8, /* size of IGMP header */
24 MAXTIMEOUT = 10000/MSPTICK, /* at most 10 secs for a response */
27 typedef struct IGMPpkt IGMPpkt;
31 uchar vihl; /* Version and header length */
32 uchar tos; /* Type of service */
33 uchar len[2]; /* packet length (including headers) */
34 uchar id[2]; /* Identification */
35 uchar frag[2]; /* Fragment information */
37 uchar proto; /* Protocol */
38 uchar cksum[2]; /* checksum of ip portion */
39 uchar src[IPaddrlen]; /* Ip source */
40 uchar dst[IPaddrlen]; /* Ip destination */
43 uchar vertype; /* version and type */
45 uchar igmpcksum[2]; /* checksum of igmp portion */
46 uchar group[IPaddrlen]; /* multicast group */
51 #define IGMPPKTSZ offsetof(IGMPpkt, payload[0])
54 * lists for group reports
56 typedef struct IGMPrep IGMPrep;
65 typedef struct IGMP IGMP;
87 igmpsendreport(Medium *m, uchar *addr)
92 bp = allocb(sizeof(IGMPpkt));
98 memset(bp->rp, 0, IGMPPKTSZ);
99 hnputl(p->src, Mediumgetaddr(m));
100 hnputl(p->dst, Ipallsys);
101 p->vertype = (1<<4) | IGMPreport;
102 p->proto = IP_IGMPPROTO;
103 memmove(p->group, addr, IPaddrlen);
104 hnputs(p->igmpcksum, ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE));
105 netlog(Logigmp, "igmpreport %I\n", p->group);
107 ipoput4(bp, 0, 1, DFLTTOS, nil); /* TTL of 1 */
114 return igmpalloc.reports != 0;
122 Multicast *mp, **lmp;
128 sleep(&igmpalloc.r, isreport, 0);
132 if(igmpalloc.reports == nil)
135 /* look for a single report */
136 lrp = &igmpalloc.reports;
138 for(rp = *lrp; rp; rp = *lrp){
141 for(mp = *lmp; mp; mp = *lmp){
142 if(rp->ticks >= mp->timeout){
151 if(rp->multi != nil){
162 /* do a single report and try again */
163 hnputl(ip, mp->addr);
164 igmpsendreport(rp->m, ip);
169 tsleep(&up->sleep, return0, 0, MSPTICK);
177 igmpiput(Medium *m, Ipifc *, Block *bp)
183 Multicast *mp, **lmp;
185 ghp = (IGMPpkt*)(bp->rp);
186 netlog(Logigmp, "igmpiput: %d %I\n", ghp->vertype, ghp->group);
189 if(n < IGMP_IPHDRSIZE+IGMP_HDRSIZE){
190 netlog(Logigmp, "igmpiput: bad len\n");
193 if((ghp->vertype>>4) != 1){
194 netlog(Logigmp, "igmpiput: bad igmp type\n");
197 if(ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE)){
198 netlog(Logigmp, "igmpiput: checksum error %I\n", ghp->src);
202 group = nhgetl(ghp->group);
205 switch(ghp->vertype & 0xf){
208 * start reporting groups that we're a member of.
211 for(rp = igmpalloc.reports; rp; rp = rp->next)
215 break; /* already reporting */
217 mp = Mediumcopymulti(m);
221 rp = malloc(sizeof(*rp));
228 for(; mp; mp = mp->next)
229 mp->timeout = nrand(MAXTIMEOUT);
230 rp->next = igmpalloc.reports;
231 igmpalloc.reports = rp;
233 wakeup(&igmpalloc.r);
238 * find report list for this medium
241 lrp = &igmpalloc.reports;
242 for(rp = *lrp; rp; rp = *lrp){
251 * if someone else has reported a group,
255 for(mp = *lmp; mp; mp = *lmp){
256 if(mp->addr == group){
273 igmpstats(char *buf, int len)
275 return snprint(buf, len, "\trcvd %d %d\n\tsent %d %d\n",
276 stats.inqueries, stats.inreports,
277 stats.outqueries, stats.outreports);
290 igmp.stats = igmpstats;
291 igmp.ipproto = IP_IGMPPROTO;
295 igmpreportfn = igmpsendreport;
296 kproc("igmpproc", igmpproc, 0);