mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #15287 from miri64/ethernet/enh/join-leave-mcast-group
gnrc_netif: add capability to join or leave link layer multicast groups
This commit is contained in:
commit
9e4dd8e451
@ -693,12 +693,36 @@ static inline int gnrc_netif_ndp_addr_len_from_l2ao(gnrc_netif_t *netif,
|
||||
assert(netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR);
|
||||
return l2util_ndp_addr_len_from_l2ao(netif->device_type, opt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts an IPv6 multicast address to a multicast address
|
||||
* of the respective link layer.
|
||||
*
|
||||
* @pre There is enough allocated space in @p l2_group for an address for a
|
||||
* device of type @p dev_type (e.g. 6 bytes for an ethernet address).
|
||||
*
|
||||
* @param[in] dev_type The network interface @p l2_addr should be generated
|
||||
* for.
|
||||
* @param[in] ipv6_group An IPv6 multicast address.
|
||||
* @param[out] l2_group A link layer multicast address
|
||||
*
|
||||
* @return Length of @p l2_group in bytes
|
||||
* @return `-ENOTSUP` if link layer does not support multicast.
|
||||
*/
|
||||
static inline int gnrc_netif_ipv6_group_to_l2_group(gnrc_netif_t *netif,
|
||||
const ipv6_addr_t *ipv6_group,
|
||||
uint8_t *l2_group)
|
||||
{
|
||||
return l2util_ipv6_group_to_l2_group(netif->device_type, ipv6_group,
|
||||
l2_group);
|
||||
}
|
||||
#else /* IS_USED(MODULE_GNRC_NETIF_IPV6) || defined(DOXYGEN) */
|
||||
#define gnrc_netif_ipv6_init_mtu(netif) (void)netif
|
||||
#define gnrc_netif_ipv6_iid_from_addr(netif, addr, addr_len, iid) (-ENOTSUP)
|
||||
#define gnrc_netif_ipv6_iid_to_addr(netif, iid, addr) (-ENOTSUP)
|
||||
#define gnrc_netif_ndp_addr_len_from_l2ao(netif, opt) (-ENOTSUP)
|
||||
#define gnrc_netif_ipv6_get_iid(netif, iid) (-ENOTSUP)
|
||||
#define gnrc_netif_ipv6_group_to_l2_group(netif, ipv6_group, l2_group) (-ENOTSUP)
|
||||
#endif /* IS_USED(MODULE_GNRC_NETIF_IPV6) || defined(DOXYGEN) */
|
||||
/** @} */
|
||||
|
||||
|
@ -134,6 +134,25 @@ int l2util_ndp_addr_len_from_l2ao(int dev_type,
|
||||
const ndp_opt_t *opt);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Converts an IPv6 multicast address to a multicast address
|
||||
* of the respective link layer.
|
||||
*
|
||||
* @pre There is enough allocated space in @p l2_group for an address for a
|
||||
* device of type @p dev_type (e.g. 6 bytes for an ethernet address).
|
||||
*
|
||||
* @param[in] dev_type The network device type of the device @p l2_addr
|
||||
* should be generated for.
|
||||
* @param[in] ipv6_group An IPv6 multicast address.
|
||||
* @param[out] l2_group A link layer multicast address
|
||||
*
|
||||
* @return Length of @p l2_group in bytes
|
||||
* @return `-ENOTSUP` if link layer does not support multicast.
|
||||
*/
|
||||
int l2util_ipv6_group_to_l2_group(int dev_type,
|
||||
const ipv6_addr_t *ipv6_group,
|
||||
uint8_t *l2_group);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -747,6 +747,21 @@ typedef enum {
|
||||
*/
|
||||
NETOPT_RSSI,
|
||||
|
||||
/**
|
||||
* @brief (array of byte array) get link layer multicast groups as array
|
||||
* of byte arrays (length of each byte array corresponds to the
|
||||
* length of @ref NETOPT_ADDRESS) or join a link layer multicast
|
||||
* group as byte array on an interface
|
||||
*
|
||||
* When getting the option you can pass an array of byte arrays of any
|
||||
* length greater than 0 to the getter. The array will be filled up to to
|
||||
* its maximum and the remaining addresses on the interface will be ignored
|
||||
*/
|
||||
NETOPT_L2_GROUP,
|
||||
/**
|
||||
* @brief (array of byte arrays) Leave an link layer multicast group
|
||||
*/
|
||||
NETOPT_L2_GROUP_LEAVE,
|
||||
/**
|
||||
* @brief maximum number of options defined here.
|
||||
*
|
||||
|
@ -122,6 +122,8 @@ static const char *_netopt_strmap[] = {
|
||||
[NETOPT_NUM_GATEWAYS] = "NETOPT_NUM_GATEWAYS",
|
||||
[NETOPT_LINK_CHECK] = "NETOPT_LINK_CHECK",
|
||||
[NETOPT_RSSI] = "NETOPT_RSSI",
|
||||
[NETOPT_L2_GROUP] = "NETOPT_L2_GROUP",
|
||||
[NETOPT_L2_GROUP_LEAVE] = "NETOPT_L2_GROUP_LEAVE",
|
||||
[NETOPT_NUMOF] = "NETOPT_NUMOF",
|
||||
};
|
||||
|
||||
|
@ -62,19 +62,19 @@ static inline void _addr_set_broadcast(uint8_t *dst)
|
||||
memset(dst, 0xff, ETHERNET_ADDR_LEN);
|
||||
}
|
||||
|
||||
static inline void _addr_set_multicast(uint8_t *dst, gnrc_pktsnip_t *payload)
|
||||
static inline void _addr_set_multicast(gnrc_netif_t *netif, uint8_t *dst,
|
||||
gnrc_pktsnip_t *payload)
|
||||
{
|
||||
switch (payload->type) {
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
case GNRC_NETTYPE_IPV6:
|
||||
/* https://tools.ietf.org/html/rfc2464#section-7 */
|
||||
dst[0] = 0x33;
|
||||
dst[1] = 0x33;
|
||||
case GNRC_NETTYPE_IPV6: {
|
||||
ipv6_hdr_t *ipv6 = payload->data;
|
||||
memcpy(dst + 2, ipv6->dst.u8 + 12, 4);
|
||||
gnrc_netif_ipv6_group_to_l2_group(netif, &ipv6->dst, dst);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
(void)netif;
|
||||
_addr_set_broadcast(dst);
|
||||
break;
|
||||
}
|
||||
@ -128,7 +128,7 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
|
||||
"are not yet supported\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
_addr_set_multicast(hdr.dst, payload);
|
||||
_addr_set_multicast(netif, hdr.dst, payload);
|
||||
}
|
||||
else if (netif_hdr->dst_l2addr_len == ETHERNET_ADDR_LEN) {
|
||||
memcpy(hdr.dst, gnrc_netif_hdr_get_dst_addr(netif_hdr),
|
||||
|
@ -717,12 +717,44 @@ gnrc_netif_t *gnrc_netif_get_by_prefix(const ipv6_addr_t *prefix)
|
||||
return best_netif;
|
||||
}
|
||||
|
||||
static int _netif_ops_set_helper(gnrc_netif_t *netif, netopt_t opt,
|
||||
void *data, uint16_t data_len)
|
||||
{
|
||||
gnrc_netapi_opt_t netapi_opt = {
|
||||
.opt = opt,
|
||||
.data = data,
|
||||
.data_len = data_len,
|
||||
};
|
||||
return netif->ops->set(netif, &netapi_opt);
|
||||
}
|
||||
|
||||
int gnrc_netif_ipv6_group_join_internal(gnrc_netif_t *netif,
|
||||
const ipv6_addr_t *addr)
|
||||
{
|
||||
uint8_t l2_group_data[GNRC_NETIF_L2ADDR_MAXLEN];
|
||||
unsigned idx = UINT_MAX;
|
||||
int l2_group_len;
|
||||
|
||||
/* can be called out of lock */
|
||||
l2_group_len = gnrc_netif_ipv6_group_to_l2_group(netif, addr,
|
||||
l2_group_data);
|
||||
gnrc_netif_acquire(netif);
|
||||
if (l2_group_len > 0) {
|
||||
int res = _netif_ops_set_helper(netif, NETOPT_L2_GROUP,
|
||||
l2_group_data, (uint16_t)l2_group_len);
|
||||
/* link layer does not support multicast, but we can still use
|
||||
* broadcast */
|
||||
if ((res != -ENOTSUP) && (res < 0)) {
|
||||
gnrc_netif_release(netif);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
/* link layer does not support multicast, but we can still use
|
||||
* broadcast */
|
||||
else if (l2_group_len != -ENOTSUP) {
|
||||
gnrc_netif_release(netif);
|
||||
return l2_group_len;
|
||||
}
|
||||
for (unsigned i = 0; i < GNRC_NETIF_IPV6_GROUPS_NUMOF; i++) {
|
||||
if (ipv6_addr_equal(&netif->ipv6.groups[i], addr)) {
|
||||
gnrc_netif_release(netif);
|
||||
@ -748,11 +780,56 @@ int gnrc_netif_ipv6_group_join_internal(gnrc_netif_t *netif,
|
||||
void gnrc_netif_ipv6_group_leave_internal(gnrc_netif_t *netif,
|
||||
const ipv6_addr_t *addr)
|
||||
{
|
||||
int idx;
|
||||
uint8_t l2_group_data[GNRC_NETIF_L2ADDR_MAXLEN];
|
||||
int idx = -1, l2_group_len;
|
||||
/* IPv6 addresses that correspond to the same L2 address */
|
||||
unsigned l2_groups = 0;
|
||||
|
||||
assert((netif != NULL) && (addr != NULL));
|
||||
/* can be called out of lock */
|
||||
l2_group_len = gnrc_netif_ipv6_group_to_l2_group(netif, addr,
|
||||
l2_group_data);
|
||||
/* link layer does not support multicast, but might still have used
|
||||
* broadcast */
|
||||
if ((l2_group_len < 0) && (l2_group_len != -ENOTSUP)) {
|
||||
return;
|
||||
}
|
||||
gnrc_netif_acquire(netif);
|
||||
idx = _group_idx(netif, addr);
|
||||
for (unsigned i = 0; i < GNRC_NETIF_IPV6_GROUPS_NUMOF; i++) {
|
||||
if (l2_group_len > 0) {
|
||||
uint8_t tmp[GNRC_NETIF_L2ADDR_MAXLEN];
|
||||
if (!ipv6_addr_is_unspecified(&netif->ipv6.groups[i]) &&
|
||||
(gnrc_netif_ipv6_group_to_l2_group(netif,
|
||||
&netif->ipv6.groups[i],
|
||||
tmp) == l2_group_len)) {
|
||||
if (memcmp(tmp, l2_group_data, l2_group_len) == 0) {
|
||||
l2_groups++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ipv6_addr_equal(&netif->ipv6.groups[i], addr)) {
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
if (idx < 0) {
|
||||
gnrc_netif_release(netif);
|
||||
return;
|
||||
}
|
||||
/* we need to have found at least one corresponding group for the IPv6
|
||||
* group we want to leave when link layer supports multicast */
|
||||
assert((l2_group_len == -ENOTSUP) || (l2_groups > 0));
|
||||
/* we only found exactly IPv6 multicast address that corresponds to
|
||||
* `l2_group_data`, so we can remove it, if there would be more, we need
|
||||
* to stay in the group */
|
||||
if (l2_groups == 1) {
|
||||
int res = _netif_ops_set_helper(netif, NETOPT_L2_GROUP_LEAVE,
|
||||
l2_group_data, (uint16_t)l2_group_len);
|
||||
/* link layer does not support multicast, but might still have used
|
||||
* broadcast */
|
||||
if ((res != -ENOTSUP) && (res < 0)) {
|
||||
DEBUG("gnrc_netif: error leaving link layer group\n");
|
||||
}
|
||||
}
|
||||
if (idx >= 0) {
|
||||
ipv6_addr_set_unspecified(&netif->ipv6.groups[idx]);
|
||||
/* TODO:
|
||||
|
@ -238,5 +238,27 @@ int l2util_ndp_addr_len_from_l2ao(int dev_type,
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int l2util_ipv6_group_to_l2_group(int dev_type,
|
||||
const ipv6_addr_t *ipv6_group,
|
||||
uint8_t *l2_group)
|
||||
{
|
||||
switch (dev_type) {
|
||||
#if IS_USED(MODULE_NETDEV_ETH)
|
||||
case NETDEV_TYPE_ETHERNET:
|
||||
/* see https://tools.ietf.org/html/rfc2464#section-7 */
|
||||
l2_group[0] = 0x33;
|
||||
l2_group[1] = 0x33;
|
||||
l2_group[2] = ipv6_group->u8[12];
|
||||
l2_group[3] = ipv6_group->u8[13];
|
||||
l2_group[4] = ipv6_group->u8[14];
|
||||
l2_group[5] = ipv6_group->u8[15];
|
||||
return sizeof(eui48_t);
|
||||
#endif
|
||||
default:
|
||||
(void)ipv6_group;
|
||||
(void)l2_group;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bitfield.h"
|
||||
#include "common.h"
|
||||
#include "embUnit.h"
|
||||
#include "embUnit/embUnit.h"
|
||||
@ -41,6 +42,7 @@
|
||||
|
||||
#define ETHERNET_STACKSIZE (THREAD_STACKSIZE_MAIN)
|
||||
#define IEEE802154_STACKSIZE (THREAD_STACKSIZE_MAIN)
|
||||
#define ETHERNET_GROUPS_MAX 8U
|
||||
|
||||
static gnrc_netif_t ethernet_netif;
|
||||
static gnrc_netif_t ieee802154_netif;
|
||||
@ -50,6 +52,9 @@ static char ieee802154_netif_stack[ETHERNET_STACKSIZE];
|
||||
static char netifs_stack[DEFAULT_DEVS_NUMOF][THREAD_STACKSIZE_DEFAULT];
|
||||
static bool init_called = false;
|
||||
|
||||
static uint8_t ethernet_groups[ETHERNET_GROUPS_MAX][ETHERNET_ADDR_LEN];
|
||||
static BITFIELD(ethernet_groups_set, ETHERNET_GROUPS_MAX);
|
||||
|
||||
static inline void _test_init(gnrc_netif_t *netif);
|
||||
static inline int _mock_netif_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt);
|
||||
static inline gnrc_pktsnip_t *_mock_netif_recv(gnrc_netif_t * netif);
|
||||
@ -62,6 +67,11 @@ static int _set_netdev_address_long(netdev_t *dev, const void *value,
|
||||
static int _get_netdev_src_len(netdev_t *dev, void *value, size_t max_len);
|
||||
static int _set_netdev_src_len(netdev_t *dev, const void *value,
|
||||
size_t value_len);
|
||||
static int _get_netdev_l2_group(netdev_t *dev, void *value, size_t max_len);
|
||||
static int _set_netdev_l2_group(netdev_t *dev, const void *value,
|
||||
size_t value_len);
|
||||
static int _set_netdev_l2_group_leave(netdev_t *dev, const void *value,
|
||||
size_t value_len);
|
||||
|
||||
static const gnrc_netif_ops_t default_ops = {
|
||||
.init = _test_init,
|
||||
@ -76,6 +86,8 @@ static void _set_up(void)
|
||||
{
|
||||
msg_t msg;
|
||||
|
||||
/* reset ethernet groups */
|
||||
memset(ethernet_groups_set, 0, sizeof(ethernet_groups_set));
|
||||
memset(ethernet_netif.ipv6.addrs_flags, 0,
|
||||
sizeof(ethernet_netif.ipv6.addrs_flags));
|
||||
memset(ethernet_netif.ipv6.addrs, 0,
|
||||
@ -915,6 +927,55 @@ static void test_netapi_get__ADDRESS_LONG(void)
|
||||
&value, sizeof(value)));
|
||||
}
|
||||
|
||||
static void test_netapi_set_get__L2_GROUP(void)
|
||||
{
|
||||
static const uint8_t exp_group1[] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 };
|
||||
static const uint8_t exp_group2[] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x02 };
|
||||
uint8_t value[2][ETHERNET_ADDR_LEN];
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(exp_group1),
|
||||
gnrc_netapi_set(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&exp_group1, sizeof(exp_group1)));
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(exp_group2),
|
||||
gnrc_netapi_set(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&exp_group2, sizeof(exp_group2)));
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(value),
|
||||
gnrc_netapi_get(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&value, sizeof(value)));
|
||||
TEST_ASSERT_EQUAL_INT(0, memcmp(exp_group1, value[0], sizeof(exp_group1)));
|
||||
TEST_ASSERT_EQUAL_INT(0, memcmp(exp_group2, value[1], sizeof(exp_group2)));
|
||||
TEST_ASSERT_EQUAL_INT(-ENOTSUP,
|
||||
gnrc_netapi_get(ieee802154_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&value, sizeof(value)));
|
||||
}
|
||||
|
||||
static void test_netapi_set__L2_GROUP_LEAVE(void)
|
||||
{
|
||||
static const uint8_t exp_group1[] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 };
|
||||
static const uint8_t exp_group2[] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x02 };
|
||||
uint8_t value[2][ETHERNET_ADDR_LEN];
|
||||
|
||||
test_netapi_set_get__L2_GROUP();
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(exp_group1),
|
||||
gnrc_netapi_set(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP_LEAVE, 0,
|
||||
&exp_group1, sizeof(exp_group1)));
|
||||
/* exp_group1 was removed */
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(exp_group2),
|
||||
gnrc_netapi_get(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&value, sizeof(value)));
|
||||
TEST_ASSERT_EQUAL_INT(0, memcmp(exp_group2, value[0], sizeof(exp_group2)));
|
||||
TEST_ASSERT_EQUAL_INT(-ENOTSUP,
|
||||
gnrc_netapi_get(ieee802154_netif.pid,
|
||||
NETOPT_L2_GROUP_LEAVE, 0,
|
||||
&value, sizeof(value)));
|
||||
}
|
||||
|
||||
static void test_netapi_set__HOP_LIMIT(void)
|
||||
{
|
||||
uint8_t value = 89;
|
||||
@ -965,6 +1026,30 @@ static void test_netapi_set__IPV6_GROUP(void)
|
||||
TEST_ASSERT(0 <= gnrc_netif_ipv6_group_idx(&netifs[0], &value));
|
||||
}
|
||||
|
||||
static void test_netapi_set__IPV6_GROUP__ethernet(void)
|
||||
{
|
||||
ipv6_addr_t value = IPV6_ADDR_ALL_NODES_LINK_LOCAL;
|
||||
uint8_t exp_ethernet[ETHERNET_ADDR_LEN];
|
||||
uint8_t l2_value[1][ETHERNET_ADDR_LEN];
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(exp_ethernet),
|
||||
gnrc_netif_ipv6_group_to_l2_group(ðernet_netif,
|
||||
&value,
|
||||
exp_ethernet));
|
||||
TEST_ASSERT(0 > gnrc_netif_ipv6_group_idx(ðernet_netif, &value));
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(value),
|
||||
gnrc_netapi_set(ethernet_netif.pid,
|
||||
NETOPT_IPV6_GROUP, 0,
|
||||
&value, sizeof(value)));
|
||||
TEST_ASSERT(0 <= gnrc_netif_ipv6_group_idx(ðernet_netif, &value));
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(exp_ethernet),
|
||||
gnrc_netapi_get(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&l2_value, sizeof(l2_value)));
|
||||
TEST_ASSERT_EQUAL_INT(0, memcmp(exp_ethernet, l2_value[0],
|
||||
sizeof(exp_ethernet)));
|
||||
}
|
||||
|
||||
static void test_netapi_set__IPV6_GROUP_LEAVE(void)
|
||||
{
|
||||
ipv6_addr_t value = IPV6_ADDR_ALL_NODES_LINK_LOCAL;
|
||||
@ -978,6 +1063,87 @@ static void test_netapi_set__IPV6_GROUP_LEAVE(void)
|
||||
TEST_ASSERT(0 > gnrc_netif_ipv6_group_idx(&netifs[0], &value));
|
||||
}
|
||||
|
||||
static void test_netapi_set__IPV6_GROUP_LEAVE__ethernet(void)
|
||||
{
|
||||
ipv6_addr_t value = IPV6_ADDR_ALL_NODES_LINK_LOCAL;
|
||||
uint8_t l2_value[1][ETHERNET_ADDR_LEN];
|
||||
|
||||
/* no L2 group assigned */
|
||||
TEST_ASSERT_EQUAL_INT(0,
|
||||
gnrc_netapi_get(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&l2_value, sizeof(l2_value)));
|
||||
/* join a group */
|
||||
test_netapi_set__IPV6_GROUP__ethernet();
|
||||
TEST_ASSERT(0 <= gnrc_netif_ipv6_group_idx(ðernet_netif, &value));
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(value),
|
||||
gnrc_netapi_set(ethernet_netif.pid,
|
||||
NETOPT_IPV6_GROUP_LEAVE, 0,
|
||||
&value, sizeof(value)));
|
||||
TEST_ASSERT(0 > gnrc_netif_ipv6_group_idx(ðernet_netif, &value));
|
||||
/* no L2 group assigned */
|
||||
TEST_ASSERT_EQUAL_INT(0,
|
||||
gnrc_netapi_get(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&l2_value, sizeof(l2_value)));
|
||||
}
|
||||
|
||||
static void test_netapi_set__IPV6_GROUP_LEAVE__ethernet_two_same(void)
|
||||
{
|
||||
ipv6_addr_t value1 = IPV6_ADDR_ALL_NODES_LINK_LOCAL;
|
||||
ipv6_addr_t value2 = IPV6_ADDR_ALL_NODES_IF_LOCAL;
|
||||
uint8_t exp_ethernet[ETHERNET_ADDR_LEN];
|
||||
uint8_t l2_value[2][ETHERNET_ADDR_LEN];
|
||||
|
||||
/* no L2 group assigned */
|
||||
TEST_ASSERT_EQUAL_INT(0,
|
||||
gnrc_netapi_get(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&l2_value, sizeof(l2_value)));
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(exp_ethernet),
|
||||
gnrc_netif_ipv6_group_to_l2_group(ðernet_netif,
|
||||
&value1,
|
||||
exp_ethernet));
|
||||
/* join a group */
|
||||
test_netapi_set__IPV6_GROUP__ethernet();
|
||||
TEST_ASSERT(0 <= gnrc_netif_ipv6_group_idx(ðernet_netif, &value1));
|
||||
/* join another IPv6 group with same suffix */
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(value2),
|
||||
gnrc_netapi_set(ethernet_netif.pid,
|
||||
NETOPT_IPV6_GROUP, 0,
|
||||
&value2, sizeof(value2)));
|
||||
TEST_ASSERT(0 <= gnrc_netif_ipv6_group_idx(ðernet_netif, &value2));
|
||||
/* only one link layer group joined due to the same suffix */
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(exp_ethernet),
|
||||
gnrc_netapi_get(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&l2_value, sizeof(l2_value)));
|
||||
TEST_ASSERT_EQUAL_INT(0, memcmp(exp_ethernet, l2_value[0],
|
||||
sizeof(exp_ethernet)));
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(value1),
|
||||
gnrc_netapi_set(ethernet_netif.pid,
|
||||
NETOPT_IPV6_GROUP_LEAVE, 0,
|
||||
&value1, sizeof(value1)));
|
||||
TEST_ASSERT(0 > gnrc_netif_ipv6_group_idx(ðernet_netif, &value1));
|
||||
/* still in link layer group due to other IPv6 group */
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(exp_ethernet),
|
||||
gnrc_netapi_get(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&l2_value, sizeof(l2_value)));
|
||||
TEST_ASSERT_EQUAL_INT(0, memcmp(exp_ethernet, l2_value[0],
|
||||
sizeof(exp_ethernet)));
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(value2),
|
||||
gnrc_netapi_set(ethernet_netif.pid,
|
||||
NETOPT_IPV6_GROUP_LEAVE, 0,
|
||||
&value2, sizeof(value2)));
|
||||
TEST_ASSERT(0 > gnrc_netif_ipv6_group_idx(ðernet_netif, &value2));
|
||||
/* no L2 group assigned */
|
||||
TEST_ASSERT_EQUAL_INT(0,
|
||||
gnrc_netapi_get(ethernet_netif.pid,
|
||||
NETOPT_L2_GROUP, 0,
|
||||
&l2_value, sizeof(l2_value)));
|
||||
}
|
||||
|
||||
static void test_netapi_set__MAX_PACKET_SIZE(void)
|
||||
{
|
||||
uint16_t value = 57194;
|
||||
@ -1574,11 +1740,16 @@ static Test *embunit_tests_gnrc_netif(void)
|
||||
new_TestFixture(test_netapi_get__6LO_IPHC),
|
||||
new_TestFixture(test_netapi_get__ADDRESS),
|
||||
new_TestFixture(test_netapi_get__ADDRESS_LONG),
|
||||
new_TestFixture(test_netapi_set_get__L2_GROUP),
|
||||
new_TestFixture(test_netapi_set__L2_GROUP_LEAVE),
|
||||
new_TestFixture(test_netapi_set__HOP_LIMIT),
|
||||
new_TestFixture(test_netapi_set__IPV6_ADDR),
|
||||
new_TestFixture(test_netapi_set__IPV6_ADDR_REMOVE),
|
||||
new_TestFixture(test_netapi_set__IPV6_GROUP),
|
||||
new_TestFixture(test_netapi_set__IPV6_GROUP__ethernet),
|
||||
new_TestFixture(test_netapi_set__IPV6_GROUP_LEAVE),
|
||||
new_TestFixture(test_netapi_set__IPV6_GROUP_LEAVE__ethernet),
|
||||
new_TestFixture(test_netapi_set__IPV6_GROUP_LEAVE__ethernet_two_same),
|
||||
new_TestFixture(test_netapi_set__MAX_PACKET_SIZE),
|
||||
new_TestFixture(test_netapi_set__6LO_IPHC),
|
||||
new_TestFixture(test_netapi_set__ADDRESS),
|
||||
@ -1603,6 +1774,12 @@ int main(void)
|
||||
_get_netdev_address);
|
||||
netdev_test_set_set_cb((netdev_test_t *)ethernet_dev, NETOPT_ADDRESS,
|
||||
_set_netdev_address);
|
||||
netdev_test_set_get_cb((netdev_test_t *)ethernet_dev, NETOPT_L2_GROUP,
|
||||
_get_netdev_l2_group);
|
||||
netdev_test_set_set_cb((netdev_test_t *)ethernet_dev, NETOPT_L2_GROUP,
|
||||
_set_netdev_l2_group);
|
||||
netdev_test_set_set_cb((netdev_test_t *)ethernet_dev, NETOPT_L2_GROUP_LEAVE,
|
||||
_set_netdev_l2_group_leave);
|
||||
netdev_test_set_get_cb((netdev_test_t *)ieee802154_dev, NETOPT_ADDRESS,
|
||||
_get_netdev_address);
|
||||
netdev_test_set_set_cb((netdev_test_t *)ieee802154_dev, NETOPT_ADDRESS,
|
||||
@ -1738,3 +1915,68 @@ static int _set_netdev_src_len(netdev_t *dev, const void *value,
|
||||
}
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int _get_netdev_l2_group(netdev_t *dev, void *value, size_t max_len)
|
||||
{
|
||||
(void)max_len;
|
||||
|
||||
if (dev == ethernet_dev) {
|
||||
expect(max_len >= ETHERNET_ADDR_LEN);
|
||||
int res = 0;
|
||||
|
||||
for (unsigned i = 0; res < (int)max_len && i < ETHERNET_GROUPS_MAX; i++) {
|
||||
if (bf_isset(ethernet_groups_set, i)) {
|
||||
memcpy(((uint8_t *)value) + res, ethernet_groups[i],
|
||||
ETHERNET_ADDR_LEN);
|
||||
res += ETHERNET_ADDR_LEN;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int _set_netdev_l2_group(netdev_t *dev, const void *value,
|
||||
size_t value_len)
|
||||
{
|
||||
if (dev == ethernet_dev) {
|
||||
int idx = -ENOMEM;
|
||||
|
||||
expect(value_len >= ETHERNET_ADDR_LEN);
|
||||
for (unsigned i = 0; i < ETHERNET_GROUPS_MAX; i++) {
|
||||
if (bf_isset(ethernet_groups_set, i)) {
|
||||
if (memcmp(value, ethernet_groups[i],
|
||||
sizeof(ethernet_groups[i])) == 0) {
|
||||
return ETHERNET_ADDR_LEN;
|
||||
}
|
||||
}
|
||||
else if (idx < 0) {
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
if (idx >= 0) {
|
||||
memcpy(ethernet_groups[idx], value, sizeof(ethernet_groups[idx]));
|
||||
bf_set(ethernet_groups_set, idx);
|
||||
return ETHERNET_ADDR_LEN;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int _set_netdev_l2_group_leave(netdev_t *dev, const void *value,
|
||||
size_t value_len)
|
||||
{
|
||||
if (dev == ethernet_dev) {
|
||||
expect(value_len >= ETHERNET_ADDR_LEN);
|
||||
for (unsigned i = 0; i < ETHERNET_GROUPS_MAX; i++) {
|
||||
if (bf_isset(ethernet_groups_set, i) &&
|
||||
(memcmp(value, ethernet_groups[i],
|
||||
sizeof(ethernet_groups[i])) == 0)) {
|
||||
bf_unset(ethernet_groups_set, i);
|
||||
}
|
||||
}
|
||||
return ETHERNET_ADDR_LEN;
|
||||
}
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
6
tests/l2util/Makefile.ci
Normal file
6
tests/l2util/Makefile.ci
Normal file
@ -0,0 +1,6 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
arduino-duemilanove \
|
||||
arduino-nano \
|
||||
arduino-uno \
|
||||
atmega328p \
|
||||
#
|
@ -32,6 +32,10 @@
|
||||
#define TEST_EUI48_EUI64 { 0x21, 0x55, 0x31, 0xff, 0xfe, 0x02, 0x41, 0xfd }
|
||||
#define TEST_EUI48_IID { 0x23, 0x55, 0x31, 0xff, 0xfe, 0x02, 0x41, 0xfd }
|
||||
#define TEST_EUI64_IID { 0x23, 0x55, 0x31, 0x02, 0x41, 0xfd, 0xfb, 0xfd }
|
||||
#define TEST_IPV6_GROUP { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x3f, 0x6c, 0xa1, 0xbb, 0xe5, 0x03, 0x6b, 0xe2 }
|
||||
/* see https://tools.ietf.org/html/rfc2464#section-7 */
|
||||
#define TEST_ETHERNET_GROUP { 0x33, 0x33, 0xe5, 0x03, 0x6b, 0xe2 }
|
||||
|
||||
static void test_eui64_from_addr__success(void)
|
||||
{
|
||||
@ -381,6 +385,37 @@ static void test_addr_len_from_l2ao__ENOTSUP(void)
|
||||
&opt));
|
||||
}
|
||||
|
||||
static void test_ipv6_group_to_l2group__success(void)
|
||||
{
|
||||
static const ipv6_addr_t test_group = {
|
||||
.u8 = TEST_IPV6_GROUP,
|
||||
};
|
||||
static const eui48_t test_ethernet = {
|
||||
.uint8 = TEST_ETHERNET_GROUP,
|
||||
};
|
||||
uint8_t res[L2UTIL_ADDR_MAX_LEN];
|
||||
|
||||
/* test Ethernet */
|
||||
memset(res, 0, sizeof(res));
|
||||
TEST_ASSERT_EQUAL_INT(sizeof(test_ethernet),
|
||||
l2util_ipv6_group_to_l2_group(NETDEV_TYPE_ETHERNET,
|
||||
&test_group, res));
|
||||
TEST_ASSERT_EQUAL_INT(0, memcmp(&test_ethernet, res,
|
||||
sizeof(test_ethernet)));
|
||||
}
|
||||
|
||||
static void test_ipv6_group_to_l2group__ENOTSUP(void)
|
||||
{
|
||||
static const ipv6_addr_t test_group = {
|
||||
.u8 = TEST_IPV6_GROUP,
|
||||
};
|
||||
uint8_t res[L2UTIL_ADDR_MAX_LEN];
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(-ENOTSUP,
|
||||
l2util_ipv6_group_to_l2_group(NETDEV_TYPE_UNKNOWN,
|
||||
&test_group, res));
|
||||
}
|
||||
|
||||
TestRef test_l2util(void)
|
||||
{
|
||||
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||
@ -395,6 +430,8 @@ TestRef test_l2util(void)
|
||||
new_TestFixture(test_addr_len_from_l2ao__success),
|
||||
new_TestFixture(test_addr_len_from_l2ao__EINVAL),
|
||||
new_TestFixture(test_addr_len_from_l2ao__ENOTSUP),
|
||||
new_TestFixture(test_ipv6_group_to_l2group__success),
|
||||
new_TestFixture(test_ipv6_group_to_l2group__ENOTSUP),
|
||||
};
|
||||
|
||||
EMB_UNIT_TESTCALLER(tests_l2util, NULL, NULL, fixtures);
|
||||
|
Loading…
Reference in New Issue
Block a user