IGMP protocol now uses the generic background protocol mechanism.
This commit is contained in:
parent
85a380530d
commit
be7897523d
159
src/core/nic.c
159
src/core/nic.c
|
@ -21,13 +21,10 @@ Literature dealing with the network protocols:
|
||||||
#include "resolv.h"
|
#include "resolv.h"
|
||||||
#include "dev.h"
|
#include "dev.h"
|
||||||
#include "nic.h"
|
#include "nic.h"
|
||||||
|
#include "background.h"
|
||||||
#include "elf.h" /* FOR EM_CURRENT */
|
#include "elf.h" /* FOR EM_CURRENT */
|
||||||
|
|
||||||
struct arptable_t arptable[MAX_ARP];
|
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 */
|
/* Put rom_info in .nocompress section so romprefix.S can write to it */
|
||||||
struct rom_info rom __attribute__ ((section (".text16.nocompress"))) = {0,0};
|
struct rom_info rom __attribute__ ((section (".text16.nocompress"))) = {0,0};
|
||||||
static unsigned long netmask;
|
static unsigned long netmask;
|
||||||
|
@ -827,140 +824,6 @@ uint16_t tcpudpchksum(struct iphdr *ip)
|
||||||
return checksum;
|
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"
|
#include "proto_eth_slow.c"
|
||||||
|
|
||||||
|
@ -985,8 +848,8 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
|
||||||
*/
|
*/
|
||||||
for (;;) {
|
for (;;) {
|
||||||
now = currticks();
|
now = currticks();
|
||||||
|
background_send(now);
|
||||||
send_eth_slow_reports(now);
|
send_eth_slow_reports(now);
|
||||||
send_igmp_reports(now);
|
|
||||||
result = eth_poll(1);
|
result = eth_poll(1);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
/* We don't have anything */
|
/* We don't have anything */
|
||||||
|
@ -1104,8 +967,8 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
|
||||||
#endif /* MDEBUG */
|
#endif /* MDEBUG */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
background_process(now, ptype, ip);
|
||||||
process_eth_slow(ptype, now);
|
process_eth_slow(ptype, now);
|
||||||
process_igmp(ip, now);
|
|
||||||
}
|
}
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
@ -1297,20 +1160,4 @@ long rfc2131_sleep_interval(long base, int exp)
|
||||||
return tmo;
|
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 */
|
|
||||||
|
|
||||||
|
|
|
@ -130,16 +130,11 @@ enum {
|
||||||
MAX_ARP
|
MAX_ARP
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IGMP_SERVER 0
|
|
||||||
#define MAX_IGMP IGMP_SERVER+1
|
|
||||||
|
|
||||||
#define RARP_REQUEST 3
|
#define RARP_REQUEST 3
|
||||||
#define RARP_REPLY 4
|
#define RARP_REPLY 4
|
||||||
|
|
||||||
#include "in.h"
|
#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 */
|
/* Helper macros used to identify when DHCP options are valid/invalid in/outside of encapsulation */
|
||||||
#define NON_ENCAP_OPT in_encapsulated_options == 0 &&
|
#define NON_ENCAP_OPT in_encapsulated_options == 0 &&
|
||||||
|
@ -164,11 +159,6 @@ struct arptable_t {
|
||||||
uint8_t node[6];
|
uint8_t node[6];
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
struct igmptable_t {
|
|
||||||
in_addr group;
|
|
||||||
unsigned long time;
|
|
||||||
} PACKED;
|
|
||||||
|
|
||||||
#define KERNEL_BUF (BOOTP_DATA_ADDR->bootp_reply.bp_file)
|
#define KERNEL_BUF (BOOTP_DATA_ADDR->bootp_reply.bp_file)
|
||||||
|
|
||||||
#define FLOPPY_BOOT_LOCATION 0x7c00
|
#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);
|
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 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 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
|
#define RAND_MAX 2147483647L
|
||||||
extern uint16_t ipchksum P((const void *ip, unsigned long len));
|
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 uint16_t add_ipchksums P((unsigned long offset, uint16_t sum, uint16_t new));
|
||||||
extern int32_t random P((void));
|
extern int32_t random P((void));
|
||||||
extern long rfc2131_sleep_interval P((long base, int exp));
|
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));
|
extern void cleanup P((void));
|
||||||
|
|
||||||
/* osloader.c */
|
/* osloader.c */
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#ifndef _IGMP_H
|
#ifndef IGMP_H
|
||||||
#define _IGMP_H
|
#define IGMP_H
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "in.h"
|
||||||
|
|
||||||
#define IGMP_QUERY 0x11
|
#define IGMP_QUERY 0x11
|
||||||
#define IGMPv1_REPORT 0x12
|
#define IGMPv1_REPORT 0x12
|
||||||
|
@ -7,11 +10,19 @@
|
||||||
#define IGMP_LEAVE 0x17
|
#define IGMP_LEAVE 0x17
|
||||||
#define GROUP_ALL_HOSTS 0xe0000001 /* 224.0.0.1 Host byte order */
|
#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 {
|
struct igmp {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t response_time;
|
uint8_t response_time;
|
||||||
uint16_t chksum;
|
uint16_t chksum;
|
||||||
in_addr group;
|
struct in_addr group;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
struct igmp_ip_t { /* Format of an igmp ip packet */
|
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;
|
struct igmp igmp;
|
||||||
} PACKED;
|
} 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 */
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "ip.h"
|
#include "ip.h"
|
||||||
#include "igmp.h"
|
#include "igmp.h"
|
||||||
|
#include "background.h"
|
||||||
#include "nic.h"
|
#include "nic.h"
|
||||||
#include "etherboot.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;
|
struct igmp *igmp;
|
||||||
int i;
|
int i;
|
||||||
unsigned iplen;
|
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 ) {
|
void leave_group ( int slot ) {
|
||||||
/* Be very stupid and always send a leave group message if
|
/* Be very stupid and always send a leave group message if
|
||||||
* I have subscribed. Imperfect but it is standards
|
* I have subscribed. Imperfect but it is standards
|
||||||
|
@ -157,4 +164,3 @@ void join_group ( int slot, unsigned long group ) {
|
||||||
igmptable[slot].time = currticks();
|
igmptable[slot].time = currticks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue