@@ -1183,6 +1183,152 @@ 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+ fn build_fragment (
1228+ src : Ipv4Address ,
1229+ dst : Ipv4Address ,
1230+ proto : IpProtocol ,
1231+ ident : u16 ,
1232+ payload_len : usize ,
1233+ more_frags : bool ,
1234+ frag_offset_octets : u16 ,
1235+ payload_byte : u8 ,
1236+ ) -> Vec < u8 > {
1237+ let repr = Ipv4Repr {
1238+ src_addr : src,
1239+ dst_addr : dst,
1240+ next_header : proto,
1241+ hop_limit : 64 ,
1242+ payload_len,
1243+ } ;
1244+ let header_len = repr. buffer_len ( ) ;
1245+ let mut bytes = vec ! [ 0u8 ; header_len + payload_len] ;
1246+ {
1247+ let mut pkt = Ipv4Packet :: new_unchecked ( & mut bytes[ ..] ) ;
1248+ repr. emit ( & mut pkt, & ChecksumCapabilities :: default ( ) ) ;
1249+ pkt. set_ident ( ident) ;
1250+ pkt. set_dont_frag ( false ) ;
1251+ pkt. set_more_frags ( more_frags) ;
1252+ pkt. set_frag_offset ( frag_offset_octets) ;
1253+ // Recompute checksum after changing fragmentation fields.
1254+ pkt. fill_checksum ( ) ;
1255+ }
1256+ // Fill payload with a simple pattern for validation
1257+ for b in & mut bytes[ header_len..] {
1258+ * b = payload_byte;
1259+ }
1260+ bytes
1261+ }
1262+
1263+ let frag1_bytes = build_fragment (
1264+ src_addr,
1265+ dst_addr,
1266+ proto,
1267+ ident,
1268+ first_payload_len,
1269+ true ,
1270+ 0 ,
1271+ 0xAA ,
1272+ ) ;
1273+ let frag2_bytes = build_fragment (
1274+ src_addr,
1275+ dst_addr,
1276+ proto,
1277+ ident,
1278+ last_payload_len,
1279+ false ,
1280+ first_payload_len as u16 ,
1281+ 0xBB ,
1282+ ) ;
1283+
1284+ let frag1 = Ipv4Packet :: new_unchecked ( & frag1_bytes[ ..] ) ;
1285+ let frag2 = Ipv4Packet :: new_unchecked ( & frag2_bytes[ ..] ) ;
1286+
1287+ // First fragment alone should not be delivered to the raw socket.
1288+ assert_eq ! (
1289+ iface. inner. process_ipv4(
1290+ & mut sockets,
1291+ PacketMeta :: default ( ) ,
1292+ HardwareAddress :: default ( ) ,
1293+ & frag1,
1294+ & mut iface. fragments
1295+ ) ,
1296+ None
1297+ ) ;
1298+ {
1299+ let socket = sockets. get_mut :: < raw:: Socket > ( handle) ;
1300+ assert ! ( !socket. can_recv( ) ) ;
1301+ }
1302+
1303+ // After the last fragment, the reassembled packet should be delivered.
1304+ assert_eq ! (
1305+ iface. inner. process_ipv4(
1306+ & mut sockets,
1307+ PacketMeta :: default ( ) ,
1308+ HardwareAddress :: default ( ) ,
1309+ & frag2,
1310+ & mut iface. fragments
1311+ ) ,
1312+ None
1313+ ) ;
1314+
1315+ // Validate the raw socket received one defragmented packet with correct payload.
1316+ let socket = sockets. get_mut :: < raw:: Socket > ( handle) ;
1317+ assert ! ( socket. can_recv( ) ) ;
1318+ let data = socket. recv ( ) . expect ( "raw socket should have a packet" ) ;
1319+ let packet = Ipv4Packet :: new_unchecked ( data) ;
1320+ let repr = Ipv4Repr :: parse ( & packet, & ChecksumCapabilities :: default ( ) ) . unwrap ( ) ;
1321+ assert_eq ! ( repr. src_addr, src_addr) ;
1322+ assert_eq ! ( repr. dst_addr, dst_addr) ;
1323+ assert_eq ! ( repr. next_header, proto) ;
1324+ assert_eq ! ( repr. payload_len, total_payload_len) ;
1325+
1326+ let payload = packet. payload ( ) ;
1327+ assert_eq ! ( payload. len( ) , total_payload_len) ;
1328+ assert ! ( payload[ ..first_payload_len] . iter( ) . all( |& b| b == 0xAA ) ) ;
1329+ assert ! ( payload[ first_payload_len..] . iter( ) . all( |& b| b == 0xBB ) ) ;
1330+ }
1331+
11861332#[ rstest]
11871333#[ case( Medium :: Ip ) ]
11881334#[ cfg( all( feature = "socket-udp" , feature = "medium-ip" ) ) ]
0 commit comments