Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 16 additions & 18 deletions subsys/net/ip/igmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,15 @@ LOG_MODULE_DECLARE(net_ipv4, CONFIG_NET_IPV4_LOG_LEVEL);
#include "connection.h"
#include "ipv4.h"
#include "net_stats.h"
#include "igmp.h"

/* Timeout for various buffer allocations in this file. */
#define PKT_WAIT_TIME K_MSEC(50)

#define IPV4_OPT_HDR_ROUTER_ALERT_LEN 4

#define IGMPV3_MODE_IS_INCLUDE 0x01
#define IGMPV3_MODE_IS_EXCLUDE 0x02
#define IGMPV3_CHANGE_TO_INCLUDE_MODE 0x03
#define IGMPV3_CHANGE_TO_EXCLUDE_MODE 0x04
#define IGMPV3_ALLOW_NEW_SOURCES 0x05
#define IGMPV3_BLOCK_OLD_SOURCES 0x06
#define IGMPV2_PAYLOAD_MIN_LEN 8
#define IGMPV3_PAYLOAD_MIN_LEN 12

static const struct in_addr all_systems = { { { 224, 0, 0, 1 } } };
#if defined(CONFIG_NET_IPV4_IGMPV3)
Expand Down Expand Up @@ -417,28 +414,29 @@ static int send_igmp_v3_report(struct net_if *iface, struct net_ipv4_igmp_v3_que

enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt, struct net_ipv4_hdr *ip_hdr)
{
#if defined(CONFIG_NET_IPV4_IGMPV3)
NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(igmpv3_access, struct net_ipv4_igmp_v3_query);
struct net_ipv4_igmp_v3_query *igmpv3_hdr;
#endif
int ret;
NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(igmpv2_access, struct net_ipv4_igmp_v2_query);

struct net_ipv4_igmp_v2_query *igmpv2_hdr;
int igmp_buf_len =
pkt->buffer->len - (net_pkt_ip_hdr_len(pkt) + net_pkt_ipv4_opts_len(pkt));
#if defined(CONFIG_NET_IPV4_IGMPV3)
struct net_ipv4_igmp_v3_query *igmpv3_hdr;
enum igmp_version version;
int ret;
int igmp_buf_len = pkt->buffer->len - net_pkt_ip_hdr_len(pkt);

NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(igmpv3_access, struct net_ipv4_igmp_v3_query);

/* Detect IGMP type (RFC 3376 ch 7.1) */
if (igmp_buf_len == 8) {
if (igmp_buf_len == IGMPV2_PAYLOAD_MIN_LEN) {
/* IGMPv1/2 detected */
version = IGMPV2;
} else if (igmp_buf_len >= 12) {
} else if (igmp_buf_len >= IGMPV3_PAYLOAD_MIN_LEN) {
/* IGMPv3 detected */
version = IGMPV3;
#if !defined(CONFIG_NET_IPV4_IGMPV3)
NET_DBG("DROP: %sv3 msg received but %s support is disabled", "IGMP", "IGMP");
return NET_DROP;
#endif
} else {
#else
if (igmp_buf_len < IGMPV2_PAYLOAD_MIN_LEN) {
#endif
NET_DBG("DROP: unsupported payload length");
return NET_DROP;
}
Expand Down
23 changes: 23 additions & 0 deletions subsys/net/ip/igmp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @file
* @brief IGMP definitions
* This is not to be included by the application.
*/

/*
* Copyright (c) 2024 Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef __IGMP_H
#define __IGMP_H

#define IGMPV3_MODE_IS_INCLUDE 0x01
#define IGMPV3_MODE_IS_EXCLUDE 0x02
#define IGMPV3_CHANGE_TO_INCLUDE_MODE 0x03
#define IGMPV3_CHANGE_TO_EXCLUDE_MODE 0x04
#define IGMPV3_ALLOW_NEW_SOURCES 0x05
#define IGMPV3_BLOCK_OLD_SOURCES 0x06

#endif /* __IGMP_H */
61 changes: 56 additions & 5 deletions tests/net/igmp/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV4_LOG_LEVEL);
#include <zephyr/random/random.h>

#include "ipv4.h"
#include "igmp.h"

#define THREAD_SLEEP 50 /* ms */

Expand Down Expand Up @@ -98,37 +99,87 @@ static void net_test_iface_init(struct net_if *iface)
NET_LINK_ETHERNET);
}

