Introduce files for new e1000 driver
[gpxe.git] / src / proto / igmp.c
blobef1ff714d188f5675f6f8f83718bb161ba539a91
1 /*
2 * Eric Biederman wrote this code originally.
4 */
6 #include <ip.h>
7 #include <igmp.h>
9 #if 0
11 static unsigned long last_igmpv1 = 0;
12 static struct igmptable_t igmptable[MAX_IGMP];
14 static long rfc1112_sleep_interval ( long base, int exp ) {
15 unsigned long divisor, tmo;
17 if ( exp > BACKOFF_LIMIT )
18 exp = BACKOFF_LIMIT;
19 divisor = RAND_MAX / ( base << exp );
20 tmo = random() / divisor;
21 return tmo;
24 static void send_igmp_reports ( unsigned long now ) {
25 struct igmp_ip_t igmp;
26 int i;
28 for ( i = 0 ; i < MAX_IGMP ; i++ ) {
29 if ( ! igmptable[i].time )
30 continue;
31 if ( now < igmptable[i].time )
32 continue;
34 igmp.router_alert[0] = 0x94;
35 igmp.router_alert[1] = 0x04;
36 igmp.router_alert[2] = 0;
37 igmp.router_alert[3] = 0;
38 build_ip_hdr ( igmptable[i].group.s_addr, 1, IP_IGMP,
39 sizeof ( igmp.router_alert ),
40 sizeof ( igmp ), &igmp );
41 igmp.igmp.type = IGMPv2_REPORT;
42 if ( last_igmpv1 &&
43 ( now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT ) ) {
44 igmp.igmp.type = IGMPv1_REPORT;
46 igmp.igmp.response_time = 0;
47 igmp.igmp.chksum = 0;
48 igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
49 igmp.igmp.chksum = ipchksum ( &igmp.igmp,
50 sizeof ( igmp.igmp ) );
51 ip_transmit ( sizeof ( igmp ), &igmp );
52 DBG ( "IGMP sent report to %s\n", inet_ntoa ( igmp.igmp.group ) );
53 /* Don't send another igmp report until asked */
54 igmptable[i].time = 0;
58 static void process_igmp ( unsigned long now, unsigned short ptype __unused,
59 struct iphdr *ip ) {
60 struct igmp *igmp;
61 int i;
62 unsigned iplen;
64 if ( ( ! ip ) || ( ip->protocol != IP_IGMP ) ||
65 ( nic.packetlen < ( sizeof ( struct iphdr ) +
66 sizeof ( struct igmp ) ) ) ) {
67 return;
70 iplen = ( ip->verhdrlen & 0xf ) * 4;
71 igmp = ( struct igmp * ) &nic.packet[ sizeof( struct iphdr ) ];
72 if ( ipchksum ( igmp, ntohs ( ip->len ) - iplen ) != 0 )
73 return;
75 if ( ( igmp->type == IGMP_QUERY ) &&
76 ( ip->dest.s_addr == htonl ( GROUP_ALL_HOSTS ) ) ) {
77 unsigned long interval = IGMP_INTERVAL;
79 if ( igmp->response_time == 0 ) {
80 last_igmpv1 = now;
81 } else {
82 interval = ( igmp->response_time * TICKS_PER_SEC ) /10;
85 DBG ( "IGMP received query for %s\n", inet_ntoa ( igmp->group ) );
86 for ( i = 0 ; i < MAX_IGMP ; i++ ) {
87 uint32_t group = igmptable[i].group.s_addr;
88 if ( ( group == 0 ) ||
89 ( group == igmp->group.s_addr ) ) {
90 unsigned long time;
91 time = currticks() +
92 rfc1112_sleep_interval ( interval, 0 );
93 if ( time < igmptable[i].time ) {
94 igmptable[i].time = time;
99 if ( ( ( igmp->type == IGMPv1_REPORT ) ||
100 ( igmp->type == IGMPv2_REPORT ) ) &&
101 ( ip->dest.s_addr == igmp->group.s_addr ) ) {
102 DBG ( "IGMP received report for %s\n",
103 inet_ntoa ( igmp->group ) );
104 for ( i = 0 ; i < MAX_IGMP ; i++ ) {
105 if ( ( igmptable[i].group.s_addr ==
106 igmp->group.s_addr ) &&
107 ( igmptable[i].time != 0 ) ) {
108 igmptable[i].time = 0;
114 struct background igmp_background __background = {
115 .send = send_igmp_reports,
116 .process = process_igmp,
119 void leave_group ( int slot ) {
120 /* Be very stupid and always send a leave group message if
121 * I have subscribed. Imperfect but it is standards
122 * compliant, easy and reliable to implement.
124 * The optimal group leave method is to only send leave when,
125 * we were the last host to respond to a query on this group,
126 * and igmpv1 compatibility is not enabled.
128 if ( igmptable[slot].group.s_addr ) {
129 struct igmp_ip_t igmp;
131 igmp.router_alert[0] = 0x94;
132 igmp.router_alert[1] = 0x04;
133 igmp.router_alert[2] = 0;
134 igmp.router_alert[3] = 0;
135 build_ip_hdr ( htonl ( GROUP_ALL_HOSTS ), 1, IP_IGMP,
136 sizeof ( igmp.router_alert ), sizeof ( igmp ),
137 &igmp);
138 igmp.igmp.type = IGMP_LEAVE;
139 igmp.igmp.response_time = 0;
140 igmp.igmp.chksum = 0;
141 igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
142 igmp.igmp.chksum = ipchksum ( &igmp.igmp, sizeof ( igmp ) );
143 ip_transmit ( sizeof ( igmp ), &igmp );
144 DBG ( "IGMP left group %s\n", inet_ntoa ( igmp.igmp.group ) );
146 memset ( &igmptable[slot], 0, sizeof ( igmptable[0] ) );
149 void join_group ( int slot, unsigned long group ) {
150 /* I have already joined */
151 if ( igmptable[slot].group.s_addr == group )
152 return;
153 if ( igmptable[slot].group.s_addr ) {
154 leave_group ( slot );
156 /* Only join a group if we are given a multicast ip, this way
157 * code can be given a non-multicast (broadcast or unicast ip)
158 * and still work...
160 if ( ( group & htonl ( MULTICAST_MASK ) ) ==
161 htonl ( MULTICAST_NETWORK ) ) {
162 igmptable[slot].group.s_addr = group;
163 igmptable[slot].time = currticks();
167 #endif