@@ -378,4 +378,97 @@ START_TEST(test_multicast_if_pins_egress_interface)
378378}
379379END_TEST
380380
381+ START_TEST (test_multicast_loop_does_not_fire_on_blocked_send )
382+ {
383+ struct wolfIP s ;
384+ int sd ;
385+ struct wolfIP_sockaddr_in bind_addr ;
386+ struct wolfIP_sockaddr_in dst ;
387+ struct wolfIP_ip_mreq mreq ;
388+ uint8_t out [8 ];
389+ int loop = 1 ;
390+ ip4 group = 0xE9010208U ;
391+ const char payload [] = "xy" ;
392+
393+ wolfIP_init (& s );
394+ mock_link_init (& s );
395+ wolfIP_ipconfig_set (& s , 0x0A000002U , 0xFFFFFF00U , 0 );
396+ sd = wolfIP_sock_socket (& s , AF_INET , IPSTACK_SOCK_DGRAM , WI_IPPROTO_UDP );
397+ ck_assert_int_gt (sd , 0 );
398+ memset (& bind_addr , 0 , sizeof (bind_addr ));
399+ bind_addr .sin_family = AF_INET ;
400+ bind_addr .sin_port = ee16 (5003 );
401+ ck_assert_int_eq (wolfIP_sock_bind (& s , sd ,
402+ (struct wolfIP_sockaddr * )& bind_addr , sizeof (bind_addr )), 0 );
403+
404+ multicast_mreq (& mreq , group , IPADDR_ANY );
405+ ck_assert_int_eq (wolfIP_sock_setsockopt (& s , sd , WOLFIP_SOL_IP ,
406+ WOLFIP_IP_ADD_MEMBERSHIP , & mreq , sizeof (mreq )), 0 );
407+ ck_assert_int_eq (wolfIP_sock_setsockopt (& s , sd , WOLFIP_SOL_IP ,
408+ WOLFIP_IP_MULTICAST_LOOP , & loop , sizeof (loop )), 0 );
409+
410+ /* Block the egress UDP path. With the pre-fix code the mcast_loop
411+ * udp_try_recv() ran before the filter, so the local RX queue got one
412+ * copy per poll even though the frame was never transmitted; with the
413+ * fix, a blocked send must not deliver a loopback copy. */
414+ filter_block_reason = WOLFIP_FILT_SENDING ;
415+ wolfIP_filter_set_callback (test_filter_cb_block , NULL );
416+ wolfIP_filter_set_udp_mask (WOLFIP_FILT_MASK (WOLFIP_FILT_SENDING ));
417+
418+ memset (& dst , 0 , sizeof (dst ));
419+ dst .sin_family = AF_INET ;
420+ dst .sin_port = ee16 (5003 );
421+ dst .sin_addr .s_addr = ee32 (group );
422+ last_frame_sent_size = 0 ;
423+ ck_assert_int_eq (wolfIP_sock_sendto (& s , sd , payload , sizeof (payload ), 0 ,
424+ (struct wolfIP_sockaddr * )& dst , sizeof (dst )),
425+ (int )sizeof (payload ));
426+
427+ /* Poll twice: with the pre-fix code the descriptor sticks in the txbuf
428+ * and each poll re-loops the datagram, so recvfrom would return it. */
429+ (void )wolfIP_poll (& s , 1 );
430+ (void )wolfIP_poll (& s , 2 );
431+ ck_assert_uint_eq (last_frame_sent_size , 0U );
432+ ck_assert_int_eq (wolfIP_sock_recvfrom (& s , sd , out , sizeof (out ), 0 , NULL ,
433+ NULL ), - WOLFIP_EAGAIN );
434+
435+ /* Clearing the filter lets the next poll send and loop exactly once. */
436+ wolfIP_filter_set_callback (NULL , NULL );
437+ wolfIP_filter_set_udp_mask (0 );
438+ (void )wolfIP_poll (& s , 3 );
439+ ck_assert_uint_gt (last_frame_sent_size , 0U );
440+ ck_assert_int_eq (wolfIP_sock_recvfrom (& s , sd , out , sizeof (out ), 0 , NULL ,
441+ NULL ), (int )sizeof (payload ));
442+ /* Only one loopback copy — no leftover. */
443+ ck_assert_int_eq (wolfIP_sock_recvfrom (& s , sd , out , sizeof (out ), 0 , NULL ,
444+ NULL ), - WOLFIP_EAGAIN );
445+ }
446+ END_TEST
447+
448+ START_TEST (test_multicast_recv_rejects_short_frame )
449+ {
450+ struct wolfIP s ;
451+ uint8_t frame [ETH_HEADER_LEN ];
452+
453+ wolfIP_init (& s );
454+ mock_link_init (& s );
455+ wolfIP_ipconfig_set (& s , 0x0A000002U , 0xFFFFFF00U , 0 );
456+
457+ /* Build a 14-byte frame (Ethernet header only) with a multicast-looking
458+ * destination MAC and ETH_TYPE_IP. Without the length guard,
459+ * wolfIP_recv_on would read ip->dst at offsets 30-33 — well past the
460+ * end of the buffer. Under ASAN this is a heap-buffer-overflow. */
461+ memset (frame , 0 , sizeof (frame ));
462+ memcpy (frame + 0 , "\x01\x00\x5e\x01\x02\x08" , 6 );
463+ memcpy (frame + 6 , "\x02\x00\x00\x00\x00\x01" , 6 );
464+ frame [12 ] = (ETH_TYPE_IP >> 8 ) & 0xff ;
465+ frame [13 ] = ETH_TYPE_IP & 0xff ;
466+
467+ last_frame_sent_size = 0 ;
468+ wolfIP_recv_ex (& s , TEST_PRIMARY_IF , frame , sizeof (frame ));
469+ /* Silently dropped, no response sent. */
470+ ck_assert_uint_eq (last_frame_sent_size , 0U );
471+ }
472+ END_TEST
473+
381474#endif /* IP_MULTICAST */
0 commit comments