@@ -1409,6 +1409,129 @@ fn test_raw_socket_tx_fragmentation(#[case] medium: Medium) {
14091409 }
14101410}
14111411
1412+ #[ rstest]
1413+ #[ case( Medium :: Ip ) ]
1414+ #[ cfg( all(
1415+ feature = "socket-raw" ,
1416+ feature = "proto-ipv4-fragmentation" ,
1417+ feature = "medium-ip"
1418+ ) ) ]
1419+ #[ case( Medium :: Ethernet ) ]
1420+ #[ cfg( all(
1421+ feature = "socket-raw" ,
1422+ feature = "proto-ipv4-fragmentation" ,
1423+ feature = "medium-ethernet"
1424+ ) ) ]
1425+ fn test_raw_socket_rx_fragmentation ( #[ case] medium : Medium ) {
1426+ use crate :: wire:: { IpProtocol , IpVersion , Ipv4Address , Ipv4Packet , Ipv4Repr } ;
1427+
1428+ let ( mut iface, mut sockets, _device) = setup ( medium) ;
1429+
1430+ // Raw socket bound to IPv4 and a custom protocol.
1431+ let packets = 1 ;
1432+ let rx_buffer = raw:: PacketBuffer :: new ( vec ! [ raw:: PacketMetadata :: EMPTY ; packets] , vec ! [ 0 ; 64 ] ) ;
1433+ let tx_buffer = raw:: PacketBuffer :: new ( vec ! [ raw:: PacketMetadata :: EMPTY ; packets] , vec ! [ 0 ; 64 ] ) ;
1434+ let raw_socket = raw:: Socket :: new (
1435+ Some ( IpVersion :: Ipv4 ) ,
1436+ Some ( IpProtocol :: Unknown ( 99 ) ) ,
1437+ rx_buffer,
1438+ tx_buffer,
1439+ ) ;
1440+ let handle = sockets. add ( raw_socket) ;
1441+
1442+ // Build two IPv4 fragments that together form one packet.
1443+ let src_addr = Ipv4Address :: new ( 127 , 0 , 0 , 2 ) ;
1444+ let dst_addr = Ipv4Address :: new ( 127 , 0 , 0 , 1 ) ;
1445+ let proto = IpProtocol :: Unknown ( 99 ) ;
1446+ let ident: u16 = 0x1234 ;
1447+
1448+ let total_payload_len = 30usize ;
1449+ let first_payload_len = 24usize ; // must be a multiple of 8
1450+ let last_payload_len = total_payload_len - first_payload_len;
1451+
1452+ // Helper to build one fragment as on-the-wire bytes
1453+ let build_fragment = |payload_len : usize ,
1454+ more_frags : bool ,
1455+ frag_offset_octets : u16 ,
1456+ payload_byte : u8 |
1457+ -> Vec < u8 > {
1458+ let repr = Ipv4Repr {
1459+ src_addr,
1460+ dst_addr,
1461+ next_header : proto,
1462+ hop_limit : 64 ,
1463+ payload_len,
1464+ } ;
1465+ let header_len = repr. buffer_len ( ) ;
1466+ let mut bytes = vec ! [ 0u8 ; header_len + payload_len] ;
1467+ {
1468+ let mut pkt = Ipv4Packet :: new_unchecked ( & mut bytes[ ..] ) ;
1469+ repr. emit ( & mut pkt, & ChecksumCapabilities :: default ( ) ) ;
1470+ pkt. set_ident ( ident) ;
1471+ pkt. set_dont_frag ( false ) ;
1472+ pkt. set_more_frags ( more_frags) ;
1473+ pkt. set_frag_offset ( frag_offset_octets) ;
1474+ // Recompute checksum after changing fragmentation fields.
1475+ pkt. fill_checksum ( ) ;
1476+ }
1477+ // Fill payload with a simple pattern for validation
1478+ for b in & mut bytes[ header_len..] {
1479+ * b = payload_byte;
1480+ }
1481+ bytes
1482+ } ;
1483+
1484+ let frag1_bytes = build_fragment ( first_payload_len, true , 0 , 0xAA ) ;
1485+ let frag2_bytes = build_fragment ( last_payload_len, false , first_payload_len as u16 , 0xBB ) ;
1486+
1487+ let frag1 = Ipv4Packet :: new_unchecked ( & frag1_bytes[ ..] ) ;
1488+ let frag2 = Ipv4Packet :: new_unchecked ( & frag2_bytes[ ..] ) ;
1489+
1490+ // First fragment alone should not be delivered to the raw socket.
1491+ assert_eq ! (
1492+ iface. inner. process_ipv4(
1493+ & mut sockets,
1494+ PacketMeta :: default ( ) ,
1495+ HardwareAddress :: default ( ) ,
1496+ & frag1,
1497+ & mut iface. fragments
1498+ ) ,
1499+ None
1500+ ) ;
1501+ {
1502+ let socket = sockets. get_mut :: < raw:: Socket > ( handle) ;
1503+ assert ! ( !socket. can_recv( ) ) ;
1504+ }
1505+
1506+ // After the last fragment, the reassembled packet should be delivered.
1507+ assert_eq ! (
1508+ iface. inner. process_ipv4(
1509+ & mut sockets,
1510+ PacketMeta :: default ( ) ,
1511+ HardwareAddress :: default ( ) ,
1512+ & frag2,
1513+ & mut iface. fragments
1514+ ) ,
1515+ None
1516+ ) ;
1517+
1518+ // Validate the raw socket received one defragmented packet with correct payload.
1519+ let socket = sockets. get_mut :: < raw:: Socket > ( handle) ;
1520+ assert ! ( socket. can_recv( ) ) ;
1521+ let data = socket. recv ( ) . expect ( "raw socket should have a packet" ) ;
1522+ let packet = Ipv4Packet :: new_unchecked ( data) ;
1523+ let repr = Ipv4Repr :: parse ( & packet, & ChecksumCapabilities :: default ( ) ) . unwrap ( ) ;
1524+ assert_eq ! ( repr. src_addr, src_addr) ;
1525+ assert_eq ! ( repr. dst_addr, dst_addr) ;
1526+ assert_eq ! ( repr. next_header, proto) ;
1527+ assert_eq ! ( repr. payload_len, total_payload_len) ;
1528+
1529+ let payload = packet. payload ( ) ;
1530+ assert_eq ! ( payload. len( ) , total_payload_len) ;
1531+ assert ! ( payload[ ..first_payload_len] . iter( ) . all( |& b| b == 0xAA ) ) ;
1532+ assert ! ( payload[ first_payload_len..] . iter( ) . all( |& b| b == 0xBB ) ) ;
1533+ }
1534+
14121535#[ rstest]
14131536#[ case( Medium :: Ip ) ]
14141537#[ cfg( all( feature = "socket-udp" , feature = "medium-ip" ) ) ]
0 commit comments