Exemple #1
0
int addrconf_ifid_802154_6lowpan(u8 *eui, struct net_device *dev)
{
	struct wpan_dev *wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr;

	/* Set short_addr autoconfiguration if short_addr is present only */
	if (!lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr))
		return -1;

	/* For either address format, all zero addresses MUST NOT be used */
	if (wpan_dev->pan_id == cpu_to_le16(0x0000) &&
	    wpan_dev->short_addr == cpu_to_le16(0x0000))
		return -1;

	/* Alternatively, if no PAN ID is known, 16 zero bits may be used */
	if (wpan_dev->pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
		memset(eui, 0, 2);
	else
		ieee802154_le16_to_be16(eui, &wpan_dev->pan_id);

	/* The "Universal/Local" (U/L) bit shall be set to zero */
	eui[0] &= ~2;
	eui[2] = 0;
	eui[3] = 0xFF;
	eui[4] = 0xFE;
	eui[5] = 0;
	ieee802154_le16_to_be16(&eui[6], &wpan_dev->short_addr);
	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;
}