#if defined(CONFIG_NET_IPV4_IGMPV3)
static struct net_ipv4_igmp_v3_report *get_igmp_hdr(struct net_pkt *pkt)
#else
static struct net_ipv4_igmp_v2_query *get_igmp_hdr(struct net_pkt *pkt)
#endif
{
net_pkt_cursor_init(pkt);

net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) +
net_pkt_ipv4_opts_len(pkt));

#if defined(CONFIG_NET_IPV4_IGMPV3)
return (struct net_ipv4_igmp_v3_report *)net_pkt_cursor_get_pos(pkt);
#else
return (struct net_ipv4_igmp_v2_query *)net_pkt_cursor_get_pos(pkt);
#endif
}

#if defined(CONFIG_NET_IPV4_IGMPV3)
static struct net_ipv4_igmp_v3_group_record *get_igmp_group_record(struct net_pkt *pkt)
{
net_pkt_cursor_init(pkt);

net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ipv4_opts_len(pkt));
net_pkt_skip(pkt, sizeof(struct net_ipv4_igmp_v3_report));

return (struct net_ipv4_igmp_v3_group_record *)net_pkt_cursor_get_pos(pkt);
}
#endif

static int tester_send(const struct device *dev, struct net_pkt *pkt)
{
struct net_ipv4_igmp_v2_query *igmp;
#if defined(CONFIG_NET_IPV4_IGMPV3)
struct net_ipv4_igmp_v3_report *igmp_header;
struct net_ipv4_igmp_v3_group_record *igmp_group_record;
#else
struct net_ipv4_igmp_v2_query *igmp_header;
#endif

if (!pkt->buffer) {
TC_ERROR("No data to send!\n");
return -ENODATA;
}

igmp = get_igmp_hdr(pkt);
igmp_header = get_igmp_hdr(pkt);

if (igmp->type == NET_IPV4_IGMP_QUERY) {
if (igmp_header->type == NET_IPV4_IGMP_QUERY) {
NET_DBG("Received query....");
is_query_received = true;
k_sem_give(&wait_data);
} else if (igmp->type == NET_IPV4_IGMP_REPORT_V2) {
} else if (igmp_header->type == NET_IPV4_IGMP_REPORT_V2) {
NET_DBG("Received v2 report....");
zassert_false(IS_ENABLED(CONFIG_NET_IPV4_IGMPV3),
"Wrong IGMP report received (IGMPv2)");
is_join_msg_ok = true;
is_report_sent = true;
k_sem_give(&wait_data);
} else if (igmp->type == NET_IPV4_IGMP_LEAVE) {
} else if (igmp_header->type == NET_IPV4_IGMP_REPORT_V3) {
NET_DBG("Received v3 report....");
zassert_true(IS_ENABLED(CONFIG_NET_IPV4_IGMPV3),
"Wrong IGMP report received (IGMPv3)");

#if defined(CONFIG_NET_IPV4_IGMPV3)
zassert_true(ntohs(igmp_header->groups_len) == 1,
"Invalid group length of IGMPv3 report (%d)", igmp_header->groups_len);

igmp_group_record = get_igmp_group_record(pkt);
zassert_true(igmp_group_record->sources_len == 0,
"Invalid sources length of IGMPv3 group record");

if (igmp_group_record->type == IGMPV3_CHANGE_TO_EXCLUDE_MODE) {
is_join_msg_ok = true;
} else if (igmp_group_record->type == IGMPV3_CHANGE_TO_INCLUDE_MODE) {
is_leave_msg_ok = true;
}
#else
is_join_msg_ok = true;
#endif
is_report_sent = true;
k_sem_give(&wait_data);
} else if (igmp_header->type == NET_IPV4_IGMP_LEAVE) {
NET_DBG("Received leave....");
is_leave_msg_ok = true;
k_sem_give(&wait_data);
Expand Down
8 changes: 8 additions & 0 deletions tests/net/igmp/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,11 @@ tests:
net.igmp.preempt:
extra_configs:
- CONFIG_NET_TC_THREAD_PREEMPTIVE=y
net.igmpv3:
extra_configs:
- CONFIG_NET_TC_THREAD_COOPERATIVE=y
- CONFIG_NET_IPV4_IGMPV3=y
net.igmpv3.preempt:
extra_configs:
- CONFIG_NET_TC_THREAD_PREEMPTIVE=y
- CONFIG_NET_IPV4_IGMPV3=y
Loading