I am converting an ICMPv6 RS packet into an RA one and send it back, but I can not get the calculations of the ICMPv6 checksum to work correctly, wireshark keeps detecting as being wrong, what am I missing here?
header icmpv6_t {
bit<8> type;
bit<8> code;
bit<16> checksum;
}
header ndp_rs_t { //Router Solicitation
bit<32> flags; //represents the reserved fields in the RS pkts
}
header ndp_ra_t { // Router Advertisement
bit<8> cur_hop_limit; // Current Hop Limit
bit<8> auto_config_flags; // Autoconfiguration flag (1bit) m_flag, (1bit) o_flag, (6bits) reserved_flags)
bit<16> router_lifetime; // Lifetime of the router (in seconds)
bit<32> reachable_time; // Time a node assumes a neighbor is reachable
bit<32> retrans_timer; // Time between retransmitted Neighbor Solicitation messages
}
header ndp_option_t { //Represents the ICMPv6 Options field
bit<8> type;
bit<8> length;
bit<48> value;
}
/*
* NDP router solicitation reply table and actions.
* Handles NDP router solicitation message and send router advertisement to the sender.
*/
action ndp_rs_to_ra(mac_addr_t my_router_mac, ipv6_addr_t my_router_ipv6) {
// Ethernet
hdr.ethernet.dst_addr = hdr.ethernet.src_addr;
hdr.ethernet.src_addr = my_router_mac;
// IPv6
hdr.ipv6.dst_addr = hdr.ipv6.src_addr;
hdr.ipv6.src_addr = my_router_ipv6;
hdr.ipv6.payload_len = 16w24; // value in bytes, ICMPv6 + NDP RA + NDP Option length (32 + 96 + 64 = 192 bits = 24 bytes)
hdr.ipv6.next_header = PROTO_ICMPV6;
// ICMPv6
hdr.icmpv6.type = ICMP6_TYPE_RA; // Router Advertisement
// RA fields
hdr.ndp_ra.setValid();
hdr.ndp_ra.cur_hop_limit = 64; // Example default
hdr.ndp_ra.auto_config_flags = 0; // m,o, and reserved flags
hdr.ndp_ra.router_lifetime = 1800; // 30 minutes
hdr.ndp_ra.reachable_time = 0; // Set as needed (no suggestion)
hdr.ndp_ra.retrans_timer = 0; // Set as needed (use your own value)
// Optional: Include link-layer address option
hdr.ndp_option.setValid();
hdr.ndp_option.type = NDP_OPT_TARGET_LL_ADDR;
hdr.ndp_option.length = 1; // Length of NDP Options Header in 8-byte (64 bits) units
hdr.ndp_option.value = my_router_mac;
// Send back out the same port
standard_metadata.egress_spec = standard_metadata.ingress_port;
// set old header as invalid
hdr.ndp_rs.setInvalid();
}
update_checksum(hdr.ndp_ra.isValid(),
{
// IPv6 Pseudo-header fields
hdr.ipv6.src_addr, // IPv6 source address
hdr.ipv6.dst_addr, // IPv6 destination address
hdr.ipv6.payload_len, // IPv6 payload length
hdr.ipv6.next_header, // Next Header (58 for ICMPv6)
// ICMPv6 fields (header and body)
hdr.icmpv6.type, // ICMPv6 type
hdr.icmpv6.code, // ICMPv6 code
16w0, // checksum field placeholder (zeroed out)
hdr.ndp_ra.cur_hop_limit, // Router Advertisement hop limit
hdr.ndp_ra.auto_config_flags, // Router Advertisement auto configuration flags
hdr.ndp_ra.router_lifetime, // Router Advertisement lifetime
hdr.ndp_ra.reachable_time, // Router Advertisement reachable time
hdr.ndp_ra.retrans_timer, // Router Advertisement retransmission timer
hdr.ndp_option.type, // NDP option type
hdr.ndp_option.length, // NDP option length
hdr.ndp_option.value // NDP option value
},
hdr.icmpv6.checksum, // The field to store the calculated checksum
HashAlgorithm.csum16 // Use the 16-bit checksum algorithm
);
I suspected that I may have changed the IPv6 Payload Length to a wrong value but after some tests it seems fine:
Frame 7: 78 bytes on wire (624 bits), 78 bytes captured (624 bits) on interface r1-eth11, id 0
Section number: 1
Interface id: 0 (r1-eth11)
Interface name: r1-eth11
Encapsulation type: Ethernet (1)
Arrival Time: Apr 12, 2025 14:35:57.287722105 WEST
UTC Arrival Time: Apr 12, 2025 13:35:57.287722105 UTC
Epoch Arrival Time: 1744464957.287722105
[Time shift for this packet: 0.000000000 seconds]
[Time delta from previous captured frame: 0.001876865 seconds]
[Time delta from previous displayed frame: 0.001876865 seconds]
[Time since reference or first frame: 13.074830438 seconds]
Frame Number: 7
Frame Length: 78 bytes (624 bits)
Capture Length: 78 bytes (624 bits)
[Frame is marked: False]
[Frame is ignored: False]
[Protocols in frame: eth:ethertype:ipv6:icmpv6]
[Coloring Rule Name: ICMP]
[Coloring Rule String: icmp || icmpv6]
Ethernet II, Src: Intel_00:00:01 (00:aa:00:00:00:01), Dst: 7e:8c:e7:f4:20:6e (7e:8c:e7:f4:20:6e)
Destination: 7e:8c:e7:f4:20:6e (7e:8c:e7:f4:20:6e)
Address: 7e:8c:e7:f4:20:6e (7e:8c:e7:f4:20:6e)
.... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
.... ...0 .... .... .... .... = IG bit: Individual address (unicast)
Source: Intel_00:00:01 (00:aa:00:00:00:01)
Address: Intel_00:00:01 (00:aa:00:00:00:01)
.... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
.... ...0 .... .... .... .... = IG bit: Individual address (unicast)
Type: IPv6 (0x86dd)
Internet Protocol Version 6, Src: 2001:1:1::ff, Dst: fe80::7c8c:e7ff:fef4:206e
0110 .... = Version: 6
.... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
.... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
.... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
.... 0000 0000 0000 0000 0000 = Flow Label: 0x00000
Payload Length: 24
Next Header: ICMPv6 (58)
Hop Limit: 255
Source Address: 2001:1:1::ff
Destination Address: fe80::7c8c:e7ff:fef4:206e
Internet Control Message Protocol v6
Type: Router Advertisement (134)
Code: 0
Checksum: 0x6da5 incorrect, should be 0x8c86
[Expert Info (Warning/Checksum): Bad checksum [should be 0x8c86]]
[Bad checksum [should be 0x8c86]]
[Severity level: Warning]
[Group: Checksum]
[Checksum Status: Bad]
Cur hop limit: 64
Flags: 0x00, Prf (Default Router Preference): Medium
0... .... = Managed address configuration: Not set
.0.. .... = Other configuration: Not set
..0. .... = Home Agent: Not set
...0 0... = Prf (Default Router Preference): Medium (0)
.... .0.. = ND Proxy: Not set
.... ..00 = Reserved: 0
Router lifetime (s): 1800
Reachable time (ms): 0
Retrans timer (ms): 0
ICMPv6 Option (Target link-layer address : 00:aa:00:00:00:01)
Type: Target link-layer address (2)
Length: 1 (8 bytes)
Link-layer address: Intel_00:00:01 (00:aa:00:00:00:01)