18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2007-2012 Siemens AG 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Written by: 68c2ecf20Sopenharmony_ci * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 78c2ecf20Sopenharmony_ci * Sergey Lapin <slapin@ossfans.org> 88c2ecf20Sopenharmony_ci * Maxim Gorbachyov <maxim.gorbachev@siemens.com> 98c2ecf20Sopenharmony_ci * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 158c2ecf20Sopenharmony_ci#include <linux/ieee802154.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <net/nl802154.h> 188c2ecf20Sopenharmony_ci#include <net/mac802154.h> 198c2ecf20Sopenharmony_ci#include <net/ieee802154_netdev.h> 208c2ecf20Sopenharmony_ci#include <net/cfg802154.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "ieee802154_i.h" 238c2ecf20Sopenharmony_ci#include "driver-ops.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciint mac802154_wpan_update_llsec(struct net_device *dev) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 288c2ecf20Sopenharmony_ci struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev); 298c2ecf20Sopenharmony_ci struct wpan_dev *wpan_dev = &sdata->wpan_dev; 308c2ecf20Sopenharmony_ci int rc = 0; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (ops->llsec) { 338c2ecf20Sopenharmony_ci struct ieee802154_llsec_params params; 348c2ecf20Sopenharmony_ci int changed = 0; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci params.pan_id = wpan_dev->pan_id; 378c2ecf20Sopenharmony_ci changed |= IEEE802154_LLSEC_PARAM_PAN_ID; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci params.hwaddr = wpan_dev->extended_addr; 408c2ecf20Sopenharmony_ci changed |= IEEE802154_LLSEC_PARAM_HWADDR; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci rc = ops->llsec->set_params(dev, ¶ms, changed); 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return rc; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int 498c2ecf20Sopenharmony_cimac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 528c2ecf20Sopenharmony_ci struct wpan_dev *wpan_dev = &sdata->wpan_dev; 538c2ecf20Sopenharmony_ci struct sockaddr_ieee802154 *sa = 548c2ecf20Sopenharmony_ci (struct sockaddr_ieee802154 *)&ifr->ifr_addr; 558c2ecf20Sopenharmony_ci int err = -ENOIOCTLCMD; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (cmd != SIOCGIFADDR && cmd != SIOCSIFADDR) 588c2ecf20Sopenharmony_ci return err; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci rtnl_lock(); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci switch (cmd) { 638c2ecf20Sopenharmony_ci case SIOCGIFADDR: 648c2ecf20Sopenharmony_ci { 658c2ecf20Sopenharmony_ci u16 pan_id, short_addr; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci pan_id = le16_to_cpu(wpan_dev->pan_id); 688c2ecf20Sopenharmony_ci short_addr = le16_to_cpu(wpan_dev->short_addr); 698c2ecf20Sopenharmony_ci if (pan_id == IEEE802154_PANID_BROADCAST || 708c2ecf20Sopenharmony_ci short_addr == IEEE802154_ADDR_BROADCAST) { 718c2ecf20Sopenharmony_ci err = -EADDRNOTAVAIL; 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci sa->family = AF_IEEE802154; 768c2ecf20Sopenharmony_ci sa->addr.addr_type = IEEE802154_ADDR_SHORT; 778c2ecf20Sopenharmony_ci sa->addr.pan_id = pan_id; 788c2ecf20Sopenharmony_ci sa->addr.short_addr = short_addr; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci err = 0; 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci case SIOCSIFADDR: 848c2ecf20Sopenharmony_ci if (netif_running(dev)) { 858c2ecf20Sopenharmony_ci rtnl_unlock(); 868c2ecf20Sopenharmony_ci return -EBUSY; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 908c2ecf20Sopenharmony_ci "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n"); 918c2ecf20Sopenharmony_ci if (sa->family != AF_IEEE802154 || 928c2ecf20Sopenharmony_ci sa->addr.addr_type != IEEE802154_ADDR_SHORT || 938c2ecf20Sopenharmony_ci sa->addr.pan_id == IEEE802154_PANID_BROADCAST || 948c2ecf20Sopenharmony_ci sa->addr.short_addr == IEEE802154_ADDR_BROADCAST || 958c2ecf20Sopenharmony_ci sa->addr.short_addr == IEEE802154_ADDR_UNDEF) { 968c2ecf20Sopenharmony_ci err = -EINVAL; 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci wpan_dev->pan_id = cpu_to_le16(sa->addr.pan_id); 1018c2ecf20Sopenharmony_ci wpan_dev->short_addr = cpu_to_le16(sa->addr.short_addr); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci err = mac802154_wpan_update_llsec(dev); 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci rtnl_unlock(); 1088c2ecf20Sopenharmony_ci return err; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int mac802154_wpan_mac_addr(struct net_device *dev, void *p) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 1148c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 1158c2ecf20Sopenharmony_ci __le64 extended_addr; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (netif_running(dev)) 1188c2ecf20Sopenharmony_ci return -EBUSY; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* lowpan need to be down for update 1218c2ecf20Sopenharmony_ci * SLAAC address after ifup 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci if (sdata->wpan_dev.lowpan_dev) { 1248c2ecf20Sopenharmony_ci if (netif_running(sdata->wpan_dev.lowpan_dev)) 1258c2ecf20Sopenharmony_ci return -EBUSY; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci ieee802154_be64_to_le64(&extended_addr, addr->sa_data); 1298c2ecf20Sopenharmony_ci if (!ieee802154_is_valid_extended_unicast_addr(extended_addr)) 1308c2ecf20Sopenharmony_ci return -EINVAL; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); 1338c2ecf20Sopenharmony_ci sdata->wpan_dev.extended_addr = extended_addr; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* update lowpan interface mac address when 1368c2ecf20Sopenharmony_ci * wpan mac has been changed 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ci if (sdata->wpan_dev.lowpan_dev) 1398c2ecf20Sopenharmony_ci memcpy(sdata->wpan_dev.lowpan_dev->dev_addr, dev->dev_addr, 1408c2ecf20Sopenharmony_ci dev->addr_len); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return mac802154_wpan_update_llsec(dev); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int ieee802154_setup_hw(struct ieee802154_sub_if_data *sdata) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct ieee802154_local *local = sdata->local; 1488c2ecf20Sopenharmony_ci struct wpan_dev *wpan_dev = &sdata->wpan_dev; 1498c2ecf20Sopenharmony_ci int ret; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) { 1528c2ecf20Sopenharmony_ci ret = drv_set_promiscuous_mode(local, 1538c2ecf20Sopenharmony_ci wpan_dev->promiscuous_mode); 1548c2ecf20Sopenharmony_ci if (ret < 0) 1558c2ecf20Sopenharmony_ci return ret; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_AFILT) { 1598c2ecf20Sopenharmony_ci ret = drv_set_pan_id(local, wpan_dev->pan_id); 1608c2ecf20Sopenharmony_ci if (ret < 0) 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci ret = drv_set_extended_addr(local, wpan_dev->extended_addr); 1648c2ecf20Sopenharmony_ci if (ret < 0) 1658c2ecf20Sopenharmony_ci return ret; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ret = drv_set_short_addr(local, wpan_dev->short_addr); 1688c2ecf20Sopenharmony_ci if (ret < 0) 1698c2ecf20Sopenharmony_ci return ret; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_LBT) { 1738c2ecf20Sopenharmony_ci ret = drv_set_lbt_mode(local, wpan_dev->lbt); 1748c2ecf20Sopenharmony_ci if (ret < 0) 1758c2ecf20Sopenharmony_ci return ret; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) { 1798c2ecf20Sopenharmony_ci ret = drv_set_csma_params(local, wpan_dev->min_be, 1808c2ecf20Sopenharmony_ci wpan_dev->max_be, 1818c2ecf20Sopenharmony_ci wpan_dev->csma_retries); 1828c2ecf20Sopenharmony_ci if (ret < 0) 1838c2ecf20Sopenharmony_ci return ret; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) { 1878c2ecf20Sopenharmony_ci ret = drv_set_max_frame_retries(local, wpan_dev->frame_retries); 1888c2ecf20Sopenharmony_ci if (ret < 0) 1898c2ecf20Sopenharmony_ci return ret; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int mac802154_slave_open(struct net_device *dev) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 1988c2ecf20Sopenharmony_ci struct ieee802154_local *local = sdata->local; 1998c2ecf20Sopenharmony_ci int res; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci ASSERT_RTNL(); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci set_bit(SDATA_STATE_RUNNING, &sdata->state); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (!local->open_count) { 2068c2ecf20Sopenharmony_ci res = ieee802154_setup_hw(sdata); 2078c2ecf20Sopenharmony_ci if (res) 2088c2ecf20Sopenharmony_ci goto err; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci res = drv_start(local); 2118c2ecf20Sopenharmony_ci if (res) 2128c2ecf20Sopenharmony_ci goto err; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci local->open_count++; 2168c2ecf20Sopenharmony_ci netif_start_queue(dev); 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_cierr: 2198c2ecf20Sopenharmony_ci /* might already be clear but that doesn't matter */ 2208c2ecf20Sopenharmony_ci clear_bit(SDATA_STATE_RUNNING, &sdata->state); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return res; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int 2268c2ecf20Sopenharmony_ciieee802154_check_mac_settings(struct ieee802154_local *local, 2278c2ecf20Sopenharmony_ci struct wpan_dev *wpan_dev, 2288c2ecf20Sopenharmony_ci struct wpan_dev *nwpan_dev) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci ASSERT_RTNL(); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) { 2338c2ecf20Sopenharmony_ci if (wpan_dev->promiscuous_mode != nwpan_dev->promiscuous_mode) 2348c2ecf20Sopenharmony_ci return -EBUSY; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_AFILT) { 2388c2ecf20Sopenharmony_ci if (wpan_dev->pan_id != nwpan_dev->pan_id || 2398c2ecf20Sopenharmony_ci wpan_dev->short_addr != nwpan_dev->short_addr || 2408c2ecf20Sopenharmony_ci wpan_dev->extended_addr != nwpan_dev->extended_addr) 2418c2ecf20Sopenharmony_ci return -EBUSY; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) { 2458c2ecf20Sopenharmony_ci if (wpan_dev->min_be != nwpan_dev->min_be || 2468c2ecf20Sopenharmony_ci wpan_dev->max_be != nwpan_dev->max_be || 2478c2ecf20Sopenharmony_ci wpan_dev->csma_retries != nwpan_dev->csma_retries) 2488c2ecf20Sopenharmony_ci return -EBUSY; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) { 2528c2ecf20Sopenharmony_ci if (wpan_dev->frame_retries != nwpan_dev->frame_retries) 2538c2ecf20Sopenharmony_ci return -EBUSY; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (local->hw.flags & IEEE802154_HW_LBT) { 2578c2ecf20Sopenharmony_ci if (wpan_dev->lbt != nwpan_dev->lbt) 2588c2ecf20Sopenharmony_ci return -EBUSY; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int 2658c2ecf20Sopenharmony_ciieee802154_check_concurrent_iface(struct ieee802154_sub_if_data *sdata, 2668c2ecf20Sopenharmony_ci enum nl802154_iftype iftype) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct ieee802154_local *local = sdata->local; 2698c2ecf20Sopenharmony_ci struct wpan_dev *wpan_dev = &sdata->wpan_dev; 2708c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *nsdata; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* we hold the RTNL here so can safely walk the list */ 2738c2ecf20Sopenharmony_ci list_for_each_entry(nsdata, &local->interfaces, list) { 2748c2ecf20Sopenharmony_ci if (nsdata != sdata && ieee802154_sdata_running(nsdata)) { 2758c2ecf20Sopenharmony_ci int ret; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* TODO currently we don't support multiple node types 2788c2ecf20Sopenharmony_ci * we need to run skb_clone at rx path. Check if there 2798c2ecf20Sopenharmony_ci * exist really an use case if we need to support 2808c2ecf20Sopenharmony_ci * multiple node types at the same time. 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_ci if (wpan_dev->iftype == NL802154_IFTYPE_NODE && 2838c2ecf20Sopenharmony_ci nsdata->wpan_dev.iftype == NL802154_IFTYPE_NODE) 2848c2ecf20Sopenharmony_ci return -EBUSY; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* check all phy mac sublayer settings are the same. 2878c2ecf20Sopenharmony_ci * We have only one phy, different values makes trouble. 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_ci ret = ieee802154_check_mac_settings(local, wpan_dev, 2908c2ecf20Sopenharmony_ci &nsdata->wpan_dev); 2918c2ecf20Sopenharmony_ci if (ret < 0) 2928c2ecf20Sopenharmony_ci return ret; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int mac802154_wpan_open(struct net_device *dev) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci int rc; 3028c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 3038c2ecf20Sopenharmony_ci struct wpan_dev *wpan_dev = &sdata->wpan_dev; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci rc = ieee802154_check_concurrent_iface(sdata, wpan_dev->iftype); 3068c2ecf20Sopenharmony_ci if (rc < 0) 3078c2ecf20Sopenharmony_ci return rc; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return mac802154_slave_open(dev); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic int mac802154_slave_close(struct net_device *dev) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 3158c2ecf20Sopenharmony_ci struct ieee802154_local *local = sdata->local; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ASSERT_RTNL(); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci netif_stop_queue(dev); 3208c2ecf20Sopenharmony_ci local->open_count--; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci clear_bit(SDATA_STATE_RUNNING, &sdata->state); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (!local->open_count) 3258c2ecf20Sopenharmony_ci ieee802154_stop_device(local); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata, 3318c2ecf20Sopenharmony_ci struct ieee802154_hdr *hdr, 3328c2ecf20Sopenharmony_ci const struct ieee802154_mac_cb *cb) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct ieee802154_llsec_params params; 3358c2ecf20Sopenharmony_ci u8 level; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci mac802154_llsec_get_params(&sdata->sec, ¶ms); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (!params.enabled && cb->secen_override && cb->secen) 3408c2ecf20Sopenharmony_ci return -EINVAL; 3418c2ecf20Sopenharmony_ci if (!params.enabled || 3428c2ecf20Sopenharmony_ci (cb->secen_override && !cb->secen) || 3438c2ecf20Sopenharmony_ci !params.out_level) 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci if (cb->seclevel_override && !cb->seclevel) 3468c2ecf20Sopenharmony_ci return -EINVAL; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci level = cb->seclevel_override ? cb->seclevel : params.out_level; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci hdr->fc.security_enabled = 1; 3518c2ecf20Sopenharmony_ci hdr->sec.level = level; 3528c2ecf20Sopenharmony_ci hdr->sec.key_id_mode = params.out_key.mode; 3538c2ecf20Sopenharmony_ci if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX) 3548c2ecf20Sopenharmony_ci hdr->sec.short_src = params.out_key.short_source; 3558c2ecf20Sopenharmony_ci else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX) 3568c2ecf20Sopenharmony_ci hdr->sec.extended_src = params.out_key.extended_source; 3578c2ecf20Sopenharmony_ci hdr->sec.key_id = params.out_key.id; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci return 0; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic int ieee802154_header_create(struct sk_buff *skb, 3638c2ecf20Sopenharmony_ci struct net_device *dev, 3648c2ecf20Sopenharmony_ci const struct ieee802154_addr *daddr, 3658c2ecf20Sopenharmony_ci const struct ieee802154_addr *saddr, 3668c2ecf20Sopenharmony_ci unsigned len) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct ieee802154_hdr hdr; 3698c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 3708c2ecf20Sopenharmony_ci struct wpan_dev *wpan_dev = &sdata->wpan_dev; 3718c2ecf20Sopenharmony_ci struct ieee802154_mac_cb *cb = mac_cb(skb); 3728c2ecf20Sopenharmony_ci int hlen; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (!daddr) 3758c2ecf20Sopenharmony_ci return -EINVAL; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci memset(&hdr.fc, 0, sizeof(hdr.fc)); 3788c2ecf20Sopenharmony_ci hdr.fc.type = cb->type; 3798c2ecf20Sopenharmony_ci hdr.fc.security_enabled = cb->secen; 3808c2ecf20Sopenharmony_ci hdr.fc.ack_request = cb->ackreq; 3818c2ecf20Sopenharmony_ci hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (mac802154_set_header_security(sdata, &hdr, cb) < 0) 3848c2ecf20Sopenharmony_ci return -EINVAL; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (!saddr) { 3878c2ecf20Sopenharmony_ci if (wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) || 3888c2ecf20Sopenharmony_ci wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) || 3898c2ecf20Sopenharmony_ci wpan_dev->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) { 3908c2ecf20Sopenharmony_ci hdr.source.mode = IEEE802154_ADDR_LONG; 3918c2ecf20Sopenharmony_ci hdr.source.extended_addr = wpan_dev->extended_addr; 3928c2ecf20Sopenharmony_ci } else { 3938c2ecf20Sopenharmony_ci hdr.source.mode = IEEE802154_ADDR_SHORT; 3948c2ecf20Sopenharmony_ci hdr.source.short_addr = wpan_dev->short_addr; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci hdr.source.pan_id = wpan_dev->pan_id; 3988c2ecf20Sopenharmony_ci } else { 3998c2ecf20Sopenharmony_ci hdr.source = *(const struct ieee802154_addr *)saddr; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci hdr.dest = *(const struct ieee802154_addr *)daddr; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci hlen = ieee802154_hdr_push(skb, &hdr); 4058c2ecf20Sopenharmony_ci if (hlen < 0) 4068c2ecf20Sopenharmony_ci return -EINVAL; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 4098c2ecf20Sopenharmony_ci skb->mac_len = hlen; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (len > ieee802154_max_payload(&hdr)) 4128c2ecf20Sopenharmony_ci return -EMSGSIZE; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return hlen; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic const struct wpan_dev_header_ops ieee802154_header_ops = { 4188c2ecf20Sopenharmony_ci .create = ieee802154_header_create, 4198c2ecf20Sopenharmony_ci}; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci/* This header create functionality assumes a 8 byte array for 4228c2ecf20Sopenharmony_ci * source and destination pointer at maximum. To adapt this for 4238c2ecf20Sopenharmony_ci * the 802.15.4 dataframe header we use extended address handling 4248c2ecf20Sopenharmony_ci * here only and intra pan connection. fc fields are mostly fallback 4258c2ecf20Sopenharmony_ci * handling. For provide dev_hard_header for dgram sockets. 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_cistatic int mac802154_header_create(struct sk_buff *skb, 4288c2ecf20Sopenharmony_ci struct net_device *dev, 4298c2ecf20Sopenharmony_ci unsigned short type, 4308c2ecf20Sopenharmony_ci const void *daddr, 4318c2ecf20Sopenharmony_ci const void *saddr, 4328c2ecf20Sopenharmony_ci unsigned len) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct ieee802154_hdr hdr; 4358c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 4368c2ecf20Sopenharmony_ci struct wpan_dev *wpan_dev = &sdata->wpan_dev; 4378c2ecf20Sopenharmony_ci struct ieee802154_mac_cb cb = { }; 4388c2ecf20Sopenharmony_ci int hlen; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (!daddr) 4418c2ecf20Sopenharmony_ci return -EINVAL; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci memset(&hdr.fc, 0, sizeof(hdr.fc)); 4448c2ecf20Sopenharmony_ci hdr.fc.type = IEEE802154_FC_TYPE_DATA; 4458c2ecf20Sopenharmony_ci hdr.fc.ack_request = wpan_dev->ackreq; 4468c2ecf20Sopenharmony_ci hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* TODO currently a workaround to give zero cb block to set 4498c2ecf20Sopenharmony_ci * security parameters defaults according MIB. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_ci if (mac802154_set_header_security(sdata, &hdr, &cb) < 0) 4528c2ecf20Sopenharmony_ci return -EINVAL; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci hdr.dest.pan_id = wpan_dev->pan_id; 4558c2ecf20Sopenharmony_ci hdr.dest.mode = IEEE802154_ADDR_LONG; 4568c2ecf20Sopenharmony_ci ieee802154_be64_to_le64(&hdr.dest.extended_addr, daddr); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci hdr.source.pan_id = hdr.dest.pan_id; 4598c2ecf20Sopenharmony_ci hdr.source.mode = IEEE802154_ADDR_LONG; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (!saddr) 4628c2ecf20Sopenharmony_ci hdr.source.extended_addr = wpan_dev->extended_addr; 4638c2ecf20Sopenharmony_ci else 4648c2ecf20Sopenharmony_ci ieee802154_be64_to_le64(&hdr.source.extended_addr, saddr); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci hlen = ieee802154_hdr_push(skb, &hdr); 4678c2ecf20Sopenharmony_ci if (hlen < 0) 4688c2ecf20Sopenharmony_ci return -EINVAL; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 4718c2ecf20Sopenharmony_ci skb->mac_len = hlen; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (len > ieee802154_max_payload(&hdr)) 4748c2ecf20Sopenharmony_ci return -EMSGSIZE; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return hlen; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int 4808c2ecf20Sopenharmony_cimac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct ieee802154_hdr hdr; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) { 4858c2ecf20Sopenharmony_ci pr_debug("malformed packet\n"); 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (hdr.source.mode == IEEE802154_ADDR_LONG) { 4908c2ecf20Sopenharmony_ci ieee802154_le64_to_be64(haddr, &hdr.source.extended_addr); 4918c2ecf20Sopenharmony_ci return IEEE802154_EXTENDED_ADDR_LEN; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return 0; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic const struct header_ops mac802154_header_ops = { 4988c2ecf20Sopenharmony_ci .create = mac802154_header_create, 4998c2ecf20Sopenharmony_ci .parse = mac802154_header_parse, 5008c2ecf20Sopenharmony_ci}; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic const struct net_device_ops mac802154_wpan_ops = { 5038c2ecf20Sopenharmony_ci .ndo_open = mac802154_wpan_open, 5048c2ecf20Sopenharmony_ci .ndo_stop = mac802154_slave_close, 5058c2ecf20Sopenharmony_ci .ndo_start_xmit = ieee802154_subif_start_xmit, 5068c2ecf20Sopenharmony_ci .ndo_do_ioctl = mac802154_wpan_ioctl, 5078c2ecf20Sopenharmony_ci .ndo_set_mac_address = mac802154_wpan_mac_addr, 5088c2ecf20Sopenharmony_ci}; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic const struct net_device_ops mac802154_monitor_ops = { 5118c2ecf20Sopenharmony_ci .ndo_open = mac802154_wpan_open, 5128c2ecf20Sopenharmony_ci .ndo_stop = mac802154_slave_close, 5138c2ecf20Sopenharmony_ci .ndo_start_xmit = ieee802154_monitor_start_xmit, 5148c2ecf20Sopenharmony_ci}; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic void mac802154_wpan_free(struct net_device *dev) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci mac802154_llsec_destroy(&sdata->sec); 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic void ieee802154_if_setup(struct net_device *dev) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci dev->addr_len = IEEE802154_EXTENDED_ADDR_LEN; 5268c2ecf20Sopenharmony_ci memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Let hard_header_len set to IEEE802154_MIN_HEADER_LEN. AF_PACKET 5298c2ecf20Sopenharmony_ci * will not send frames without any payload, but ack frames 5308c2ecf20Sopenharmony_ci * has no payload, so substract one that we can send a 3 bytes 5318c2ecf20Sopenharmony_ci * frame. The xmit callback assumes at least a hard header where two 5328c2ecf20Sopenharmony_ci * bytes fc and sequence field are set. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci dev->hard_header_len = IEEE802154_MIN_HEADER_LEN - 1; 5358c2ecf20Sopenharmony_ci /* The auth_tag header is for security and places in private payload 5368c2ecf20Sopenharmony_ci * room of mac frame which stucks between payload and FCS field. 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_ci dev->needed_tailroom = IEEE802154_MAX_AUTH_TAG_LEN + 5398c2ecf20Sopenharmony_ci IEEE802154_FCS_LEN; 5408c2ecf20Sopenharmony_ci /* The mtu size is the payload without mac header in this case. 5418c2ecf20Sopenharmony_ci * We have a dynamic length header with a minimum header length 5428c2ecf20Sopenharmony_ci * which is hard_header_len. In this case we let mtu to the size 5438c2ecf20Sopenharmony_ci * of maximum payload which is IEEE802154_MTU - IEEE802154_FCS_LEN - 5448c2ecf20Sopenharmony_ci * hard_header_len. The FCS which is set by hardware or ndo_start_xmit 5458c2ecf20Sopenharmony_ci * and the minimum mac header which can be evaluated inside driver 5468c2ecf20Sopenharmony_ci * layer. The rest of mac header will be part of payload if greater 5478c2ecf20Sopenharmony_ci * than hard_header_len. 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_ci dev->mtu = IEEE802154_MTU - IEEE802154_FCS_LEN - 5508c2ecf20Sopenharmony_ci dev->hard_header_len; 5518c2ecf20Sopenharmony_ci dev->tx_queue_len = 300; 5528c2ecf20Sopenharmony_ci dev->flags = IFF_NOARP | IFF_BROADCAST; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic int 5568c2ecf20Sopenharmony_ciieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, 5578c2ecf20Sopenharmony_ci enum nl802154_iftype type) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct wpan_dev *wpan_dev = &sdata->wpan_dev; 5608c2ecf20Sopenharmony_ci int ret; 5618c2ecf20Sopenharmony_ci u8 tmp; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* set some type-dependent values */ 5648c2ecf20Sopenharmony_ci sdata->wpan_dev.iftype = type; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci get_random_bytes(&tmp, sizeof(tmp)); 5678c2ecf20Sopenharmony_ci atomic_set(&wpan_dev->bsn, tmp); 5688c2ecf20Sopenharmony_ci get_random_bytes(&tmp, sizeof(tmp)); 5698c2ecf20Sopenharmony_ci atomic_set(&wpan_dev->dsn, tmp); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* defaults per 802.15.4-2011 */ 5728c2ecf20Sopenharmony_ci wpan_dev->min_be = 3; 5738c2ecf20Sopenharmony_ci wpan_dev->max_be = 5; 5748c2ecf20Sopenharmony_ci wpan_dev->csma_retries = 4; 5758c2ecf20Sopenharmony_ci wpan_dev->frame_retries = 3; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci wpan_dev->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST); 5788c2ecf20Sopenharmony_ci wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci switch (type) { 5818c2ecf20Sopenharmony_ci case NL802154_IFTYPE_NODE: 5828c2ecf20Sopenharmony_ci ieee802154_be64_to_le64(&wpan_dev->extended_addr, 5838c2ecf20Sopenharmony_ci sdata->dev->dev_addr); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci sdata->dev->header_ops = &mac802154_header_ops; 5868c2ecf20Sopenharmony_ci sdata->dev->needs_free_netdev = true; 5878c2ecf20Sopenharmony_ci sdata->dev->priv_destructor = mac802154_wpan_free; 5888c2ecf20Sopenharmony_ci sdata->dev->netdev_ops = &mac802154_wpan_ops; 5898c2ecf20Sopenharmony_ci sdata->dev->ml_priv = &mac802154_mlme_wpan; 5908c2ecf20Sopenharmony_ci wpan_dev->promiscuous_mode = false; 5918c2ecf20Sopenharmony_ci wpan_dev->header_ops = &ieee802154_header_ops; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci mutex_init(&sdata->sec_mtx); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci mac802154_llsec_init(&sdata->sec); 5968c2ecf20Sopenharmony_ci ret = mac802154_wpan_update_llsec(sdata->dev); 5978c2ecf20Sopenharmony_ci if (ret < 0) 5988c2ecf20Sopenharmony_ci return ret; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci case NL802154_IFTYPE_MONITOR: 6028c2ecf20Sopenharmony_ci sdata->dev->needs_free_netdev = true; 6038c2ecf20Sopenharmony_ci sdata->dev->netdev_ops = &mac802154_monitor_ops; 6048c2ecf20Sopenharmony_ci wpan_dev->promiscuous_mode = true; 6058c2ecf20Sopenharmony_ci break; 6068c2ecf20Sopenharmony_ci default: 6078c2ecf20Sopenharmony_ci BUG(); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistruct net_device * 6148c2ecf20Sopenharmony_ciieee802154_if_add(struct ieee802154_local *local, const char *name, 6158c2ecf20Sopenharmony_ci unsigned char name_assign_type, enum nl802154_iftype type, 6168c2ecf20Sopenharmony_ci __le64 extended_addr) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct net_device *ndev = NULL; 6198c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata = NULL; 6208c2ecf20Sopenharmony_ci int ret = -ENOMEM; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci ASSERT_RTNL(); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci ndev = alloc_netdev(sizeof(*sdata), name, 6258c2ecf20Sopenharmony_ci name_assign_type, ieee802154_if_setup); 6268c2ecf20Sopenharmony_ci if (!ndev) 6278c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci ndev->needed_headroom = local->hw.extra_tx_headroom + 6308c2ecf20Sopenharmony_ci IEEE802154_MAX_HEADER_LEN; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci ret = dev_alloc_name(ndev, ndev->name); 6338c2ecf20Sopenharmony_ci if (ret < 0) 6348c2ecf20Sopenharmony_ci goto err; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci ieee802154_le64_to_be64(ndev->perm_addr, 6378c2ecf20Sopenharmony_ci &local->hw.phy->perm_extended_addr); 6388c2ecf20Sopenharmony_ci switch (type) { 6398c2ecf20Sopenharmony_ci case NL802154_IFTYPE_NODE: 6408c2ecf20Sopenharmony_ci ndev->type = ARPHRD_IEEE802154; 6418c2ecf20Sopenharmony_ci if (ieee802154_is_valid_extended_unicast_addr(extended_addr)) 6428c2ecf20Sopenharmony_ci ieee802154_le64_to_be64(ndev->dev_addr, &extended_addr); 6438c2ecf20Sopenharmony_ci else 6448c2ecf20Sopenharmony_ci memcpy(ndev->dev_addr, ndev->perm_addr, 6458c2ecf20Sopenharmony_ci IEEE802154_EXTENDED_ADDR_LEN); 6468c2ecf20Sopenharmony_ci break; 6478c2ecf20Sopenharmony_ci case NL802154_IFTYPE_MONITOR: 6488c2ecf20Sopenharmony_ci ndev->type = ARPHRD_IEEE802154_MONITOR; 6498c2ecf20Sopenharmony_ci break; 6508c2ecf20Sopenharmony_ci default: 6518c2ecf20Sopenharmony_ci ret = -EINVAL; 6528c2ecf20Sopenharmony_ci goto err; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* TODO check this */ 6568c2ecf20Sopenharmony_ci SET_NETDEV_DEV(ndev, &local->phy->dev); 6578c2ecf20Sopenharmony_ci dev_net_set(ndev, wpan_phy_net(local->hw.phy)); 6588c2ecf20Sopenharmony_ci sdata = netdev_priv(ndev); 6598c2ecf20Sopenharmony_ci ndev->ieee802154_ptr = &sdata->wpan_dev; 6608c2ecf20Sopenharmony_ci memcpy(sdata->name, ndev->name, IFNAMSIZ); 6618c2ecf20Sopenharmony_ci sdata->dev = ndev; 6628c2ecf20Sopenharmony_ci sdata->wpan_dev.wpan_phy = local->hw.phy; 6638c2ecf20Sopenharmony_ci sdata->local = local; 6648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sdata->wpan_dev.list); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* setup type-dependent data */ 6678c2ecf20Sopenharmony_ci ret = ieee802154_setup_sdata(sdata, type); 6688c2ecf20Sopenharmony_ci if (ret) 6698c2ecf20Sopenharmony_ci goto err; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci ret = register_netdevice(ndev); 6728c2ecf20Sopenharmony_ci if (ret < 0) 6738c2ecf20Sopenharmony_ci goto err; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci mutex_lock(&local->iflist_mtx); 6768c2ecf20Sopenharmony_ci list_add_tail_rcu(&sdata->list, &local->interfaces); 6778c2ecf20Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci return ndev; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cierr: 6828c2ecf20Sopenharmony_ci free_netdev(ndev); 6838c2ecf20Sopenharmony_ci return ERR_PTR(ret); 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_civoid ieee802154_if_remove(struct ieee802154_sub_if_data *sdata) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci ASSERT_RTNL(); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci mutex_lock(&sdata->local->iflist_mtx); 6918c2ecf20Sopenharmony_ci list_del_rcu(&sdata->list); 6928c2ecf20Sopenharmony_ci mutex_unlock(&sdata->local->iflist_mtx); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci synchronize_rcu(); 6958c2ecf20Sopenharmony_ci unregister_netdevice(sdata->dev); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_civoid ieee802154_remove_interfaces(struct ieee802154_local *local) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata, *tmp; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci mutex_lock(&local->iflist_mtx); 7038c2ecf20Sopenharmony_ci list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { 7048c2ecf20Sopenharmony_ci list_del(&sdata->list); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci unregister_netdevice(sdata->dev); 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic int netdev_notify(struct notifier_block *nb, 7128c2ecf20Sopenharmony_ci unsigned long state, void *ptr) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 7158c2ecf20Sopenharmony_ci struct ieee802154_sub_if_data *sdata; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (state != NETDEV_CHANGENAME) 7188c2ecf20Sopenharmony_ci return NOTIFY_DONE; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (!dev->ieee802154_ptr || !dev->ieee802154_ptr->wpan_phy) 7218c2ecf20Sopenharmony_ci return NOTIFY_DONE; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (dev->ieee802154_ptr->wpan_phy->privid != mac802154_wpan_phy_privid) 7248c2ecf20Sopenharmony_ci return NOTIFY_DONE; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci sdata = IEEE802154_DEV_TO_SUB_IF(dev); 7278c2ecf20Sopenharmony_ci memcpy(sdata->name, dev->name, IFNAMSIZ); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return NOTIFY_OK; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic struct notifier_block mac802154_netdev_notifier = { 7338c2ecf20Sopenharmony_ci .notifier_call = netdev_notify, 7348c2ecf20Sopenharmony_ci}; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ciint ieee802154_iface_init(void) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci return register_netdevice_notifier(&mac802154_netdev_notifier); 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_civoid ieee802154_iface_exit(void) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&mac802154_netdev_notifier); 7448c2ecf20Sopenharmony_ci} 745