📄 igmp.c
字号:
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include "ip.h"enum{ IGMP_IPHDRSIZE = 20, /* size of ip header */ IGMP_HDRSIZE = 8, /* size of IGMP header */ IP_IGMPPROTO = 2, IGMPquery = 1, IGMPreport = 2, MSPTICK = 100, MAXTIMEOUT = 10000/MSPTICK, /* at most 10 secs for a response */};typedef struct IGMPpkt IGMPpkt;struct IGMPpkt{ /* ip header */ byte vihl; /* Version and header length */ byte tos; /* Type of service */ byte len[2]; /* packet length (including headers) */ byte id[2]; /* Identification */ byte frag[2]; /* Fragment information */ byte Unused; byte proto; /* Protocol */ byte cksum[2]; /* checksum of ip portion */ byte src[IPaddrlen]; /* Ip source */ byte dst[IPaddrlen]; /* Ip destination */ /* igmp header */ byte vertype; /* version and type */ byte unused; byte igmpcksum[2]; /* checksum of igmp portion */ byte group[IPaddrlen]; /* multicast group */};/* * lists for group reports */typedef struct IGMPrep IGMPrep;struct IGMPrep{ IGMPrep *next; Media *m; int ticks; Multicast *multi;};typedef struct IGMP IGMP;struct IGMP{ Lock; Rendez r; IGMPrep *reports;};IGMP igmpalloc; Proto igmp;extern Fs fs;static struct Stats{ ulong inqueries; ulong outqueries; ulong inreports; ulong outreports;} stats;voidigmpsendreport(Media *m, byte *addr){ IGMPpkt *p; Block *bp; bp = allocb(sizeof(IGMPpkt)); if(bp == nil) return; p = (IGMPpkt*)bp->wp; p->vihl = IP_VER4; bp->wp += sizeof(IGMPpkt); memset(bp->rp, 0, sizeof(IGMPpkt)); hnputl(p->src, Mediagetaddr(m)); hnputl(p->dst, Ipallsys); p->vertype = (1<<4) | IGMPreport; p->proto = IP_IGMPPROTO; memmove(p->group, addr, IPaddrlen); hnputs(p->igmpcksum, ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE)); netlog(Logigmp, "igmpreport %I\n", p->group); stats.outreports++; ipoput4(bp, 0, 1, DFLTTOS, nil); /* TTL of 1 */}static intisreport(void *a){ USED(a); return igmpalloc.reports != 0;}voidigmpproc(void *a){ IGMPrep *rp, **lrp; Multicast *mp, **lmp; byte ip[IPaddrlen]; USED(a); for(;;){ sleep(&igmpalloc.r, isreport, 0); for(;;){ lock(&igmpalloc); if(igmpalloc.reports == nil) break; /* look for a single report */ lrp = &igmpalloc.reports; mp = nil; for(rp = *lrp; rp; rp = *lrp){ rp->ticks++; lmp = &rp->multi; for(mp = *lmp; mp; mp = *lmp){ if(rp->ticks >= mp->timeout){ *lmp = mp->next; break; } lmp = &mp->next; } if(mp != nil) break; if(rp->multi != nil){ lrp = &rp->next; continue; } else { *lrp = rp->next; free(rp); } } unlock(&igmpalloc); if(mp){ /* do a single report and try again */ hnputl(ip, mp->addr); igmpsendreport(rp->m, ip); free(mp); continue; } tsleep(&up->sleep, return0, 0, MSPTICK); } unlock(&igmpalloc); }}voidigmpiput(Media *m, Ipifc *, Block *bp){ int n; IGMPpkt *ghp; Ipaddr group; IGMPrep *rp, **lrp; Multicast *mp, **lmp; ghp = (IGMPpkt*)(bp->rp); netlog(Logigmp, "igmpiput: %d %I\n", ghp->vertype, ghp->group); n = blocklen(bp); if(n < IGMP_IPHDRSIZE+IGMP_HDRSIZE){ netlog(Logigmp, "igmpiput: bad len\n"); goto error; } if((ghp->vertype>>4) != 1){ netlog(Logigmp, "igmpiput: bad igmp type\n"); goto error; } if(ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE)){ netlog(Logigmp, "igmpiput: checksum error %I\n", ghp->src); goto error; } group = nhgetl(ghp->group); lock(&igmpalloc); switch(ghp->vertype & 0xf){ case IGMPquery: /* * start reporting groups that we're a member of. */ stats.inqueries++; for(rp = igmpalloc.reports; rp; rp = rp->next) if(rp->m == m) break; if(rp != nil) break; /* already reporting */ mp = Mediacopymulti(m); if(mp == nil) break; rp = malloc(sizeof(*rp)); if(rp == nil) break; rp->m = m; rp->multi = mp; rp->ticks = 0; for(; mp; mp = mp->next) mp->timeout = nrand(MAXTIMEOUT); rp->next = igmpalloc.reports; igmpalloc.reports = rp; wakeup(&igmpalloc.r); break; case IGMPreport: /* * find report list for this medium */ stats.inreports++; lrp = &igmpalloc.reports; for(rp = *lrp; rp; rp = *lrp){ if(rp->m == m) break; lrp = &rp->next; } if(rp == nil) break; /* * if someone else has reported a group, * we don't have to. */ lmp = &rp->multi; for(mp = *lmp; mp; mp = *lmp){ if(mp->addr == group){ *lmp = mp->next; free(mp); break; } lmp = &mp->next; } break; } unlock(&igmpalloc);error: freeb(bp);}intigmpstats(char *buf, int len){ return snprint(buf, len, "\trcvd %d %d\n\tsent %d %d\n", stats.inqueries, stats.inreports, stats.outqueries, stats.outreports);}voidigmpinit(Fs *fs){ igmp.name = "igmp"; igmp.connect = nil; igmp.announce = nil; igmp.ctl = nil; igmp.state = nil; igmp.close = nil; igmp.rcv = igmpiput; igmp.stats = igmpstats; igmp.ipproto = IP_IGMPPROTO; igmp.nc = 0; igmp.ptclsize = 0; igmpreportfn = igmpsendreport; kproc("igmpproc", igmpproc, 0); Fsproto(fs, &igmp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -