Skip to content

Conversation

@zkkkk12
Copy link

@zkkkk12 zkkkk12 commented Dec 30, 2025

Supports no Neighbor request for invalid routing addresses in cross-segment communication

Note: Please adhere to Contributing Guidelines.

Summary

Supports no Neighbor request for invalid routing addresses in cross-segment communication

Impact

When processing IPv6 packet transmission, if the destination address is unspecified, the device buffer length is set to 0 and the device returns directly without sending any packets.This prevents the system from attempting to send data packets to invalid addresses, thus avoiding wasting network resources.

Testing

#include <nuttx/config.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>

#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/icmpv6.h>
#include <nuttx/net/neighbor.h>

#include "Ipv6NeighborTest.h"
#include "CunitTest.h"

/* Test constants */
#define TEST_INTERFACE_NAME "test_eth0"

/* IPv6 unspecified address (all zeros) */
static const net_ipv6addr_t g_unspecified_addr = {0, 0, 0, 0, 0, 0, 0, 0};

/* Helper function to create a network device structure for testing */
static struct net_driver_s *create_test_netdev(void)
{
  struct net_driver_s *dev;

  /* Allocate memory for test netdev */
  dev = (struct net_driver_s *)malloc(sizeof(struct net_driver_s));
  if (dev == NULL)
    {
      return NULL;
    }

  /* Initialize basic fields */
  memset(dev, 0, sizeof(struct net_driver_s));

  /* Set device properties for IPv6 testing */
  dev->d_lltype = NET_LL_ETHERNET;
  dev->d_ifname = TEST_INTERFACE_NAME;
  dev->d_ifup = true;

  /* Set IPv6 link-local address (fe80::1) */
  dev->d_ipv6addr[0] = HTONS(0xfe80);
  dev->d_ipv6addr[1] = 0;
  dev->d_ipv6addr[2] = 0;
  dev->d_ipv6addr[3] = 0;
  dev->d_ipv6addr[4] = 0;
  dev->d_ipv6addr[5] = 0;
  dev->d_ipv6addr[6] = 0;
  dev->d_ipv6addr[7] = HTONS(0x0001);

  /* Set IPv6 netmask (prefix length 64) */
  dev->d_ipv6netmask[0] = HTONS(0xffff);
  dev->d_ipv6netmask[1] = HTONS(0xffff);
  dev->d_ipv6netmask[2] = HTONS(0xffff);
  dev->d_ipv6netmask[3] = HTONS(0xffff);
  dev->d_ipv6netmask[4] = 0;
  dev->d_ipv6netmask[5] = 0;
  dev->d_ipv6netmask[6] = 0;
  dev->d_ipv6netmask[7] = 0;

  /* Set default router to unspecified address (this is what we want to test) */
  memset(dev->d_ipv6draddr, 0, sizeof(net_ipv6addr_t));

  /* Set MAC address */
  dev->d_mac.ether.ether_addr_octet[0] = 0x00;
  dev->d_mac.ether.ether_addr_octet[1] = 0x11;
  dev->d_mac.ether.ether_addr_octet[2] = 0x22;
  dev->d_mac.ether.ether_addr_octet[3] = 0x33;
  dev->d_mac.ether.ether_addr_octet[4] = 0x44;
  dev->d_mac.ether.ether_addr_octet[5] = 0x55;

  /* Clear NOARP flag to allow neighbor discovery */
  IFF_CLR_NOARP(dev->d_flags);

  return dev;
}

/* Helper function to cleanup test netdev */
static void cleanup_test_netdev(struct net_driver_s *dev)
{
  if (dev != NULL)
    {
      free(dev);
    }
}

/* Helper function to create IPv6 packet in device buffer */
static void create_test_ipv6_packet(struct net_driver_s *dev, const net_ipv6addr_t dest_addr)
{
  struct ipv6_hdr_s *ip;

  /* Allocate buffer for Ethernet + IPv6 header */
  dev->d_buf = malloc(sizeof(struct eth_hdr_s) + sizeof(struct ipv6_hdr_s));
  if (dev->d_buf == NULL)
    {
      return;
    }

  /* Set packet length */
  dev->d_len = sizeof(struct eth_hdr_s) + sizeof(struct ipv6_hdr_s);

  /* Skip Ethernet header and get IPv6 header */
  ip = (struct ipv6_hdr_s *)(dev->d_buf + sizeof(struct eth_hdr_s));

  /* Set IPv6 header fields */
  ip->vtc = 0x60;  /* Version 6, Traffic class 0 */
  ip->tcf = 0;     /* Traffic class 0, Flow label 0 */
  ip->flow = 0;    /* Flow label 0 */
  ip->len[0] = 0;  /* Payload length (will be set later) */
  ip->len[1] = 0;
  ip->proto = IP_PROTO_TCP;  /* Next header */
  ip->ttl = 64;    /* Hop limit */

  /* Set source address (link-local) */
  ip->srcipaddr[0] = HTONS(0xfe80);
  ip->srcipaddr[1] = 0;
  ip->srcipaddr[2] = 0;
  ip->srcipaddr[3] = 0;
  ip->srcipaddr[4] = 0;
  ip->srcipaddr[5] = 0;
  ip->srcipaddr[6] = 0;
  ip->srcipaddr[7] = HTONS(0x0001);

  /* Set destination address */
  memcpy(ip->destipaddr, dest_addr, sizeof(net_ipv6addr_t));
}

