@@ -1183,6 +1183,129 @@ fn test_raw_socket_tx_fragmentation(#[case] medium: Medium) {
11831183 }
11841184}
11851185
1186+ #[ rstest]
1187+ #[ case( Medium :: Ip ) ]
1188+ #[ cfg( all(
1189+ feature = "socket-raw" ,
1190+ feature = "proto-ipv4-fragmentation" ,
1191+ feature = "medium-ip"
1192+ ) ) ]
1193+ #[ case( Medium :: Ethernet ) ]
1194+ #[ cfg( all(
1195+ feature = "socket-raw" ,
1196+ feature = "proto-ipv4-fragmentation" ,
1197+ feature = "medium-ethernet"
1198+ ) ) ]
1199+ fn test_raw_socket_rx_fragmentation ( #[ case] medium : Medium ) {
1200+ use crate :: wire:: { IpProtocol , IpVersion , Ipv4Address , Ipv4Packet , Ipv4Repr } ;
1201+
1202+ let ( mut iface, mut sockets, _device) = setup ( medium) ;
1203+
1204+ // Raw socket bound to IPv4 and a custom protocol.
1205+ let packets = 1 ;
1206+ let rx_buffer = raw:: PacketBuffer :: new ( vec ! [ raw:: PacketMetadata :: EMPTY ; packets] , vec ! [ 0 ; 64 ] ) ;
1207+ let tx_buffer = raw:: PacketBuffer :: new ( vec ! [ raw:: PacketMetadata :: EMPTY ; packets] , vec ! [ 0 ; 64 ] ) ;
1208+ let raw_socket = raw:: Socket :: new (
1209+ Some ( IpVersion :: Ipv4 ) ,
1210+ Some ( IpProtocol :: Unknown ( 99 ) ) ,
1211+ rx_buffer,
1212+ tx_buffer,
1213+ ) ;
1214+ let handle = sockets. add ( raw_socket) ;
1215+
1216+ // Build two IPv4 fragments that together form one packet.
1217+ let src_addr = Ipv4Address :: new ( 127 , 0 , 0 , 2 ) ;
1218+ let dst_addr = Ipv4Address :: new ( 127 , 0 , 0 , 1 ) ;
1219+ let proto = IpProtocol :: Unknown ( 99 ) ;
1220+ let ident: u16 = 0x1234 ;
1221+
1222+ let total_payload_len = 30usize ;
1223+ let first_payload_len = 24usize ; // must be a multiple of 8
1224+ let last_payload_len = total_payload_len - first_payload_len;
1225+
1226+ // Helper to build one fragment as on-the-wire bytes
1227+ let build_fragment = |payload_len : usize ,
1228+ more_frags : bool ,
1229+ frag_offset_octets : u16 ,
1230+ payload_byte : u8 |
1231+ -> Vec < u8 > {
1232+ let repr = Ipv4Repr {
1233+ src_addr,
1234+ dst_addr,
1235+ next_header : proto,
1236+ hop_limit : 64 ,
1237+ payload_len,
1238+ } ;
1239+ let header_len = repr. buffer_len ( ) ;
1240+ let mut bytes = vec ! [ 0u8 ; header_len + payload_len] ;
1241+ {
1242+ let mut pkt = Ipv4Packet :: new_unchecked ( & mut bytes[ ..] ) ;
1243+ repr. emit ( & mut pkt, & ChecksumCapabilities :: default ( ) ) ;
1244+ pkt. set_ident ( ident) ;
1245+ pkt. set_dont_frag ( false ) ;
1246+ pkt. set_more_frags ( more_frags) ;
1247+ pkt. set_frag_offset ( frag_offset_octets) ;
1248+ // Recompute checksum after changing fragmentation fields.
1249+ pkt. fill_checksum ( ) ;
1250+ }
1251+ // Fill payload with a simple pattern for validation
1252+ for b in & mut bytes[ header_len..] {
1253+ * b = payload_byte;
1254+ }
1255+ bytes
1256+ } ;
1257+
1258+ let frag1_bytes = build_fragment ( first_payload_len, true , 0 , 0xAA ) ;
1259+ let frag2_bytes = build_fragment ( last_payload_len, false , first_payload_len as u16 , 0xBB ) ;
1260+
1261+ let frag1 = Ipv4Packet :: new_unchecked ( & frag1_bytes[ ..] ) ;
1262+ let frag2 = Ipv4Packet :: new_unchecked ( & frag2_bytes[ ..] ) ;
1263+
1264+ // First fragment alone should not be delivered to the raw socket.
1265+ assert_eq ! (
1266+ iface. inner. process_ipv4(
1267+ & mut sockets,
1268+ PacketMeta :: default ( ) ,
1269+ HardwareAddress :: default ( ) ,
1270+ & frag1,
1271+ & mut iface. fragments
1272+ ) ,
1273+ None
1274+ ) ;
1275+ {
1276+ let socket = sockets. get_mut :: < raw:: Socket > ( handle) ;
1277+ assert ! ( !socket. can_recv( ) ) ;
1278+ }
1279+
1280+ // After the last fragment, the reassembled packet should be delivered.
1281+ assert_eq ! (
1282+ iface. inner. process_ipv4(
1283+ & mut sockets,
1284+ PacketMeta :: default ( ) ,
1285+ HardwareAddress :: default ( ) ,
1286+ & frag2,
1287+ & mut iface. fragments
1288+ ) ,
1289+ None
1290+ ) ;
1291+
1292+ // Validate the raw socket received one defragmented packet with correct payload.
1293+ let socket = sockets. get_mut :: < raw:: Socket > ( handle) ;
1294+ assert ! ( socket. can_recv( ) ) ;
1295+ let data = socket. recv ( ) . expect ( "raw socket should have a packet" ) ;
1296+ let packet = Ipv4Packet :: new_unchecked ( data) ;
1297+ let repr = Ipv4Repr :: parse ( & packet, & ChecksumCapabilities :: default ( ) ) . unwrap ( ) ;
1298+ assert_eq ! ( repr. src_addr, src_addr) ;
1299+ assert_eq ! ( repr. dst_addr, dst_addr) ;
1300+ assert_eq ! ( repr. next_header, proto) ;
1301+ assert_eq ! ( repr. payload_len, total_payload_len) ;
1302+
1303+ let payload = packet. payload ( ) ;
1304+ assert_eq ! ( payload. len( ) , total_payload_len) ;
1305+ assert ! ( payload[ ..first_payload_len] . iter( ) . all( |& b| b == 0xAA ) ) ;
1306+ assert ! ( payload[ first_payload_len..] . iter( ) . all( |& b| b == 0xBB ) ) ;
1307+ }
1308+
11861309#[ rstest]
11871310#[ case( Medium :: Ip ) ]
11881311#[ cfg( all( feature = "socket-udp" , feature = "medium-ip" ) ) ]
0 commit comments