You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

igmp.c 4.6KB

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