/* Test icmpv6_neighbor function with unspecified address */
int do_icmpv6_neighbor_unspecified_addr_test(void)
{
  struct net_driver_s *dev;
  int ret;

  /* Create test network device */
  dev = create_test_netdev();
  if (dev == NULL)
    {
      printf("Failed to create test netdev\n");
      return TEST_FAIL;
    }

  /* Test icmpv6_neighbor with unspecified address - should return EHOSTUNREACH */
  ret = icmpv6_neighbor(dev, g_unspecified_addr);
  if (ret != -EHOSTUNREACH)
    {
      printf("icmpv6_neighbor should return EHOSTUNREACH for unspecified address, got %d\n", ret);
      cleanup_test_netdev(dev);
      return TEST_FAIL;
    }

  cleanup_test_netdev(dev);
  return TEST_PASS;
}

/* Test neighbor_ethernet_out function with unspecified address */
int do_neighbor_ethernet_out_unspecified_addr_test(void)
{
  struct net_driver_s *dev;
  uint16_t original_len;

  /* Create test network device */
  dev = create_test_netdev();
  if (dev == NULL)
    {
      printf("Failed to create test netdev\n");
      return TEST_FAIL;
    }

  /* Create IPv6 packet with unspecified destination address */
  create_test_ipv6_packet(dev, g_unspecified_addr);
  if (dev->d_buf == NULL)
    {
      printf("Failed to create test packet\n");
      cleanup_test_netdev(dev);
      return TEST_FAIL;
    }

  original_len = dev->d_len;

  /* Call neighbor_ethernet_out - should detect unspecified address and set d_len to 0 */
  neighbor_ethernet_out(dev);

  if (dev->d_len != 0)
    {
      printf("neighbor_ethernet_out should set d_len to 0 for unspecified address, got %d\n", dev->d_len);
      free(dev->d_buf);
      cleanup_test_netdev(dev);
      return TEST_FAIL;
    }

  /* Cleanup */
  free(dev->d_buf);
  cleanup_test_netdev(dev);
  return TEST_PASS;
}


/****************************************************************************
 * Name: main
 *
 * Description:
 *   Main function to run IPv6 neighbor unspecified address tests
 *
 * Returned Value:
 *   Zero on success, non-zero on failure
 *
 ****************************************************************************/

int main(int argc, char *argv[])
{
  int ret;
  int passed = 0;
  int failed = 0;

  printf("=== IPv6 Neighbor Unspecified Address Test ===\n\n");

  /* Test 1: icmpv6_neighbor with unspecified address */
  printf("Running do_icmpv6_neighbor_unspecified_addr_test...\n");
  ret = do_icmpv6_neighbor_unspecified_addr_test();
  if (ret == TEST_PASS)
    {
      printf("PASS: icmpv6_neighbor correctly handles unspecified address\n");
      passed++;
    }
  else
    {
      printf("FAIL: icmpv6_neighbor test failed\n");
      failed++;
    }

  printf("\n");

  /* Test 2: neighbor_ethernet_out with unspecified address */
  printf("Running do_neighbor_ethernet_out_unspecified_addr_test...\n");
  ret = do_neighbor_ethernet_out_unspecified_addr_test();
  if (ret == TEST_PASS)
    {
      printf("PASS: neighbor_ethernet_out correctly handles unspecified address\n");
      passed++;
    }
  else
    {
      printf("FAIL: neighbor_ethernet_out test failed\n");
      failed++;
    }

  printf("\n");
  printf("=== Test Results ===\n");
  printf("Total tests: %d\n", passed + failed);
  printf("Passed: %d\n", passed);
  printf("Failed: %d\n", failed);

  if (failed == 0)
    {
      printf("\nSUCCESS: All IPv6 neighbor unspecified address tests passed!\n");
      printf("The fix ensures that:\n");
      printf("1. icmpv6_neighbor() returns EHOSTUNREACH when address is unspecified\n");
      printf("2. neighbor_ethernet_out() sets packet length to 0 when address is unspecified\n");
      return 0;
    }
  else
    {
      printf("\nFAILURE: Some tests failed!\n");
      return 1;
    }
}

Terminal output log:

core1> === IPv6 Neighbor Unspecified Address Test ===
core1> Running do_icmpv6_neighbor_unspecified_addr_test...
core1> PASS: icmpv6_neighbor correctly handles unspecified address
core1> Running do_neighbor_ethernet_out_unspecified_addr_test...
core1> PASS: neighbor_ethernet_out correctly handles unspecified address
core1> === Test Results ===
core1> SUCCESS: All IPv6 neighbor unspecified address tests passed!

Supports no Neighbor request for invalid routing addresses in cross-segment communication

Signed-off-by: zhangkai25 <zhangkai25@xiaomi.com>
@github-actions github-actions bot added Area: Networking Effects networking subsystem Size: S The size of the change in this PR is small labels Dec 30, 2025
@xiaoxiang781216 xiaoxiang781216 merged commit 7a6b9e9 into apache:master Dec 30, 2025
40 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Networking Effects networking subsystem Size: S The size of the change in this PR is small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants