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));
96 memset(bp->rp, 0, IGMPPKTSZ);
97 hnputl(p->src, Mediumgetaddr(m));
98 hnputl(p->dst, Ipallsys);
99 p->vertype = (1<<4) | IGMPreport;
100 p->proto = IP_IGMPPROTO;
101 memmove(p->group, addr, IPaddrlen);
102 hnputs(p->igmpcksum, ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE));
103 netlog(Logigmp, "igmpreport %I\n", p->group);
105 ipoput4(bp, 0, 1, DFLTTOS, nil); /* TTL of 1 */
112 return igmpalloc.reports != 0;
120 Multicast *mp, **lmp;
126 sleep(&igmpalloc.r, isreport, 0);
130 if(igmpalloc.reports == nil)
133 /* look for a single report */
134 lrp = &igmpalloc.reports;
136 for(rp = *lrp; rp; rp = *lrp){
139 for(mp = *lmp; mp; mp = *lmp){
140 if(rp->ticks >= mp->timeout){
149 if(rp->multi != nil){
160 /* do a single report and try again */
161 hnputl(ip, mp->addr);
162 igmpsendreport(rp->m, ip);
167 tsleep(&up->sleep, return0, 0, MSPTICK);
175 igmpiput(Medium *m, Ipifc *, Block *bp)
181 Multicast *mp, **lmp;
183 ghp = (IGMPpkt*)(bp->rp);
184 netlog(Logigmp, "igmpiput: %d %I\n", ghp->vertype, ghp->group);
187 if(n < IGMP_IPHDRSIZE+IGMP_HDRSIZE){
188 netlog(Logigmp, "igmpiput: bad len\n");
191 if((ghp->vertype>>4) != 1){
192 netlog(Logigmp, "igmpiput: bad igmp type\n");
195 if(ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE)){
196 netlog(Logigmp, "igmpiput: checksum error %I\n", ghp->src);
200 group = nhgetl(ghp->group);
203 switch(ghp->vertype & 0xf){
206 * start reporting groups that we're a member of.
209 for(rp = igmpalloc.reports; rp; rp = rp->next)
213 break; /* already reporting */
215 mp = Mediumcopymulti(m);
219 rp = malloc(sizeof(*rp));
226 for(; mp; mp = mp->next)
227 mp->timeout = nrand(MAXTIMEOUT);
228 rp->next = igmpalloc.reports;
229 igmpalloc.reports = rp;
231 wakeup(&igmpalloc.r);
236 * find report list for this medium
239 lrp = &igmpalloc.reports;
240 for(rp = *lrp; rp; rp = *lrp){
249 * if someone else has reported a group,
253 for(mp = *lmp; mp; mp = *lmp){
254 if(mp->addr == group){
271 igmpstats(char *buf, int len)
273 return snprint(buf, len, "\trcvd %d %d\n\tsent %d %d\n",
274 stats.inqueries, stats.inreports,
275 stats.outqueries, stats.outreports);
288 igmp.stats = igmpstats;
289 igmp.ipproto = IP_IGMPPROTO;
293 igmpreportfn = igmpsendreport;
294 kproc("igmpproc", igmpproc, 0);