summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2005-06-02 00:22:14 +0200
committerMichael Brown2005-06-02 00:22:14 +0200
commitbe7897523d42915910bb5f1828cbe5cb1d6ed8cd (patch)
tree52518721815fe6110729764a2e3c06a86ab63597
parentAdd generic mechanism for background protocols (e.g. ARP, IGMP) (diff)
downloadipxe-be7897523d42915910bb5f1828cbe5cb1d6ed8cd.tar.gz
ipxe-be7897523d42915910bb5f1828cbe5cb1d6ed8cd.tar.xz
ipxe-be7897523d42915910bb5f1828cbe5cb1d6ed8cd.zip
IGMP protocol now uses the generic background protocol mechanism.
-rw-r--r--src/core/nic.c159
-rw-r--r--src/include/etherboot.h13
-rw-r--r--src/include/igmp.h33
-rw-r--r--src/proto/igmp.c10
4 files changed, 37 insertions, 178 deletions
diff --git a/src/core/nic.c b/src/core/nic.c
index 5b857fdd..ebe69e83 100644
--- a/src/core/nic.c
+++ b/src/core/nic.c
@@ -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 */
diff --git a/src/include/etherboot.h b/src/include/etherboot.h
index 669ee8b2..7bc52311 100644
--- a/src/include/etherboot.h
+++ b/src/include/etherboot.h
@@ -130,16 +130,11 @@ enum {
MAX_ARP
};
-#define IGMP_SERVER 0
-#define MAX_IGMP IGMP_SERVER+1
-
#define RARP_REQUEST 3
#define RARP_REPLY 4
#include "in.h"
-#define MULTICAST_MASK 0xF0000000
-#define MULTICAST_NETWORK 0xE0000000
/* Helper macros used to identify when DHCP options are valid/invalid in/outside of encapsulation */
#define NON_ENCAP_OPT in_encapsulated_options == 0 &&
@@ -164,11 +159,6 @@ struct arptable_t {
uint8_t node[6];
} PACKED;
-struct igmptable_t {
- in_addr group;
- unsigned long time;
-} PACKED;
-
#define KERNEL_BUF (BOOTP_DATA_ADDR->bootp_reply.bp_file)
#define FLOPPY_BOOT_LOCATION 0x7c00
@@ -214,14 +204,11 @@ int tcp_reset(struct iphdr *ip);
typedef int (*reply_t)(int ival, void *ptr, unsigned short ptype, struct iphdr *ip, struct udphdr *udp, struct tcphdr *tcp);
extern int await_reply P((reply_t reply, int ival, void *ptr, long timeout));
extern int decode_rfc1533 P((unsigned char *, unsigned int, unsigned int, int));
-extern void join_group(int slot, unsigned long group);
-extern void leave_group(int slot);
#define RAND_MAX 2147483647L
extern uint16_t ipchksum P((const void *ip, unsigned long len));
extern uint16_t add_ipchksums P((unsigned long offset, uint16_t sum, uint16_t new));
extern int32_t random P((void));
extern long rfc2131_sleep_interval P((long base, int exp));
-extern long rfc1112_sleep_interval P((long base, int exp));
extern void cleanup P((void));
/* osloader.c */
diff --git a/src/include/igmp.h b/src/include/igmp.h
index 2235d6c6..48753eab 100644
--- a/src/include/igmp.h
+++ b/src/include/igmp.h
@@ -1,5 +1,8 @@
-#ifndef _IGMP_H
-#define _IGMP_H
+#ifndef IGMP_H
+#define IGMP_H
+
+#include "stdint.h"
+#include "in.h"
#define IGMP_QUERY 0x11
#define IGMPv1_REPORT 0x12
@@ -7,11 +10,19 @@
#define IGMP_LEAVE 0x17
#define GROUP_ALL_HOSTS 0xe0000001 /* 224.0.0.1 Host byte order */
+#define MULTICAST_MASK 0xf0000000
+#define MULTICAST_NETWORK 0xe0000000
+
+enum {
+ IGMP_SERVER,
+ MAX_IGMP
+};
+
struct igmp {
- uint8_t type;
- uint8_t response_time;
- uint16_t chksum;
- in_addr group;
+ uint8_t type;
+ uint8_t response_time;
+ uint16_t chksum;
+ struct in_addr group;
} PACKED;
struct igmp_ip_t { /* Format of an igmp ip packet */
@@ -20,4 +31,12 @@ struct igmp_ip_t { /* Format of an igmp ip packet */
struct igmp igmp;
} PACKED;
-#endif /* _IGMP_H */
+struct igmptable_t {
+ struct in_addr group;
+ unsigned long time;
+} PACKED;
+
+extern void join_group ( int slot, unsigned long group );
+extern void leave_group ( int slot );
+
+#endif /* IGMP_H */
diff --git a/src/proto/igmp.c b/src/proto/igmp.c
index 17dae336..aad530f7 100644
--- a/src/proto/igmp.c
+++ b/src/proto/igmp.c
@@ -5,6 +5,7 @@
#include "ip.h"
#include "igmp.h"
+#include "background.h"
#include "nic.h"
#include "etherboot.h"
@@ -56,7 +57,8 @@ static void send_igmp_reports ( unsigned long now ) {
}
}
-static void process_igmp ( struct iphdr *ip, unsigned long now ) {
+static void process_igmp ( unsigned long now, unsigned short ptype __unused,
+ struct iphdr *ip ) {
struct igmp *igmp;
int i;
unsigned iplen;
@@ -110,6 +112,11 @@ static void process_igmp ( struct iphdr *ip, unsigned long now ) {
}
}
+static struct background igmp_background __background = {
+ .send = send_igmp_reports,
+ .process = process_igmp,
+};
+
void leave_group ( int slot ) {
/* Be very stupid and always send a leave group message if
* I have subscribed. Imperfect but it is standards
@@ -157,4 +164,3 @@ void join_group ( int slot, unsigned long group ) {
igmptable[slot].time = currticks();
}
}
-