@@ -16,6 +16,7 @@ LOG_MODULE_REGISTER(net_arp, CONFIG_NET_ARP_LOG_LEVEL);
1616#include <zephyr/net/net_pkt.h>
1717#include <zephyr/net/net_if.h>
1818#include <zephyr/net/net_stats.h>
19+ #include <zephyr/net/net_mgmt.h>
1920
2021#include "arp.h"
2122#include "net_private.h"
@@ -34,6 +35,12 @@ static struct k_work_delayable arp_request_timer;
3435
3536static struct k_mutex arp_mutex ;
3637
38+ #if defined(CONFIG_NET_ARP_GRATUITOUS_TRANSMISSION )
39+ static struct net_mgmt_event_callback iface_event_cb ;
40+ static struct net_mgmt_event_callback ipv4_event_cb ;
41+ static struct k_work_delayable arp_gratuitous_work ;
42+ #endif /* defined(CONFIG_NET_ARP_GRATUITOUS_TRANSMISSION) */
43+
3744static void arp_entry_cleanup (struct arp_entry * entry , bool pending )
3845{
3946 NET_DBG ("entry %p" , entry );
@@ -466,6 +473,141 @@ static void arp_gratuitous(struct net_if *iface,
466473 }
467474}
468475
476+ #if defined(CONFIG_NET_ARP_GRATUITOUS_TRANSMISSION )
477+ static void arp_gratuitous_send (struct net_if * iface ,
478+ struct in_addr * ipaddr )
479+ {
480+ struct net_arp_hdr * hdr ;
481+ struct net_pkt * pkt ;
482+
483+ pkt = net_pkt_alloc_with_buffer (iface , sizeof (struct net_arp_hdr ),
484+ AF_UNSPEC , 0 , NET_BUF_TIMEOUT );
485+ if (!pkt ) {
486+ return ;
487+ }
488+
489+ net_buf_add (pkt -> buffer , sizeof (struct net_arp_hdr ));
490+ net_pkt_set_vlan_tag (pkt , net_eth_get_vlan_tag (iface ));
491+
492+ hdr = NET_ARP_HDR (pkt );
493+
494+ hdr -> hwtype = htons (NET_ARP_HTYPE_ETH );
495+ hdr -> protocol = htons (NET_ETH_PTYPE_IP );
496+ hdr -> hwlen = sizeof (struct net_eth_addr );
497+ hdr -> protolen = sizeof (struct in_addr );
498+ hdr -> opcode = htons (NET_ARP_REQUEST );
499+
500+ memcpy (& hdr -> dst_hwaddr .addr , net_eth_broadcast_addr (),
501+ sizeof (struct net_eth_addr ));
502+ memcpy (& hdr -> src_hwaddr .addr , net_if_get_link_addr (iface )-> addr ,
503+ sizeof (struct net_eth_addr ));
504+
505+ net_ipv4_addr_copy_raw (hdr -> dst_ipaddr , (uint8_t * )ipaddr );
506+ net_ipv4_addr_copy_raw (hdr -> src_ipaddr , (uint8_t * )ipaddr );
507+
508+ net_pkt_lladdr_src (pkt )-> addr = net_if_get_link_addr (iface )-> addr ;
509+ net_pkt_lladdr_src (pkt )-> len = sizeof (struct net_eth_addr );
510+
511+ net_pkt_lladdr_dst (pkt )-> addr = (uint8_t * )net_eth_broadcast_addr ();
512+ net_pkt_lladdr_dst (pkt )-> len = sizeof (struct net_eth_addr );
513+
514+ NET_DBG ("Sending gratuitous ARP pkt %p" , pkt );
515+
516+ if (net_if_send_data (iface , pkt ) == NET_DROP ) {
517+ net_pkt_unref (pkt );
518+ }
519+ }
520+
521+ static void notify_all_ipv4_addr (struct net_if * iface )
522+ {
523+ struct net_if_ipv4 * ipv4 = iface -> config .ip .ipv4 ;
524+ int i ;
525+
526+ if (!ipv4 ) {
527+ return ;
528+ }
529+
530+ for (i = 0 ; i < NET_IF_MAX_IPV4_ADDR ; i ++ ) {
531+ if (ipv4 -> unicast [i ].ipv4 .is_used &&
532+ ipv4 -> unicast [i ].ipv4 .address .family == AF_INET &&
533+ ipv4 -> unicast [i ].ipv4 .addr_state == NET_ADDR_PREFERRED ) {
534+ arp_gratuitous_send (iface ,
535+ & ipv4 -> unicast [i ].ipv4 .address .in_addr );
536+ }
537+ }
538+ }
539+
540+ static void iface_event_handler (struct net_mgmt_event_callback * cb ,
541+ uint32_t mgmt_event , struct net_if * iface )
542+ {
543+ ARG_UNUSED (cb );
544+
545+ if (!(net_if_l2 (iface ) == & NET_L2_GET_NAME (ETHERNET ) ||
546+ net_eth_is_vlan_interface (iface ))) {
547+ return ;
548+ }
549+
550+ if (mgmt_event != NET_EVENT_IF_UP ) {
551+ return ;
552+ }
553+
554+ notify_all_ipv4_addr (iface );
555+ }
556+
557+ static void ipv4_event_handler (struct net_mgmt_event_callback * cb ,
558+ uint32_t mgmt_event , struct net_if * iface )
559+ {
560+ struct in_addr * ipaddr ;
561+
562+ if (!(net_if_l2 (iface ) == & NET_L2_GET_NAME (ETHERNET ) ||
563+ net_eth_is_vlan_interface (iface ))) {
564+ return ;
565+ }
566+
567+ if (!net_if_is_up (iface )) {
568+ return ;
569+ }
570+
571+ if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD ) {
572+ return ;
573+ }
574+
575+ if (cb -> info_length != sizeof (struct in_addr )) {
576+ return ;
577+ }
578+
579+ ipaddr = (struct in_addr * )cb -> info ;
580+
581+ arp_gratuitous_send (iface , ipaddr );
582+ }
583+
584+ static void iface_cb (struct net_if * iface , void * user_data )
585+ {
586+ ARG_UNUSED (user_data );
587+
588+ if (!(net_if_l2 (iface ) == & NET_L2_GET_NAME (ETHERNET ) ||
589+ net_eth_is_vlan_interface (iface ))) {
590+ return ;
591+ }
592+
593+ if (!net_if_is_up (iface )) {
594+ return ;
595+ }
596+
597+ notify_all_ipv4_addr (iface );
598+ }
599+
600+ static void arp_gratuitous_work_handler (struct k_work * work )
601+ {
602+ ARG_UNUSED (work );
603+
604+ net_if_foreach (iface_cb , NULL );
605+
606+ k_work_reschedule (& arp_gratuitous_work ,
607+ K_SECONDS (CONFIG_NET_ARP_GRATUITOUS_INTERVAL ));
608+ }
609+ #endif /* defined(CONFIG_NET_ARP_GRATUITOUS_TRANSMISSION) */
610+
469611void net_arp_update (struct net_if * iface ,
470612 struct in_addr * src ,
471613 struct net_eth_addr * hwaddr ,
@@ -837,4 +979,19 @@ void net_arp_init(void)
837979 k_mutex_init (& arp_mutex );
838980
839981 arp_cache_initialized = true;
982+
983+ #if defined(CONFIG_NET_ARP_GRATUITOUS_TRANSMISSION )
984+ net_mgmt_init_event_callback (& iface_event_cb , iface_event_handler ,
985+ NET_EVENT_IF_UP );
986+ net_mgmt_init_event_callback (& ipv4_event_cb , ipv4_event_handler ,
987+ NET_EVENT_IPV4_ADDR_ADD );
988+
989+ net_mgmt_add_event_callback (& iface_event_cb );
990+ net_mgmt_add_event_callback (& ipv4_event_cb );
991+
992+ k_work_init_delayable (& arp_gratuitous_work ,
993+ arp_gratuitous_work_handler );
994+ k_work_reschedule (& arp_gratuitous_work ,
995+ K_SECONDS (CONFIG_NET_ARP_GRATUITOUS_INTERVAL ));
996+ #endif /* defined(CONFIG_NET_ARP_GRATUITOUS_TRANSMISSION) */
840997}
0 commit comments