mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #3628 from authmillenon/ng_ndp/enh/0-length-addr
gnrc_ndp: add support for address-less link-layers
This commit is contained in:
commit
6786da07e2
@ -19,8 +19,8 @@
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef INTERNAL_H_
|
||||
#define INTERNAL_H_
|
||||
#ifndef GNRC_NDP_INTERNAL_H_
|
||||
#define GNRC_NDP_INTERNAL_H_
|
||||
|
||||
#include "net/ipv6/addr.h"
|
||||
#include "net/ipv6/hdr.h"
|
||||
@ -91,23 +91,22 @@ void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_a
|
||||
/**
|
||||
* @brief Handles a SL2A option.
|
||||
*
|
||||
* @param[in] iface Interface the option was received on.
|
||||
* @param[in] pkt Packet the option was received in.
|
||||
* @param[in] ipv6 IPv6 header of @p pkt
|
||||
* @param[in] icmpv6_type ICMPv6 type of the message carrying the option.
|
||||
* @param[in] sl2a_opt The SL2A option.
|
||||
* @param[in] tl2a_opt The TL2A option.
|
||||
* @param[out] l2addr The L2 address carried in the SL2A option.
|
||||
*
|
||||
* @return true, on success.
|
||||
* @return false, if SL2A was not valid.
|
||||
* @return length of the L2 address, on success.
|
||||
* @return -EINVAL, if SL2A was not valid.
|
||||
* @return -ENOTSUP, if node should silently ignore the option.
|
||||
*/
|
||||
bool gnrc_ndp_internal_sl2a_opt_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
|
||||
ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ndp_opt_t *sl2a_opt);
|
||||
int gnrc_ndp_internal_sl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ndp_opt_t *sl2a_opt, uint8_t *l2addr);
|
||||
|
||||
/**
|
||||
* @brief Handles a TL2A option.
|
||||
*
|
||||
* @param[in] iface Interface the option was received on.
|
||||
* @param[in] pkt Packet the option was received in.
|
||||
* @param[in] ipv6 IPv6 header of @p pkt
|
||||
* @param[in] icmpv6_type ICMPv6 type of the message carrying the option.
|
||||
@ -116,6 +115,7 @@ bool gnrc_ndp_internal_sl2a_opt_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
|
||||
*
|
||||
* @return length of the L2 address, on success.
|
||||
* @return -EINVAL, if TL2A was not valid.
|
||||
* @return -ENOTSUP, if node should silently ignore the option.
|
||||
*/
|
||||
int gnrc_ndp_internal_tl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6,
|
||||
uint8_t icmpv6_type, ndp_opt_t *tl2a_opt,
|
||||
@ -125,5 +125,5 @@ int gnrc_ndp_internal_tl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6,
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INTERNAL_H_ */
|
||||
#endif /* GNRC_NDP_INTERNAL_H_ */
|
||||
/** @} */
|
||||
|
@ -43,23 +43,42 @@
|
||||
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
#endif
|
||||
|
||||
/* random helper function */
|
||||
/* sets an entry to stale if its l2addr differs from the given one or creates it stale if it
|
||||
* does not exist */
|
||||
static void _stale_nc(kernel_pid_t iface, ipv6_addr_t *ipaddr, uint8_t *l2addr,
|
||||
int l2addr_len)
|
||||
{
|
||||
if (l2addr_len != -ENOTSUP) {
|
||||
gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, ipaddr);
|
||||
if (nc_entry == NULL) {
|
||||
gnrc_ipv6_nc_add(iface, ipaddr, l2addr, (uint16_t)l2addr_len,
|
||||
GNRC_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
else if (((uint16_t)l2addr_len != nc_entry->l2_addr_len) ||
|
||||
(memcmp(l2addr, nc_entry->l2_addr, l2addr_len) != 0)) {
|
||||
/* if entry exists but l2 address differs: set */
|
||||
nc_entry->l2_addr_len = (uint16_t)l2addr_len;
|
||||
memcpy(nc_entry->l2_addr, l2addr, l2addr_len);
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
|
||||
ipv6_hdr_t *ipv6, ndp_nbr_sol_t *nbr_sol,
|
||||
size_t icmpv6_size)
|
||||
{
|
||||
uint16_t opt_offset = 0;
|
||||
uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
|
||||
uint8_t *buf = ((uint8_t *)nbr_sol) + sizeof(ndp_nbr_sol_t);
|
||||
ipv6_addr_t *tgt;
|
||||
int sicmpv6_size = (int)icmpv6_size;
|
||||
|
||||
int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
|
||||
DEBUG("ndp: received neighbor solicitation (src: %s, ",
|
||||
ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str)));
|
||||
DEBUG("dst: %s, ",
|
||||
ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str)));
|
||||
DEBUG("tgt: %s)\n",
|
||||
ipv6_addr_to_str(addr_str, &nbr_sol->tgt, sizeof(addr_str)));
|
||||
|
||||
/* check validity */
|
||||
if ((ipv6->hl != 255) || (nbr_sol->code != 0) ||
|
||||
(icmpv6_size < sizeof(ndp_nbr_sol_t)) ||
|
||||
@ -70,41 +89,37 @@ void gnrc_ndp_nbr_sol_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
|
||||
/* ipv6 releases */
|
||||
return;
|
||||
}
|
||||
|
||||
if ((tgt = gnrc_ipv6_netif_find_addr(iface, &nbr_sol->tgt)) == NULL) {
|
||||
DEBUG("ndp: Target address is not to interface %" PRIkernel_pid "\n",
|
||||
iface);
|
||||
/* ipv6 releases */
|
||||
return;
|
||||
}
|
||||
|
||||
sicmpv6_size -= sizeof(ndp_nbr_sol_t);
|
||||
|
||||
while (sicmpv6_size > 0) {
|
||||
ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);
|
||||
|
||||
switch (opt->type) {
|
||||
case NDP_OPT_SL2A:
|
||||
if (!gnrc_ndp_internal_sl2a_opt_handle(iface, pkt, ipv6, nbr_sol->type, opt)) {
|
||||
/* invalid source link-layer address option */
|
||||
if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, nbr_sol->type, opt,
|
||||
l2src)) < 0) {
|
||||
/* -ENOTSUP can not happen, since the function only returns this for invalid
|
||||
* message types containing the SL2A. Neighbor solicitations are not an
|
||||
* invalid message type for SL2A. According to that, we don't need to watch
|
||||
* out for that here, but regardless, the source link-layer address option
|
||||
* is invalid. */
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
/* silently discard all other options */
|
||||
break;
|
||||
}
|
||||
|
||||
opt_offset += (opt->len * 8);
|
||||
sicmpv6_size -= (opt->len * 8);
|
||||
}
|
||||
|
||||
_stale_nc(iface, &ipv6->src, l2src, l2src_len);
|
||||
gnrc_ndp_internal_send_nbr_adv(iface, tgt, &ipv6->src, ipv6_addr_is_multicast(&ipv6->dst),
|
||||
NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static inline bool _pkt_has_l2addr(gnrc_netif_hdr_t *netif_hdr)
|
||||
@ -178,66 +193,24 @@ void gnrc_ndp_nbr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
|
||||
netif_hdr = netif->data;
|
||||
}
|
||||
|
||||
if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_INCOMPLETE) {
|
||||
gnrc_pktqueue_t *queued_pkt;
|
||||
if (l2tgt_len != -ENOTSUP) {
|
||||
if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_INCOMPLETE) {
|
||||
gnrc_pktqueue_t *queued_pkt;
|
||||
|
||||
if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len == 0)) {
|
||||
/* link-layer has addresses, but no TLLAO supplied: discard silently
|
||||
* (see https://tools.ietf.org/html/rfc4861#section-7.2.5) */
|
||||
return;
|
||||
}
|
||||
|
||||
nc_entry->iface = iface;
|
||||
nc_entry->l2_addr_len = l2tgt_len;
|
||||
memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len);
|
||||
|
||||
if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) {
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_REACHABLE);
|
||||
}
|
||||
else {
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
|
||||
if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_R) {
|
||||
nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER;
|
||||
}
|
||||
else {
|
||||
nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER;
|
||||
/* TODO: update FIB */
|
||||
}
|
||||
|
||||
while ((queued_pkt = gnrc_pktqueue_remove_head(&nc_entry->pkts)) != NULL) {
|
||||
gnrc_netapi_send(gnrc_ipv6_pid, queued_pkt->pkt);
|
||||
queued_pkt->pkt = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* first or-term: no link-layer, but nc_entry has l2addr,
|
||||
* second or-term: different l2addr cached */
|
||||
bool l2tgt_changed = false;
|
||||
|
||||
if ((!_pkt_has_l2addr(netif_hdr)) && (l2tgt_len == 0)) {
|
||||
/* there was previously a L2 address registered */
|
||||
l2tgt_changed = (nc_entry->l2_addr_len != 0);
|
||||
}
|
||||
/* link-layer has addresses and TLLAO with different address */
|
||||
else if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len != 0)) {
|
||||
l2tgt_changed = (!(l2tgt_len == nc_entry->l2_addr_len)) &&
|
||||
(memcmp(nc_entry->l2_addr, l2tgt, l2tgt_len) == 0);
|
||||
}
|
||||
|
||||
if ((nbr_adv->flags & NDP_NBR_ADV_FLAGS_O) || !l2tgt_changed ||
|
||||
(l2tgt_len == 0)) {
|
||||
if (l2tgt_len != 0) {
|
||||
nc_entry->iface = iface;
|
||||
nc_entry->l2_addr_len = l2tgt_len;
|
||||
memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len);
|
||||
if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len == 0)) {
|
||||
/* link-layer has addresses, but no TLLAO supplied: discard silently
|
||||
* (see https://tools.ietf.org/html/rfc4861#section-7.2.5) */
|
||||
return;
|
||||
}
|
||||
|
||||
nc_entry->iface = iface;
|
||||
nc_entry->l2_addr_len = l2tgt_len;
|
||||
memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len);
|
||||
|
||||
if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) {
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_REACHABLE);
|
||||
}
|
||||
else if (l2tgt_changed && (l2tgt_len != 0)) {
|
||||
else {
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
|
||||
@ -246,13 +219,55 @@ void gnrc_ndp_nbr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
|
||||
}
|
||||
else {
|
||||
nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER;
|
||||
/* TODO: update FIB */
|
||||
/* TODO: update state of neighbor as router in FIB? */
|
||||
}
|
||||
|
||||
while ((queued_pkt = gnrc_pktqueue_remove_head(&nc_entry->pkts)) != NULL) {
|
||||
gnrc_netapi_send(gnrc_ipv6_pid, queued_pkt->pkt);
|
||||
queued_pkt->pkt = NULL;
|
||||
}
|
||||
}
|
||||
else if (l2tgt_changed) {
|
||||
if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_REACHABLE) {
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
|
||||
else {
|
||||
/* first or-term: no link-layer, but nc_entry has l2addr,
|
||||
* second or-term: different l2addr cached */
|
||||
bool l2tgt_changed = false;
|
||||
|
||||
if ((!_pkt_has_l2addr(netif_hdr)) && (l2tgt_len == 0)) {
|
||||
/* there was previously a L2 address registered */
|
||||
l2tgt_changed = (nc_entry->l2_addr_len != 0);
|
||||
}
|
||||
/* link-layer has addresses and TLLAO with different address */
|
||||
else if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len != 0)) {
|
||||
l2tgt_changed = (!(l2tgt_len == nc_entry->l2_addr_len)) &&
|
||||
(memcmp(nc_entry->l2_addr, l2tgt, l2tgt_len) == 0);
|
||||
}
|
||||
|
||||
if ((nbr_adv->flags & NDP_NBR_ADV_FLAGS_O) || !l2tgt_changed ||
|
||||
(l2tgt_len == 0)) {
|
||||
if (l2tgt_len != 0) {
|
||||
nc_entry->iface = iface;
|
||||
nc_entry->l2_addr_len = l2tgt_len;
|
||||
memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len);
|
||||
}
|
||||
|
||||
if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) {
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_REACHABLE);
|
||||
}
|
||||
else if (l2tgt_changed) {
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
|
||||
if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_R) {
|
||||
nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER;
|
||||
}
|
||||
else {
|
||||
nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER;
|
||||
/* TODO: update state of neighbor as router in FIB? */
|
||||
}
|
||||
}
|
||||
else if (l2tgt_changed &&
|
||||
gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_REACHABLE) {
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -311,17 +311,15 @@ void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *tgt,
|
||||
gnrc_netapi_send(gnrc_ipv6_pid, pkt);
|
||||
}
|
||||
|
||||
bool gnrc_ndp_internal_sl2a_opt_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
|
||||
ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ndp_opt_t *sl2a_opt)
|
||||
int gnrc_ndp_internal_sl2a_opt_handle(gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
|
||||
ndp_opt_t *sl2a_opt, uint8_t *l2src)
|
||||
{
|
||||
gnrc_ipv6_nc_t *nc_entry = NULL;
|
||||
uint8_t sl2a_len = 0;
|
||||
int sl2a_len = 0;
|
||||
uint8_t *sl2a = (uint8_t *)(sl2a_opt + 1);
|
||||
|
||||
if ((sl2a_opt->len == 0) || ipv6_addr_is_unspecified(&ipv6->src)) {
|
||||
DEBUG("ndp: invalid source link-layer address option received\n");
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while (pkt) {
|
||||
@ -333,41 +331,25 @@ bool gnrc_ndp_internal_sl2a_opt_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
|
||||
pkt = pkt->next;
|
||||
}
|
||||
|
||||
if (sl2a_len == 0) { /* in case there was no source address in l2 */
|
||||
sl2a_len = (sl2a_opt->len / 8) - sizeof(ndp_opt_t);
|
||||
|
||||
/* ignore all zeroes at the end for length */
|
||||
for (; sl2a[sl2a_len - 1] == 0x00; sl2a_len--);
|
||||
}
|
||||
|
||||
DEBUG("ndp: received SL2A (link-layer address: %s)\n",
|
||||
gnrc_netif_addr_to_str(addr_str, sizeof(addr_str), sl2a, sl2a_len));
|
||||
|
||||
switch (icmpv6_type) {
|
||||
case ICMPV6_NBR_SOL:
|
||||
nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
|
||||
if (sl2a_len == 0) { /* in case there was no source address in l2 */
|
||||
sl2a_len = (sl2a_opt->len / 8) - sizeof(ndp_opt_t);
|
||||
|
||||
if (nc_entry != NULL) {
|
||||
if ((sl2a_len != nc_entry->l2_addr_len) ||
|
||||
(memcmp(sl2a, nc_entry->l2_addr, sl2a_len) != 0)) {
|
||||
/* if entry exists but l2 address differs: set */
|
||||
nc_entry->l2_addr_len = sl2a_len;
|
||||
memcpy(nc_entry->l2_addr, sl2a, sl2a_len);
|
||||
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gnrc_ipv6_nc_add(iface, &ipv6->src, sl2a, sl2a_len,
|
||||
GNRC_IPV6_NC_STATE_STALE);
|
||||
/* ignore all zeroes at the end for length */
|
||||
for (; sl2a[sl2a_len - 1] == 0x00; sl2a_len--);
|
||||
}
|
||||
|
||||
return true;
|
||||
memcpy(l2src, sl2a, sl2a_len);
|
||||
return sl2a_len;
|
||||
|
||||
default: /* wrong encapsulating message: silently discard */
|
||||
DEBUG("ndp: silently discard sl2a_opt for ICMPv6 message type %"
|
||||
PRIu8 "\n", icmpv6_type);
|
||||
return true;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,6 @@ kernel_pid_t gnrc_ndp_node_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
|
||||
next_hop_ip = gnrc_ndp_internal_default_router();
|
||||
}
|
||||
|
||||
|
||||
if (next_hop_ip == NULL) {
|
||||
next_hop_ip = dst; /* Just look if it's in the neighbor cache
|
||||
* (aka on-link but not registered in prefix list as such) */
|
||||
@ -128,8 +127,9 @@ kernel_pid_t gnrc_ndp_node_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
|
||||
if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_STALE) {
|
||||
gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_DELAY);
|
||||
}
|
||||
|
||||
memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len);
|
||||
if (nc_entry->l2_addr_len > 0) {
|
||||
memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len);
|
||||
}
|
||||
*l2addr_len = nc_entry->l2_addr_len;
|
||||
/* TODO: unreachability check */
|
||||
return nc_entry->iface;
|
||||
|
@ -127,20 +127,59 @@ static int _ipv6_nc_list(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ipv6_nc_add(kernel_pid_t iface, char *ipv6_addr_str,
|
||||
char *l2_addr_str)
|
||||
static inline kernel_pid_t _get_iface(void)
|
||||
{
|
||||
kernel_pid_t ifs[GNRC_NETIF_NUMOF];
|
||||
size_t ifnum = gnrc_netif_get(ifs);
|
||||
return (ifnum > 1) ? KERNEL_PID_UNDEF : ifs[0];
|
||||
}
|
||||
|
||||
static int _ipv6_nc_add(int argc, char **argv)
|
||||
{
|
||||
char *ipv6_addr_str;
|
||||
char *l2_addr_str = NULL;
|
||||
kernel_pid_t iface = KERNEL_PID_UNDEF;
|
||||
ipv6_addr_t ipv6_addr;
|
||||
uint8_t l2_addr[MAX_L2_ADDR_LEN];
|
||||
size_t l2_addr_len;
|
||||
|
||||
switch (argc) {
|
||||
case 1:
|
||||
iface = _get_iface();
|
||||
ipv6_addr_str = argv[0]; /* store for output */
|
||||
l2_addr_len = 0;
|
||||
break;
|
||||
case 2:
|
||||
ipv6_addr_str = argv[0]; /* store for output */
|
||||
if (ipv6_addr_from_str(&ipv6_addr, ipv6_addr_str) == NULL) {
|
||||
iface = atoi(argv[0]);
|
||||
ipv6_addr_str = argv[1];
|
||||
l2_addr_len = 0;
|
||||
}
|
||||
else {
|
||||
iface = _get_iface();
|
||||
l2_addr_str = argv[1];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
iface = atoi(argv[0]);
|
||||
ipv6_addr_str = argv[1];
|
||||
l2_addr_str = argv[2];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_is_iface(iface)) {
|
||||
puts("error: invalid interface given.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ipv6_addr_from_str(&ipv6_addr, ipv6_addr_str) == NULL) {
|
||||
puts("error: unable to parse IPv6 address.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((l2_addr_len = gnrc_netif_addr_from_str(l2_addr, sizeof(l2_addr),
|
||||
l2_addr_str)) == 0) {
|
||||
if ((l2_addr_str != NULL) && (l2_addr_len = gnrc_netif_addr_from_str(l2_addr, sizeof(l2_addr),
|
||||
argv[1])) == 0) {
|
||||
puts("error: unable to parse link-layer address.");
|
||||
return 1;
|
||||
}
|
||||
@ -198,31 +237,12 @@ int _ipv6_nc_manage(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
if ((argc == 4) && (strcmp("add", argv[1]) == 0)) {
|
||||
kernel_pid_t ifs[GNRC_NETIF_NUMOF];
|
||||
size_t ifnum = gnrc_netif_get(ifs);
|
||||
if (ifnum > 1) {
|
||||
puts("error: multiple interfaces exist.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return _ipv6_nc_add(ifs[0], argv[2], argv[3]);
|
||||
if (strcmp("add", argv[1]) == 0) {
|
||||
return _ipv6_nc_add(argc - 2, &argv[2]);
|
||||
}
|
||||
else if ((argc > 4) && (strcmp("add", argv[1]) == 0)) {
|
||||
kernel_pid_t iface = (kernel_pid_t)atoi(argv[2]);
|
||||
|
||||
if (!_is_iface(iface)) {
|
||||
puts("error: invalid interface given.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return _ipv6_nc_add(iface, argv[3], argv[4]);
|
||||
}
|
||||
|
||||
if (strcmp("del", argv[1]) == 0) {
|
||||
return _ipv6_nc_del(argv[2]);
|
||||
}
|
||||
|
||||
if (strcmp("reset", argv[1]) == 0) {
|
||||
return _ipv6_nc_reset();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user