IGMP protocol now uses the generic background protocol mechanism.

This commit is contained in:
Michael Brown
2005-06-01 22:22:14 +00:00
parent 85a380530d
commit be7897523d
4 changed files with 37 additions and 178 deletions

View File

@@ -21,13 +21,10 @@ Literature dealing with the network protocols:
#include "resolv.h"
#include "dev.h"
#include "nic.h"
#include "background.h"
#include "elf.h" /* FOR EM_CURRENT */
struct arptable_t arptable[MAX_ARP];
#if MULTICAST_LEVEL2
unsigned long last_igmpv1 = 0;
struct igmptable_t igmptable[MAX_IGMP];
#endif
/* Put rom_info in .nocompress section so romprefix.S can write to it */
struct rom_info rom __attribute__ ((section (".text16.nocompress"))) = {0,0};
static unsigned long netmask;
@@ -827,140 +824,6 @@ uint16_t tcpudpchksum(struct iphdr *ip)
return checksum;
}
#ifdef MULTICAST_LEVEL2
static void send_igmp_reports(unsigned long now)
{
int i;
for(i = 0; i < MAX_IGMP; i++) {
if (igmptable[i].time && (now >= igmptable[i].time)) {
struct igmp_ip_t igmp;
igmp.router_alert[0] = 0x94;
igmp.router_alert[1] = 0x04;
igmp.router_alert[2] = 0;
igmp.router_alert[3] = 0;
build_ip_hdr(igmptable[i].group.s_addr,
1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
igmp.igmp.type = IGMPv2_REPORT;
if (last_igmpv1 &&
(now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
igmp.igmp.type = IGMPv1_REPORT;
}
igmp.igmp.response_time = 0;
igmp.igmp.chksum = 0;
igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
ip_transmit(sizeof(igmp), &igmp);
#ifdef MDEBUG
printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
#endif
/* Don't send another igmp report until asked */
igmptable[i].time = 0;
}
}
}
static void process_igmp(struct iphdr *ip, unsigned long now)
{
struct igmp *igmp;
int i;
unsigned iplen;
if (!ip || (ip->protocol == IP_IGMP) ||
(nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
return;
}
iplen = (ip->verhdrlen & 0xf)*4;
igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
return;
if ((igmp->type == IGMP_QUERY) &&
(ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
unsigned long interval = IGMP_INTERVAL;
if (igmp->response_time == 0) {
last_igmpv1 = now;
} else {
interval = (igmp->response_time * TICKS_PER_SEC)/10;
}
#ifdef MDEBUG
printf("Received IGMP query for: %@\n", igmp->group.s_addr);
#endif
for(i = 0; i < MAX_IGMP; i++) {
uint32_t group = igmptable[i].group.s_addr;
if ((group == 0) || (group == igmp->group.s_addr)) {
unsigned long time;
time = currticks() + rfc1112_sleep_interval(interval, 0);
if (time < igmptable[i].time) {
igmptable[i].time = time;
}
}
}
}
if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
(ip->dest.s_addr == igmp->group.s_addr)) {
#ifdef MDEBUG
printf("Received IGMP report for: %@\n", igmp->group.s_addr);
#endif
for(i = 0; i < MAX_IGMP; i++) {
if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
igmptable[i].time != 0) {
igmptable[i].time = 0;
}
}
}
}
void leave_group(int slot)
{
/* Be very stupid and always send a leave group message if
* I have subscribed. Imperfect but it is standards
* compliant, easy and reliable to implement.
*
* The optimal group leave method is to only send leave when,
* we were the last host to respond to a query on this group,
* and igmpv1 compatibility is not enabled.
*/
if (igmptable[slot].group.s_addr) {
struct igmp_ip_t igmp;
igmp.router_alert[0] = 0x94;
igmp.router_alert[1] = 0x04;
igmp.router_alert[2] = 0;
igmp.router_alert[3] = 0;
build_ip_hdr(htonl(GROUP_ALL_HOSTS),
1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
igmp.igmp.type = IGMP_LEAVE;
igmp.igmp.response_time = 0;
igmp.igmp.chksum = 0;
igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
ip_transmit(sizeof(igmp), &igmp);
#ifdef MDEBUG
printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
#endif
}
memset(&igmptable[slot], 0, sizeof(igmptable[0]));
}
void join_group(int slot, unsigned long group)
{
/* I have already joined */
if (igmptable[slot].group.s_addr == group)
return;
if (igmptable[slot].group.s_addr) {
leave_group(slot);
}
/* Only join a group if we are given a multicast ip, this way
* code can be given a non-multicast (broadcast or unicast ip)
* and still work...
*/
if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
igmptable[slot].group.s_addr = group;
igmptable[slot].time = currticks();
}
}
#else
#define send_igmp_reports(now) do {} while(0)
#define process_igmp(ip, now) do {} while(0)
#endif
#include "proto_eth_slow.c"
@@ -985,8 +848,8 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
*/
for (;;) {
now = currticks();
background_send(now);
send_eth_slow_reports(now);
send_igmp_reports(now);
result = eth_poll(1);
if (result == 0) {
/* We don't have anything */
@@ -1104,8 +967,8 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
#endif /* MDEBUG */
}
}
background_process(now, ptype, ip);
process_eth_slow(ptype, now);
process_igmp(ip, now);
}
return(0);
}
@@ -1297,20 +1160,4 @@ long rfc2131_sleep_interval(long base, int exp)
return tmo;
}
#ifdef MULTICAST_LEVEL2
/**************************************************************************
RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
**************************************************************************/
long rfc1112_sleep_interval(long base, int exp)
{
unsigned long divisor, tmo;
#ifdef BACKOFF_LIMIT
if (exp > BACKOFF_LIMIT)
exp = BACKOFF_LIMIT;
#endif
divisor = RAND_MAX/(base << exp);
tmo = random()/divisor;
return tmo;
}
#endif /* MULTICAST_LEVEL_2 */