Skip to content

Commit 403f130

Browse files
committed
Added loopback interface
1 parent eb29076 commit 403f130

File tree

4 files changed

+295
-86
lines changed

4 files changed

+295
-86
lines changed

config.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@
1919
#define WOLFIP_ENABLE_FORWARDING 0
2020
#endif
2121

22+
#ifndef WOLFIP_ENABLE_LOOPBACK
23+
#define WOLFIP_ENABLE_LOOPBACK 0
24+
#endif
25+
26+
#if WOLFIP_ENABLE_LOOPBACK && WOLFIP_MAX_INTERFACES < 2
27+
#error "WOLFIP_ENABLE_LOOPBACK requires WOLFIP_MAX_INTERFACES > 1"
28+
#endif
29+
2230
/* Linux test configuration */
2331
#define WOLFIP_IP "10.10.10.2"
2432
#define LINUX_IP "10.10.10.1"

docs/API.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct ll {
3030
int (*send)(struct ll *ll, void *buf, uint32_t len); // Transmit function
3131
};
3232
```
33-
wolfIP maintains an array of these descriptors sized by `WOLFIP_MAX_INTERFACES` (default `1`). Call `wolfIP_getdev_ex()` to access a specific slot; the legacy `wolfIP_getdev()` helper still returns slot `0`.
33+
wolfIP maintains an array of these descriptors sized by `WOLFIP_MAX_INTERFACES` (default `1`). Call `wolfIP_getdev_ex()` to access a specific slot; the legacy `wolfIP_getdev()` helper targets the first hardware slot (index `0` normally, or `1` when the optional loopback interface is enabled).
3434

3535
### IP Configuration
3636
```c
@@ -41,10 +41,15 @@ struct ipconf {
4141
ip4 gw; // Default gateway
4242
};
4343
```
44-
Each `struct wolfIP` instance owns `WOLFIP_MAX_INTERFACES` `ipconf` entries—one per link-layer slot. Use the `_ex` helpers to read or update a specific interface; the legacy accessors operate on index `0` for backwards compatibility.
44+
Each `struct wolfIP` instance owns `WOLFIP_MAX_INTERFACES` `ipconf` entries—one per link-layer slot. Use the `_ex` helpers to read or update a specific interface; the legacy accessors operate on the first hardware interface (index `0` unless loopback support is compiled in).
4545

4646
If `WOLFIP_ENABLE_FORWARDING` is set to `1` at compile time, the stack performs simple IPv4 forwarding between interfaces. Packets received on one interface whose destinations match another configured interface are re-sent with the IP TTL decreased by one (or an ICMP TTL-exceeded response if the TTL would drop to zero).
4747

48+
Enabling `WOLFIP_ENABLE_LOOPBACK` (requires `WOLFIP_MAX_INTERFACES > 1`) creates an internal loopback
49+
device at index `0` with the fixed address `127.0.0.1/8`. Traffic sent to that address is reflected back
50+
through the stack so local sockets, pings, and other services behave as they would on a standard
51+
loopback interface; the first hardware interface then shifts to index `1` for legacy helpers.
52+
4853
### Socket Address Structures
4954
```c
5055
struct wolfIP_sockaddr_in {

src/test/unit/unit.c

Lines changed: 93 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,22 @@
1919
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
2020
*/
2121
#include "check.h"
22-
#ifndef WOLFIP_MAX_INTERFACES
23-
#define WOLFIP_MAX_INTERFACES 2
24-
#endif
22+
#include "../../../config.h"
23+
#undef WOLFIP_MAX_INTERFACES
24+
#define WOLFIP_MAX_INTERFACES 3
25+
#undef WOLFIP_ENABLE_FORWARDING
2526
#ifndef WOLFIP_ENABLE_FORWARDING
2627
#define WOLFIP_ENABLE_FORWARDING 1
2728
#endif
29+
#if WOLFIP_ENABLE_LOOPBACK
30+
#define TEST_LOOPBACK_IF 0U
31+
#define TEST_PRIMARY_IF 1U
32+
#define TEST_SECOND_IF 2U
33+
#else
34+
#define TEST_LOOPBACK_IF 0U
35+
#define TEST_PRIMARY_IF 0U
36+
#define TEST_SECOND_IF 1U
37+
#endif
2838
#include <stdio.h>
2939
#include "../../wolfip.c"
3040
#include <stdlib.h> /* for random() */
@@ -78,7 +88,11 @@ static void mock_link_init_idx(struct wolfIP *s, unsigned int idx, const uint8_t
7888

7989
void mock_link_init(struct wolfIP *s)
8090
{
81-
mock_link_init_idx(s, 0, NULL);
91+
unsigned int idx = 0;
92+
#if WOLFIP_ENABLE_LOOPBACK
93+
idx = 1;
94+
#endif
95+
mock_link_init_idx(s, idx, NULL);
8296
}
8397

8498
static struct timers_binheap heap;
@@ -468,19 +482,19 @@ START_TEST(test_arp_request_basic)
468482
uint32_t target_ip = 0xC0A80002; /* 192.168.0.2 */
469483
mock_link_init(&s);
470484
s.last_tick = 1000;
471-
arp_request(&s, 0, target_ip);
485+
arp_request(&s, TEST_PRIMARY_IF, target_ip);
472486
ck_assert_int_eq(last_frame_sent_size, sizeof(struct arp_packet));
473487
arp = (struct arp_packet *)last_frame_sent;
474488
ck_assert_mem_eq(arp->eth.dst, "\xff\xff\xff\xff\xff\xff", 6);
475-
ck_assert_mem_eq(arp->eth.src, s.ll_dev[0].mac, 6);
489+
ck_assert_mem_eq(arp->eth.src, s.ll_dev[TEST_PRIMARY_IF].mac, 6);
476490
ck_assert_int_eq(arp->eth.type, ee16(0x0806));
477491
ck_assert_int_eq(arp->htype, ee16(1));
478492
ck_assert_int_eq(arp->ptype, ee16(0x0800));
479493
ck_assert_int_eq(arp->hlen, 6);
480494
ck_assert_int_eq(arp->plen, 4);
481495
ck_assert_int_eq(arp->opcode, ee16(ARP_REQUEST));
482-
ck_assert_mem_eq(arp->sma, s.ll_dev[0].mac, 6);
483-
ck_assert_int_eq(arp->sip, ee32(s.ipconf[0].ip));
496+
ck_assert_mem_eq(arp->sma, s.ll_dev[TEST_PRIMARY_IF].mac, 6);
497+
ck_assert_int_eq(arp->sip, ee32(s.ipconf[TEST_PRIMARY_IF].ip));
484498
ck_assert_mem_eq(arp->tma, "\x00\x00\x00\x00\x00\x00", 6);
485499
ck_assert_int_eq(arp->tip, ee32(target_ip));
486500
}
@@ -493,9 +507,9 @@ START_TEST(test_arp_request_throttle)
493507
uint32_t target_ip = 0xC0A80002; /*192.168.0.2*/
494508
mock_link_init(&s);
495509
s.last_tick = 1000;
496-
s.arp.last_arp[0] = 880;
510+
s.arp.last_arp[TEST_PRIMARY_IF] = 880;
497511
last_frame_sent_size = 0;
498-
arp_request(&s, 0, target_ip);
512+
arp_request(&s, TEST_PRIMARY_IF, target_ip);
499513
ck_assert_int_eq(last_frame_sent_size, 0);
500514
}
501515
END_TEST
@@ -506,7 +520,7 @@ START_TEST(test_arp_request_target_ip) {
506520
wolfIP_init(&s);
507521
mock_link_init(&s);
508522
s.last_tick = 1000;
509-
arp_request(&s, 0, target_ip);
523+
arp_request(&s, TEST_PRIMARY_IF, target_ip);
510524
ck_assert_int_eq(((struct arp_packet *)(last_frame_sent))->tip, ee32(target_ip));
511525
}
512526
END_TEST
@@ -522,7 +536,7 @@ START_TEST(test_arp_request_handling) {
522536
struct wolfIP s;
523537
wolfIP_init(&s);
524538
mock_link_init(&s);
525-
s.ipconf[0].ip = device_ip;
539+
s.ipconf[TEST_PRIMARY_IF].ip = device_ip;
526540

527541
/* Prepare ARP request */
528542
arp_req.opcode = ee16(ARP_REQUEST);
@@ -531,7 +545,7 @@ START_TEST(test_arp_request_handling) {
531545
arp_req.tip = ee32(device_ip);
532546

533547
/* Call arp_recv with the ARP request */
534-
arp_recv(&s, 0, &arp_req, sizeof(arp_req));
548+
arp_recv(&s, TEST_PRIMARY_IF, &arp_req, sizeof(arp_req));
535549
wolfIP_poll(&s, 1000);
536550
wolfIP_poll(&s, 1001);
537551
wolfIP_poll(&s, 1002);
@@ -545,7 +559,7 @@ START_TEST(test_arp_request_handling) {
545559
arp_reply = (struct arp_packet *)last_frame_sent;
546560
ck_assert_int_eq(last_frame_sent_size, sizeof(struct arp_packet));
547561
ck_assert_int_eq(arp_reply->opcode, ee16(ARP_REPLY));
548-
ck_assert_mem_eq(arp_reply->sma, s.ll_dev[0].mac, 6); // source MAC
562+
ck_assert_mem_eq(arp_reply->sma, s.ll_dev[TEST_PRIMARY_IF].mac, 6); // source MAC
549563
ck_assert_int_eq(arp_reply->sip, ee32(device_ip)); // source IP
550564
ck_assert_mem_eq(arp_reply->tma, req_mac, 6); // target MAC
551565
ck_assert_int_eq(arp_reply->tip, ee32(req_ip)); // target IP
@@ -567,7 +581,7 @@ START_TEST(test_arp_reply_handling) {
567581
memcpy(arp_reply.sma, reply_mac, 6);
568582

569583
/* Call arp_recv with the ARP reply */
570-
arp_recv(&s, 0, &arp_reply, sizeof(arp_reply));
584+
arp_recv(&s, TEST_PRIMARY_IF, &arp_reply, sizeof(arp_reply));
571585

572586
/* Check if ARP table updated with reply IP and MAC */
573587
ck_assert_int_eq(s.arp.neighbors[0].ip, reply_ip);
@@ -576,7 +590,7 @@ START_TEST(test_arp_reply_handling) {
576590
/* Update same IP with a different MAC address */
577591
uint8_t new_mac[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
578592
memcpy(arp_reply.sma, new_mac, 6);
579-
arp_recv(&s, 0, &arp_reply, sizeof(arp_reply));
593+
arp_recv(&s, TEST_PRIMARY_IF, &arp_reply, sizeof(arp_reply));
580594

581595
/* Check if ARP table updates with new MAC */
582596
ck_assert_mem_eq(s.arp.neighbors[0].mac, new_mac, 6);
@@ -596,7 +610,7 @@ START_TEST(test_arp_lookup_success) {
596610
memcpy(s.arp.neighbors[0].mac, mock_mac, 6);
597611

598612
/* Test arp_lookup */
599-
int result = arp_lookup(&s, 0, ip, found_mac);
613+
int result = arp_lookup(&s, TEST_PRIMARY_IF, ip, found_mac);
600614
ck_assert_int_eq(result, 0);
601615
ck_assert_mem_eq(found_mac, mock_mac, 6);
602616
}
@@ -610,7 +624,7 @@ START_TEST(test_arp_lookup_failure) {
610624
mock_link_init(&s);
611625

612626
/* Ensure arp_lookup fails for unknown IP */
613-
int result = arp_lookup(&s, 0, ip, found_mac);
627+
int result = arp_lookup(&s, TEST_PRIMARY_IF, ip, found_mac);
614628
ck_assert_int_eq(result, -1);
615629
uint8_t zero_mac[6] = {0, 0, 0, 0, 0, 0};
616630
ck_assert_mem_eq(found_mac, zero_mac, 6);
@@ -623,11 +637,46 @@ START_TEST(test_wolfip_getdev_ex_api)
623637
wolfIP_init(&s);
624638
struct ll *ll_def = wolfIP_getdev(&s);
625639
ck_assert_ptr_nonnull(ll_def);
626-
ck_assert_ptr_eq(ll_def, wolfIP_getdev_ex(&s, 0));
640+
ck_assert_ptr_eq(ll_def, wolfIP_getdev_ex(&s, TEST_PRIMARY_IF));
641+
#if WOLFIP_ENABLE_LOOPBACK
642+
ck_assert_ptr_ne(ll_def, wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF));
643+
#endif
627644
ck_assert_ptr_null(wolfIP_getdev_ex(&s, WOLFIP_MAX_INTERFACES));
628645
}
629646
END_TEST
630647

648+
#if WOLFIP_ENABLE_LOOPBACK
649+
START_TEST(test_wolfip_loopback_defaults)
650+
{
651+
struct wolfIP s;
652+
struct ll *loop;
653+
struct ll *hw;
654+
ip4 ip = 0, mask = 0, gw = 0;
655+
656+
wolfIP_init(&s);
657+
658+
loop = wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF);
659+
ck_assert_ptr_nonnull(loop);
660+
ck_assert_ptr_nonnull(loop->send);
661+
ck_assert_uint_eq(loop->mac[0], 0x02);
662+
663+
wolfIP_ipconfig_get_ex(&s, TEST_LOOPBACK_IF, &ip, &mask, &gw);
664+
ck_assert_uint_eq(ip, 0x7F000001U);
665+
ck_assert_uint_eq(mask, 0xFF000000U);
666+
ck_assert_uint_eq(gw, 0U);
667+
668+
wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0x0A0000FEU);
669+
wolfIP_ipconfig_get_ex(&s, TEST_PRIMARY_IF, &ip, &mask, &gw);
670+
ck_assert_uint_eq(ip, 0x0A000001U);
671+
ck_assert_uint_eq(mask, 0xFFFFFF00U);
672+
ck_assert_uint_eq(gw, 0x0A0000FEU);
673+
674+
hw = wolfIP_getdev(&s);
675+
ck_assert_ptr_eq(hw, wolfIP_getdev_ex(&s, TEST_PRIMARY_IF));
676+
}
677+
END_TEST
678+
#endif
679+
631680
START_TEST(test_wolfip_ipconfig_ex_per_interface)
632681
{
633682
struct wolfIP s;
@@ -643,8 +692,8 @@ START_TEST(test_wolfip_ipconfig_ex_per_interface)
643692
wolfIP_init(&s);
644693
wolfIP_ipconfig_set(&s, base_ip, base_mask, base_gw);
645694

646-
wolfIP_ipconfig_set_ex(&s, 1, iface_ip, iface_mask, iface_gw);
647-
wolfIP_ipconfig_get_ex(&s, 1, &out_ip, &out_mask, &out_gw);
695+
wolfIP_ipconfig_set_ex(&s, TEST_SECOND_IF, iface_ip, iface_mask, iface_gw);
696+
wolfIP_ipconfig_get_ex(&s, TEST_SECOND_IF, &out_ip, &out_mask, &out_gw);
648697

649698
ck_assert_uint_eq(out_ip, iface_ip);
650699
ck_assert_uint_eq(out_mask, iface_mask);
@@ -656,11 +705,11 @@ START_TEST(test_wolfip_ipconfig_ex_per_interface)
656705
ck_assert_uint_eq(def_gw, base_gw);
657706

658707
wolfIP_ipconfig_set_ex(&s, WOLFIP_MAX_INTERFACES, 0xDEADBEEF, 0xFFFFFFFF, 0x01010101);
659-
ck_assert_uint_eq(s.ipconf[1].ip, iface_ip);
660-
ck_assert_uint_eq(s.ipconf[1].mask, iface_mask);
661-
ck_assert_uint_eq(s.ipconf[1].gw, iface_gw);
708+
ck_assert_uint_eq(s.ipconf[TEST_SECOND_IF].ip, iface_ip);
709+
ck_assert_uint_eq(s.ipconf[TEST_SECOND_IF].mask, iface_mask);
710+
ck_assert_uint_eq(s.ipconf[TEST_SECOND_IF].gw, iface_gw);
662711

663-
wolfIP_ipconfig_get_ex(&s, 1, NULL, NULL, NULL);
712+
wolfIP_ipconfig_get_ex(&s, TEST_SECOND_IF, NULL, NULL, NULL);
664713
}
665714
END_TEST
666715

@@ -674,9 +723,9 @@ START_TEST(test_wolfip_recv_ex_multi_interface_arp_reply)
674723

675724
wolfIP_init(&s);
676725
mock_link_init(&s);
677-
mock_link_init_idx(&s, 1, iface1_mac);
726+
mock_link_init_idx(&s, TEST_SECOND_IF, iface1_mac);
678727
wolfIP_ipconfig_set(&s, 0xC0A80001, 0xFFFFFF00, 0);
679-
wolfIP_ipconfig_set_ex(&s, 1, 0xC0A80101, 0xFFFFFF00, 0);
728+
wolfIP_ipconfig_set_ex(&s, TEST_SECOND_IF, 0xC0A80101, 0xFFFFFF00, 0);
680729

681730
memset(&arp_req, 0, sizeof(arp_req));
682731
memset(last_frame_sent, 0, sizeof(last_frame_sent));
@@ -695,14 +744,14 @@ START_TEST(test_wolfip_recv_ex_multi_interface_arp_reply)
695744
memset(arp_req.tma, 0, sizeof(arp_req.tma));
696745
arp_req.tip = ee32(0xC0A80101);
697746

698-
wolfIP_recv_ex(&s, 1, &arp_req, sizeof(arp_req));
747+
wolfIP_recv_ex(&s, TEST_SECOND_IF, &arp_req, sizeof(arp_req));
699748

700749
ck_assert_uint_eq(last_frame_sent_size, sizeof(struct arp_packet));
701750
arp_reply = (struct arp_packet *)last_frame_sent;
702751
ck_assert_uint_eq(arp_reply->opcode, ee16(ARP_REPLY));
703752
ck_assert_mem_eq(arp_reply->eth.src, iface1_mac, 6);
704753
ck_assert_mem_eq(arp_reply->sma, iface1_mac, 6);
705-
ck_assert_uint_eq(arp_reply->sip, ee32(s.ipconf[1].ip));
754+
ck_assert_uint_eq(arp_reply->sip, ee32(s.ipconf[TEST_SECOND_IF].ip));
706755
}
707756
END_TEST
708757

@@ -721,15 +770,15 @@ START_TEST(test_wolfip_forwarding_basic)
721770

722771
wolfIP_init(&s);
723772
mock_link_init(&s);
724-
mock_link_init_idx(&s, 1, iface1_mac);
773+
mock_link_init_idx(&s, TEST_SECOND_IF, iface1_mac);
725774
wolfIP_ipconfig_set(&s, 0xC0A80001, 0xFFFFFF00, 0);
726-
wolfIP_ipconfig_set_ex(&s, 1, 0xC0A80101, 0xFFFFFF00, 0);
775+
wolfIP_ipconfig_set_ex(&s, TEST_SECOND_IF, 0xC0A80101, 0xFFFFFF00, 0);
727776
s.arp.neighbors[0].ip = dest_ip;
728-
s.arp.neighbors[0].if_idx = 1;
777+
s.arp.neighbors[0].if_idx = TEST_SECOND_IF;
729778
memcpy(s.arp.neighbors[0].mac, next_hop_mac, 6);
730779

731780
memset(&frame, 0, sizeof(frame));
732-
memcpy(frame.eth.dst, s.ll_dev[0].mac, 6);
781+
memcpy(frame.eth.dst, s.ll_dev[TEST_PRIMARY_IF].mac, 6);
733782
memcpy(frame.eth.src, src_mac, 6);
734783
frame.eth.type = ee16(ETH_TYPE_IP);
735784
frame.ver_ihl = 0x45;
@@ -745,12 +794,12 @@ START_TEST(test_wolfip_forwarding_basic)
745794
memset(last_frame_sent, 0, sizeof(last_frame_sent));
746795
last_frame_sent_size = 0;
747796

748-
wolfIP_recv_ex(&s, 0, &frame, sizeof(frame));
797+
wolfIP_recv_ex(&s, TEST_PRIMARY_IF, &frame, sizeof(frame));
749798

750799
ck_assert_uint_eq(last_frame_sent_size, sizeof(struct wolfIP_ip_packet));
751800
fwd = (struct wolfIP_ip_packet *)last_frame_sent;
752801
ck_assert_mem_eq(fwd->eth.dst, next_hop_mac, 6);
753-
ck_assert_mem_eq(fwd->eth.src, s.ll_dev[1].mac, 6);
802+
ck_assert_mem_eq(fwd->eth.src, s.ll_dev[TEST_SECOND_IF].mac, 6);
754803
ck_assert_uint_eq(fwd->ttl, (uint8_t)(initial_ttl - 1));
755804
expected_csum = (uint16_t)(orig_csum + 1);
756805
if (expected_csum == 0)
@@ -770,12 +819,12 @@ START_TEST(test_wolfip_forwarding_ttl_expired)
770819

771820
wolfIP_init(&s);
772821
mock_link_init(&s);
773-
mock_link_init_idx(&s, 1, iface1_mac);
822+
mock_link_init_idx(&s, TEST_SECOND_IF, iface1_mac);
774823
wolfIP_ipconfig_set(&s, 0xC0A80001, 0xFFFFFF00, 0);
775-
wolfIP_ipconfig_set_ex(&s, 1, 0xC0A80101, 0xFFFFFF00, 0);
824+
wolfIP_ipconfig_set_ex(&s, TEST_SECOND_IF, 0xC0A80101, 0xFFFFFF00, 0);
776825

777826
memset(&frame, 0, sizeof(frame));
778-
memcpy(frame.eth.dst, s.ll_dev[0].mac, 6);
827+
memcpy(frame.eth.dst, s.ll_dev[TEST_PRIMARY_IF].mac, 6);
779828
memcpy(frame.eth.src, src_mac, 6);
780829
frame.eth.type = ee16(ETH_TYPE_IP);
781830
frame.ver_ihl = 0x45;
@@ -790,13 +839,13 @@ START_TEST(test_wolfip_forwarding_ttl_expired)
790839
memset(last_frame_sent, 0, sizeof(last_frame_sent));
791840
last_frame_sent_size = 0;
792841

793-
wolfIP_recv_ex(&s, 0, &frame, sizeof(frame));
842+
wolfIP_recv_ex(&s, TEST_PRIMARY_IF, &frame, sizeof(frame));
794843

795844
ck_assert_uint_eq(last_frame_sent_size, sizeof(struct wolfIP_icmp_packet));
796845
icmp = (struct wolfIP_icmp_packet *)last_frame_sent;
797846
ck_assert_uint_eq(icmp->type, ICMP_TTL_EXCEEDED);
798847
ck_assert_mem_eq(icmp->ip.eth.dst, src_mac, 6);
799-
ck_assert_mem_eq(icmp->ip.eth.src, s.ll_dev[0].mac, 6);
848+
ck_assert_mem_eq(icmp->ip.eth.src, s.ll_dev[TEST_PRIMARY_IF].mac, 6);
800849
ck_assert_uint_eq(frame.ttl, 1); /* original packet should remain unchanged */
801850
}
802851
END_TEST
@@ -968,6 +1017,10 @@ Suite *wolf_suite(void)
9681017
suite_add_tcase(s, tc_utils);
9691018
tcase_add_test(tc_utils, test_wolfip_getdev_ex_api);
9701019
suite_add_tcase(s, tc_utils);
1020+
#if WOLFIP_ENABLE_LOOPBACK
1021+
tcase_add_test(tc_utils, test_wolfip_loopback_defaults);
1022+
suite_add_tcase(s, tc_utils);
1023+
#endif
9711024
tcase_add_test(tc_utils, test_wolfip_ipconfig_ex_per_interface);
9721025
suite_add_tcase(s, tc_utils);
9731026

0 commit comments

Comments
 (0)