static void lowpan_ndisc_prefix_rcv_add_addr(struct net *net,
        struct net_device *dev,
        const struct prefix_info *pinfo,
        struct inet6_dev *in6_dev,
        struct in6_addr *addr,
        int addr_type, u32 addr_flags,
        bool sllao, bool tokenized,
        __u32 valid_lft,
        u32 prefered_lft,
        bool dev_addr_generated)
{
    int err;

    /* generates short based address for RA PIO's */
    if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154) && dev_addr_generated &&
            !addrconf_ifid_802154_6lowpan(addr->s6_addr + 8, dev)) {
        err = addrconf_prefix_rcv_add_addr(net, dev, pinfo, in6_dev,
                                           addr, addr_type, addr_flags,
                                           sllao, tokenized, valid_lft,
                                           prefered_lft);
        if (err)
            ND_PRINTK(2, warn,
                      "RA: could not add a short address based address for prefix: %pI6c\n",
                      &pinfo->prefix);
    }
}
static void lowpan_ndisc_update(const struct net_device *dev,
                                struct neighbour *n, u32 flags, u8 icmp6_type,
                                const struct ndisc_options *ndopts)
{
    if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154))
        return;

    /* react on overrides only. TODO check if this is really right. */
    if (flags & NEIGH_UPDATE_F_OVERRIDE)
        lowpan_ndisc_802154_update(n, flags, icmp6_type, ndopts);
}
static int lowpan_ndisc_parse_options(const struct net_device *dev,
                                      struct nd_opt_hdr *nd_opt,
                                      struct ndisc_options *ndopts)
{
    if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154))
        return 0;

    switch (nd_opt->nd_opt_type) {
    case ND_OPT_SOURCE_LL_ADDR:
    case ND_OPT_TARGET_LL_ADDR:
        return lowpan_ndisc_parse_802154_options(dev, nd_opt, ndopts);
    default:
        return 0;
    }
}
static void lowpan_ndisc_fill_addr_option(const struct net_device *dev,
        struct sk_buff *skb, u8 icmp6_type,
        const u8 *ha)
{
    struct wpan_dev *wpan_dev;
    __be16 short_addr;
    u8 opt_type;

    if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154))
        return;

    switch (icmp6_type) {
    case NDISC_REDIRECT:
        if (ha) {
            ieee802154_le16_to_be16(&short_addr, ha);
            __ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
                                     &short_addr,
                                     IEEE802154_SHORT_ADDR_LEN, 0);
        }
        return;
    case NDISC_NEIGHBOUR_ADVERTISEMENT:
        opt_type = ND_OPT_TARGET_LL_ADDR;
        break;
    case NDISC_ROUTER_SOLICITATION:
    case NDISC_NEIGHBOUR_SOLICITATION:
        opt_type = ND_OPT_SOURCE_LL_ADDR;
        break;
    default:
        return;
    }

    wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr;

    if (lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr)) {
        ieee802154_le16_to_be16(&short_addr,
                                &wpan_dev->short_addr);
        __ndisc_fill_addr_option(skb, opt_type, &short_addr,
                                 IEEE802154_SHORT_ADDR_LEN, 0);
    }
}
static int lowpan_ndisc_opt_addr_space(const struct net_device *dev,
                                       u8 icmp6_type, struct neighbour *neigh,
                                       u8 *ha_buf, u8 **ha)
{
    struct lowpan_802154_neigh *n;
    struct wpan_dev *wpan_dev;
    int addr_space = 0;

    if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154))
        return 0;

    switch (icmp6_type) {
    case NDISC_REDIRECT:
        n = lowpan_802154_neigh(neighbour_priv(neigh));

        read_lock_bh(&neigh->lock);
        if (lowpan_802154_is_valid_src_short_addr(n->short_addr)) {
            memcpy(ha_buf, &n->short_addr,
                   IEEE802154_SHORT_ADDR_LEN);
            read_unlock_bh(&neigh->lock);
            addr_space += __ndisc_opt_addr_space(IEEE802154_SHORT_ADDR_LEN, 0);
            *ha = ha_buf;
        } else {
            read_unlock_bh(&neigh->lock);
        }
        break;
    case NDISC_NEIGHBOUR_ADVERTISEMENT:
    case NDISC_NEIGHBOUR_SOLICITATION:
    case NDISC_ROUTER_SOLICITATION:
        wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr;

        if (lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr))
            addr_space = __ndisc_opt_addr_space(IEEE802154_SHORT_ADDR_LEN, 0);
        break;
    default:
        break;
    }

    return addr_space;
}
Exemple #6
0
static int lowpan_event(struct notifier_block *unused,
			unsigned long event, void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct inet6_dev *idev;
	struct in6_addr addr;
	int i;

	if (dev->type != ARPHRD_6LOWPAN)
		return NOTIFY_DONE;

	idev = __in6_dev_get(dev);
	if (!idev)
		return NOTIFY_DONE;

	switch (event) {
	case NETDEV_UP:
	case NETDEV_CHANGE:
		/* (802.15.4 6LoWPAN short address slaac handling */
		if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154) &&
		    addrconf_ifid_802154_6lowpan(addr.s6_addr + 8, dev) == 0) {
			__ipv6_addr_set_half(&addr.s6_addr32[0],
					     htonl(0xFE800000), 0);
			addrconf_add_linklocal(idev, &addr, 0);
		}
		break;
	case NETDEV_DOWN:
		for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
			clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE,
				  &lowpan_dev(dev)->ctx.table[i].flags);
		break;
	default:
		return NOTIFY_DONE;
	}

	return NOTIFY_OK;
}