Add an implementation for IGMP

This adds an implementation for trapping IGMP packets to the CPU
which will identify IGMPv1/2/3 packets, but handle only v3.
The implementation then inserts/updates/deletes L3 MC entries
in the L3 lookup table. The entries consist of an Ipv4
Destination IP (the IPv4 MC address), a Source IP (0.0.0.0) and
a Portmask. Note that this implementation is not VLAN aware,
as there is no hardware support in the device.

An alternative strategy is to control switching of the L2-MC packets
in which the IPv4-MC packets are transported (dst-MaC is
01:00:5e:xx:yy:zz, with xx:yy:zz corresponding to bits in the Ipv4-MC
address). This will allow to use VLAN-aware packet switching. While
code support is there for table insert/update/deletes, some further
L2 configuration is missing.

There is no support for IPv6 MC, yet.
This commit is contained in:
logicog
2025-12-15 06:54:41 +01:00
parent 96977b5d88
commit c8c524b71f
6 changed files with 310 additions and 36 deletions
+3 -4
View File
@@ -74,12 +74,11 @@ extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
struct rtl_tag { struct rtl_tag {
uint16_t tag; uint16_t tag;
uint8_t version; uint8_t version;
uint16_t dummy; uint8_t reason;
uint8_t flag; uint16_t flags;
uint16_t pmask; uint16_t pmask; // A bit mask for a TX pkt, 4-bit port-number for RX
}; };
// Headers for calls in the common code area (HOME/BANK0) // Headers for calls in the common code area (HOME/BANK0)
void print_string(__code char *p); void print_string(__code char *p);
void print_long(__xdata uint32_t a); void print_long(__xdata uint32_t a);
+289 -28
View File
@@ -6,6 +6,8 @@
// #define REGDBG // #define REGDBG
// #define DEBUG // #define DEBUG
#define IPMC_USES_L3MC
#include <stdint.h> #include <stdint.h>
#include "rtl837x_common.h" #include "rtl837x_common.h"
#include "rtl837x_sfr.h" #include "rtl837x_sfr.h"
@@ -14,9 +16,71 @@
#include "machine.h" #include "machine.h"
extern __code struct machine machine; extern __code struct machine machine;
#include "uip.h"
#pragma codeseg BANK1
#pragma constseg BANK1
extern __xdata uint8_t cpuPort; extern __xdata uint8_t cpuPort;
extern __xdata uint8_t sfr_data[4]; extern __xdata uint8_t sfr_data[4];
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
__xdata uint16_t idx;
#ifdef IPMC_USES_L3MC
struct ipmc_table_entry {
uint8_t sip[4];
uint8_t dip[4];
uint16_t pmask;
uint8_t igmp_index;
uint8_t igmp_asic;
};
static __xdata struct ipmc_table_entry entry;
#else
struct l2mc_table_entry {
uint8_t mac[6];
uint16_t vlan;
uint16_t pmask;
uint8_t is_svl;
uint8_t igmp_index;
uint8_t igmp_asic;
};
static __xdata struct l2mc_table_entry entry;
#endif
struct igmp_pkt {
uint8_t ipv4mc_addr[6];
uint8_t src_addr[6];
struct rtl_tag rtl_tag;
uint16_t ipv4_tag;
uint8_t hlen;
uint8_t dscp;
uint16_t len;
uint16_t id;
uint16_t flags;
uint8_t ttl;
uint8_t protocol;
uint16_t checksum;
uint8_t src_ip[4];
uint8_t dst_ip[4];
uint8_t ip_opt;
uint8_t ip_len;
uint16_t ra;
uint8_t igmp_type;
uint8_t igmp_res1;
uint16_t igmp_checksum;
uint16_t igmp_res2;
uint16_t igmp_records;
uint8_t igmp_rtype;
uint8_t igmp_auxlen;
uint16_t igmp_nsrc;
uint8_t mc_ip[4];
};
#define IGMP_I ((__xdata struct igmp_pkt *)&uip_buf[0])
void igmp_setup(void) __banked void igmp_setup(void) __banked
{ {
uint8_t i; uint8_t i;
@@ -25,20 +89,9 @@ void igmp_setup(void) __banked
REG_SET(RTL837X_IPV4_PORT_MC_LM_ACT, LOOKUP_MISS_FLOOD); REG_SET(RTL837X_IPV4_PORT_MC_LM_ACT, LOOKUP_MISS_FLOOD);
REG_SET(RTL837X_IPV6_PORT_MC_LM_ACT, LOOKUP_MISS_FLOOD); REG_SET(RTL837X_IPV6_PORT_MC_LM_ACT, LOOKUP_MISS_FLOOD);
// For now, forward all unkown MC pkts (2 bits per port. 00: flood via floodmask, 01: drop, 10: trap, 11: to rport)
REG_SET(RTL837X_MC_LOOKUPMISS_ACTIONS, 0x00000000); //0x4f78
// Define ports where unknown MC addresses are flooded to: // Define ports where unknown MC addresses are flooded to:
REG_SET(RTL837X_MC_FLOODMASK, machine.isRTL8373 ? PMASK_9 : PMASK_6); REG_SET(RTL837X_IPV4_UNKN_MC_FLD_PMSK, machine.isRTL8373? PMASK_9: PMASK_6);
REG_SET(RTL837X_IPV6_UNKN_MC_FLD_PMSK, machine.isRTL8373? PMASK_9: PMASK_6);
// Define ports where unknown MC addresses are flooded to:
if (isRTL8373) {
REG_SET(RTL837X_IPV4_UNKN_MC_FLD_PMSK, PMASK_9);
REG_SET(RTL837X_IPV6_UNKN_MC_FLD_PMSK, PMASK_9);
} else {
REG_SET(RTL837X_IPV4_UNKN_MC_FLD_PMSK, PMASK_6);
REG_SET(RTL837X_IPV6_UNKN_MC_FLD_PMSK, PMASK_6);
}
// Enable lookup of IPv4 MC addresses in table // Enable lookup of IPv4 MC addresses in table
reg_bit_set(RTL837X_L2_CTRL, L2_CTRL_LUT_IPMC_HASH); reg_bit_set(RTL837X_L2_CTRL, L2_CTRL_LUT_IPMC_HASH);
@@ -60,46 +113,43 @@ void igmp_setup(void) __banked
* 00: handle in HW by ASIC * 00: handle in HW by ASIC
* 01: flood * 01: flood
* 10: trap * 10: trap
* 10: drop * 11: drop
* Bits 0-1: IGMPv1, 2-3: IGMPv2, 4-5: IGMPv3, 6-7: MLDv1 (for IPv6), 8-9: MLDv2 * Bits 0-1: IGMPv1, 2-3: IGMPv2, 4-5: IGMPv3, 6-7: MLDv1 (for IPv6), 8-9: MLDv2
* For now the IGMP protocols are flooded (01), MLD which MAC-based is handled by ASIC * For now the IGMP protocols are flooded (01), MLD which MAC-based is handled by ASIC
* All messages are allowed and maximum MC group is 0xff * All messages are allowed and maximum MC group is 0xff
*/ */
for (i = minPort; i <= maxPort; i++) for (i = machine.min_port; i <= machine.max_port; i++) {
print_byte(i); write_char(':');
REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), IGMP_MAX_GROUP | IGMP_PROTOCOL_ENABLE | IGMP_FLOOD); REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), IGMP_MAX_GROUP | IGMP_PROTOCOL_ENABLE | IGMP_FLOOD);
write_char('\n');
}
// Allow all physical ports to be dynamic router ports /* // Allow all physical ports to be dynamic router ports
reg_read_m(RTL837X_IGMP_ROUTER_PORT); reg_read_m(RTL837X_IGMP_ROUTER_PORT);
if (isRTL8373) { if (isRTL8373) {
REG_WRITE(RTL837X_IGMP_ROUTER_PORT, PMASK_9 >> 8, PMASK_9 & 0xff, sfr_data[1], sfr_data[0]); REG_WRITE(RTL837X_IGMP_ROUTER_PORT, PMASK_9 >> 8, PMASK_9 & 0xff, sfr_data[1], sfr_data[0]);
} else { } else {
REG_WRITE(RTL837X_IGMP_ROUTER_PORT, PMASK_6 >> 8, PMASK_6 & 0xff, sfr_data[1], sfr_data[0]); REG_WRITE(RTL837X_IGMP_ROUTER_PORT, PMASK_6 >> 8, PMASK_6 & 0xff, sfr_data[1], sfr_data[0]);
} }
*/
} }
void igmp_enable(void) __banked void igmp_enable(void) __banked
{ {
uint8_t i;
print_string("igmp_enable called\n"); print_string("igmp_enable called\n");
// Configure trapping of unhandled IGMP protocol packets to CPU // Configure trapping of unhandled IGMP protocol packets to CPU
REG_SET(RTL837X_IGMP_TRAP_CFG, IGMP_CPU_PORT | IGMP_TRAP_PRIORITY); REG_SET(RTL837X_IGMP_TRAP_CFG, IGMP_CPU_PORT | IGMP_TRAP_PRIORITY);
// Drop unknown IP-MC packets // Drop unknown IP-MC packets
if (isRTL8373) { REG_SET(RTL837X_IPV4_PORT_MC_LM_ACT, machine.isRTL8373? LOOKUP_MISS_DROP_9: LOOKUP_MISS_DROP_6);
REG_SET(RTL837X_IPV4_PORT_MC_LM_ACT, LOOKUP_MISS_DROP_9); // REG_SET(RTL837X_IPV6_PORT_MC_LM_ACT, machine.isRTL8373? LOOKUP_MISS_DROP_9: LOOKUP_MISS_DROP_6);
REG_SET(RTL837X_IPV6_PORT_MC_LM_ACT, LOOKUP_MISS_DROP_9);
} else {
REG_SET(RTL837X_IPV4_PORT_MC_LM_ACT, LOOKUP_MISS_DROP_6);
REG_SET(RTL837X_IPV6_PORT_MC_LM_ACT, LOOKUP_MISS_DROP_6);
}
// Configure per-port IGMP configuration, bits 0-10 enable MC protocol snooping, // Configure per-port IGMP configuration, bits 0-10 enable MC protocol snooping,
// bits 16-24 configure max MC group used by that port. Trap to CPU (10) // bits 16-24 configure max MC group used by that port. Trap to CPU (10)
for (i = minPort; i <= maxPort; i++) for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), IGMP_MAX_GROUP | IGMP_PROTOCOL_ENABLE | IGMP_ASIC); REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), IGMP_MAX_GROUP | IGMP_PROTOCOL_ENABLE | IGMP_TRAP);
}
} }
@@ -114,3 +164,214 @@ void igmp_router_port_set(uint16_t pmask) __banked
print_sfr_data(); write_char('\n'); print_sfr_data(); write_char('\n');
REG_WRITE(RTL837X_IGMP_ROUTER_PORT, sfr_data[0], sfr_data[1], pmask >> 8, pmask & 0xff); REG_WRITE(RTL837X_IGMP_ROUTER_PORT, sfr_data[0], sfr_data[1], pmask >> 8, pmask & 0xff);
} }
/*
* IGMP show the current entries and state
*/
void igmp_show(void) __banked
{
print_string("igmp_show called\n");
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
write_char('0' + i); write_char(':');
reg_read_m(RTL837X_IGMP_PORT_CFG + (i << 2));
print_sfr_data();
write_char('\n');
}
// TODO: print all L3MC entries in the table
}
#ifdef IPMC_USES_L3MC
void entry_to_l3mc(void)
{
REG_WRITE(RTL837x_TBL_DATA_IN_A, entry.sip[0], entry.sip[1], entry.sip[2], entry.sip[3]);
REG_WRITE(RTL837x_TBL_DATA_IN_B, ((entry.pmask & 0x3) << 6) | (entry.dip[0] & 0xf) | 0x10, entry.dip[1], entry.dip[2], entry.dip[3]);
REG_WRITE(RTL837x_TBL_DATA_IN_C, 0x00, entry.igmp_asic & 1, entry.igmp_index, entry.pmask >> 2);
}
#else
void entry_to_l2mc(void)
{
// R5cb8-5e004201 R5cbc-20010100 R5cc0-00000020 R5cac-00000403
REG_WRITE(RTL837x_TBL_DATA_IN_A, entry.mac[2], entry.mac[3], entry.mac[4], entry.mac[5]);
REG_WRITE(RTL837x_TBL_DATA_IN_B, 0x20 | ((entry.pmask & 0x3) << 6) | (entry.vlan >> 8), entry.vlan & 0xff, entry.mac[0], entry.mac[1]);
REG_WRITE(RTL837x_TBL_DATA_IN_C, 0x00, entry.igmp_asic & 1, entry.igmp_index, entry.pmask >> 2);
}
#endif
void igmp_packet_handler(void) __banked
{
// By default we do not send anything out
uip_len = 0;
#ifdef DEBUG
print_string("\nIPv4 MC packet:\n");
for (uint8_t i = 0; i < 80; i++) {
print_byte(uip_buf[i]);
write_char(' ');
}
write_char('\n');
#endif
if (IGMP_I->protocol != 2)
return;
#ifdef DEBUG
print_string("Found IGMP, type: "); print_byte(IGMP_I->igmp_type); write_char('\n');
#endif
// We react to IGMPv1/v2 and v3 membership reports
if (!(IGMP_I->igmp_type == 0x12 || IGMP_I->igmp_type == 0x16 || IGMP_I->igmp_type == 0x22))
return;
#ifdef DEBUG
print_string("IGMP membership report, type "); print_byte(IGMP_I->igmp_rtype); write_char('\n');
#endif
#ifdef IPMC_USES_L3MC
memset(&entry, 0, sizeof(struct ipmc_table_entry));
// For IPv4 MC, the Source-IP is 0.0.0.0
entry.sip[0] = 0x00; entry.sip[1] = 0x00; entry.sip[2] = 0x00; entry.sip[3] = 0x00;
// For IPv4 MC, the Destination-IP is the IPv4 MC address
entry.dip[0] = IGMP_I->mc_ip[0]; entry.dip[1] = IGMP_I->mc_ip[1]; entry.dip[2] = IGMP_I->mc_ip[2]; entry.dip[3] = IGMP_I->mc_ip[3];
entry_to_l3mc();
#else
/* The L2 Multicast MAC for IP-Multicast is 01:00:5e:xx:yy:zz, where
* xx = MC_IP[1] & 0x7f
* yy = MC_IP[2]
* zz = MC_IP[3]
*/
memset(&entry, 0, sizeof(struct l2mc_table_entry));
entry.mac[0] = 0x01; entry.mac[1] = 0x00; entry.mac[2] = 0x5e;
entry.mac[3] = IGMP_I->mc_ip[1] & 0x7f; entry.mac[4] = IGMP_I->mc_ip[2]; entry.mac[5] = IGMP_I->mc_ip[3];
entry.vlan = 1; //TODO: Get this out of the packet and compare with VLAN table!
entry_to_ipmc();
#endif
// Wait for any pending Table operations to end
do {
reg_read_m(RTL837X_TBL_CTRL);
} while (sfr_data[3] & 1);
reg_read_m(RTL837x_TBL_DATA_0);
#ifdef DEBUG
print_sfr_data();
#endif
sfr_data[2] &= 0x3f; // Sets the Read-method to 0 (why MAC-lookup?) and clear the CLEAR-Entry bit
sfr_data[1] &= 0xf8;
reg_write_m(RTL837x_TBL_DATA_0);
#ifdef DEBUG
print_string(" l2 ctrl now: ");
print_sfr_data();
#endif
// First try to find entry to see whether it needs to be updated
REG_WRITE(RTL837X_TBL_CTRL, 0x00, 0x00, TBL_L2_UNICAST, TBL_EXECUTE);
do {
reg_read_m(RTL837X_TBL_CTRL);
} while (sfr_data[3] & 0x1);
#ifdef DEBUG
print_string("\nsearch done\n");
print_string("Table data searched:\n");
reg_read_m(RTL837x_TBL_DATA_IN_A);
print_sfr_data(); write_char(' ');
reg_read_m(RTL837x_TBL_DATA_IN_B);
print_sfr_data(); write_char(' ');
reg_read_m(RTL837x_TBL_DATA_IN_C);
print_sfr_data(); write_char('\n');
print_string("Table data gotten:\n");
reg_read_m(RTL837x_L2_DATA_OUT_A); write_char(' ');
print_sfr_data();
reg_read_m(RTL837x_L2_DATA_OUT_B);
print_sfr_data(); write_char(' ');
reg_read_m(RTL837x_L2_DATA_OUT_C);
print_sfr_data(); write_char('\n');
print_string("Result: ");
#endif
reg_read_m(RTL837x_TBL_DATA_0);
#ifdef DEBUG
print_sfr_data();
#endif
idx = ((sfr_data[2] & 0xf) << 8) | sfr_data[3];
if (IGMP_I->igmp_rtype == 0x4) {// Join group
if (sfr_data[2] & 0x10) {
print_string("\nIGMP-Entry FOUND\n");
reg_read_m(RTL837x_L2_DATA_OUT_B);
entry.pmask = sfr_data[0] >> 6;
reg_read_m(RTL837x_L2_DATA_OUT_C);
entry.pmask |= ((uint16_t)sfr_data[3]) << 2;
}
// Update (found) entry with portmask from trapped Packet
entry.pmask |= (1L << (IGMP_I->rtl_tag.pmask >> 8)); // Swap bytes from network order, only 4 LSB count
// print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n');
} else if (IGMP_I->igmp_rtype == 0x3){ // Leave group
if (sfr_data[2] & 0x10) {
print_string("\nIGMP_Entry FOUND\n");
reg_read_m(RTL837x_L2_DATA_OUT_B);
entry.pmask = sfr_data[0] >> 6;
reg_read_m(RTL837x_L2_DATA_OUT_C);
entry.pmask |= ((uint16_t)sfr_data[3]) << 2;
#ifdef DEBUG
print_string("Portmask: ");
print_short(entry.pmask);
print_string("Index: ");
print_short(idx);
write_char('\n');
#endif
// Remove portmask of IGMP packet from entry
entry.pmask &= ~(1L << (IGMP_I->rtl_tag.pmask >> 8)); // Swap bytes from network order, only 4 LSB count
// print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n');
} else {
print_string("IGMP Entry already deleted\n");
return;
}
if (!entry.pmask && idx) { // No more ports in that group and an actual entry?
// Delete Entry
reg_read_m(RTL837x_TBL_DATA_0);
sfr_data[1] |= 0x04; // Clear entry
reg_write_m(RTL837x_TBL_DATA_0);
REG_WRITE(RTL837X_TBL_CTRL, idx >> 8, idx & 0xff, TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE);
do {
reg_read_m(RTL837X_TBL_CTRL);
} while (sfr_data[3] & 0x1);
print_string("IGMP Entry deleted\n");
return;
}
} else { // Unknown message: ignore.
return;
}
if (!entry.pmask)
return;
print_string("Updating IGMP entry\n");
// Write the updated entry
#ifdef IPMC_USES_L3MC
entry_to_l3mc();
#else
entry_to_ipmc();
#endif
reg_read_m(RTL837x_TBL_DATA_0);
#ifdef DEBUG
print_sfr_data();
#endif
sfr_data[2] &= 0x3f; // Set the Read-method to 0 and clear the CLEAR-Entry bit
sfr_data[1] &= 0xf8;
reg_write_m(RTL837x_TBL_DATA_0);
#ifdef DEBUG
print_string(" l2 ctrl now: ");
print_sfr_data();
#endif
reg_read_m(RTL837X_TBL_CTRL);
REG_WRITE(RTL837X_TBL_CTRL, sfr_data[0], sfr_data[1], TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE);
do {
reg_read_m(RTL837X_TBL_CTRL);
} while (sfr_data[3] & 0x1);
#ifdef DEBUG
print_string("\nupdate done\n");
print_string("Table data written:\n");
reg_read_m(RTL837x_TBL_DATA_IN_A);
print_sfr_data(); write_char(' ');
reg_read_m(RTL837x_TBL_DATA_IN_B);
print_sfr_data(); write_char(' ');
reg_read_m(RTL837x_TBL_DATA_IN_C);
print_sfr_data(); write_char('\n');
print_string("Result: ");
reg_read_m(RTL837x_TBL_DATA_0);
print_sfr_data();
#endif
}
+3
View File
@@ -5,5 +5,8 @@
void igmp_setup(void) __banked; void igmp_setup(void) __banked;
void igmp_enable(void) __banked; void igmp_enable(void) __banked;
void igmp_router_port_set(uint16_t pmask) __banked;
void igmp_packet_handler(void) __banked;
void igmp_show(void) __banked;
#endif #endif
+3
View File
@@ -127,6 +127,8 @@
#define RTL837x_L2_DATA_OUT_B 0x5cd0 #define RTL837x_L2_DATA_OUT_B 0x5cd0
#define RTL837x_L2_DATA_OUT_C 0x5cd4 #define RTL837x_L2_DATA_OUT_C 0x5cd4
#define RTL837x_TBL_DATA_IN_A 0x5cb8 #define RTL837x_TBL_DATA_IN_A 0x5cb8
#define RTL837x_TBL_DATA_IN_B 0x5cbc
#define RTL837x_TBL_DATA_IN_C 0x5cc0
#define RTL837x_PVID_BASE_REG 0x4e1c #define RTL837x_PVID_BASE_REG 0x4e1c
#define RTL837x_L2_TBL_FLUSH_CTRL 0x53d4 #define RTL837x_L2_TBL_FLUSH_CTRL 0x53d4
@@ -186,6 +188,7 @@
#define RTL837X_IGMP_PORT_CFG 0x52a0 #define RTL837X_IGMP_PORT_CFG 0x52a0
#define IGMP_MAX_GROUP 0x00ff0000 #define IGMP_MAX_GROUP 0x00ff0000
#define IGMP_PROTOCOL_ENABLE 0x00007c00 #define IGMP_PROTOCOL_ENABLE 0x00007c00
#define IGMP_TRAP 0x0000002a
#define IGMP_FLOOD 0x00000015 #define IGMP_FLOOD 0x00000015
#define IGMP_ASIC 0x00000000 #define IGMP_ASIC 0x00000000
#define RTL837X_IGMP_ROUTER_PORT 0x529c #define RTL837X_IGMP_ROUTER_PORT 0x529c
+2 -2
View File
@@ -151,8 +151,8 @@ void stp_cnf_send(uint8_t port)
STP_O->rtl_tag.tag = HTONS(0x8899); STP_O->rtl_tag.tag = HTONS(0x8899);
STP_O->rtl_tag.version = 0x04; STP_O->rtl_tag.version = 0x04;
STP_O->rtl_tag.dummy = 0x0000; STP_O->rtl_tag.reason = 0x00;
STP_O->rtl_tag.flag = 0x20; // WHY ??? STP_O->rtl_tag.flags = 0x0020; // Disable L2 learning
STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << port); STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << port);
STP_O->msg_len = HTONS(0x27); STP_O->msg_len = HTONS(0x27);
+10 -2
View File
@@ -849,6 +849,8 @@ void handle_rx(void)
rx_packet_vlan |= uip_buf[12 + RTL_TAG_SIZE + 3]; rx_packet_vlan |= uip_buf[12 + RTL_TAG_SIZE + 3];
#ifdef RXTXDBG #ifdef RXTXDBG
print_string(" RX-VLAN: "); print_short(rx_packet_vlan); write_char('\n'); print_string(" RX-VLAN: "); print_short(rx_packet_vlan); write_char('\n');
print_string(" RX dst: "); print_byte(uip_buf[0]); print_byte(uip_buf[1]); print_byte(uip_buf[2]);
print_byte(uip_buf[3]); print_byte(uip_buf[4]); print_byte(uip_buf[5]); write_char('\n');
#endif #endif
if (stpEnabled && uip_buf[0] == 0x01 && uip_buf[1] == 0x80 && uip_buf[2] == 0xc2 // STP packet? if (stpEnabled && uip_buf[0] == 0x01 && uip_buf[1] == 0x80 && uip_buf[2] == 0xc2 // STP packet?
&& uip_buf[3] == 0x00 && uip_buf[4] == 0x00 && uip_buf[5] == 0x00) { && uip_buf[3] == 0x00 && uip_buf[4] == 0x00 && uip_buf[5] == 0x00) {
@@ -857,13 +859,19 @@ void handle_rx(void)
print_string("STP TX\n"); print_string("STP TX\n");
tcpip_output(); tcpip_output();
} }
} else if (uip_buf[0] == 0x01 && uip_buf[1] == 0x00 && uip_buf[2] == 0x5e // IPv4-MC packet?
&& uip_buf[3] == 0x00 && uip_buf[4] == 0x00 && uip_buf[5] == 0x16) {
igmp_packet_handler();
if (uip_len) {
tcpip_output();
}
} else if (uip_buf[ETHERTYPE_OFFSET] == 0x08 && uip_buf[ETHERTYPE_OFFSET + 1] == 0x06) { // ARP? } else if (uip_buf[ETHERTYPE_OFFSET] == 0x08 && uip_buf[ETHERTYPE_OFFSET + 1] == 0x06) { // ARP?
uip_arp_arpin(); uip_arp_arpin();
if (uip_len) { if (uip_len) {
tcpip_output(); tcpip_output();
} }
} else if (uip_buf[ETHERTYPE_OFFSET] == 0x08 && uip_buf[ETHERTYPE_OFFSET + 1] == 0x00) { } else if (uip_buf[ETHERTYPE_OFFSET] == 0x08 && uip_buf[ETHERTYPE_OFFSET + 1] == 0x00) { // TCP?
uip_arp_ipin(); uip_arp_ipin(); // Learn MAC addresses in TCP packets
uip_input(); uip_input();
if (uip_len) { if (uip_len) {
// Add ethernet frame // Add ethernet frame