您的位置:首页 > 房产 > 家装 > 中国十大货源批发平台_网站建设包括哪些_搜索引擎收录_武汉百度

中国十大货源批发平台_网站建设包括哪些_搜索引擎收录_武汉百度

2024/10/6 0:37:22 来源:https://blog.csdn.net/weixin_44586903/article/details/142652387  浏览:    关键词:中国十大货源批发平台_网站建设包括哪些_搜索引擎收录_武汉百度
中国十大货源批发平台_网站建设包括哪些_搜索引擎收录_武汉百度

cfg80211

概念

        cfg80211 是 Linux 内核中一个用于无线网络的配置和管理的子系统,它为多个无线网络驱动提供了一个统一的接口,以便于无线设备的配置和操作。cfg80211 的设计目标是提供一个简化的管理和配置无线设备的框架,同时支持多种无线设备的标准和功能,其在内核中的/net/wireless/core.c文件会对wifi使用的cfg80211进行初始化。

        iw,hostapd,wpa_supplicant等通过Netlink 套接字和构建消息来与内核空间进行交互。当启动 AP 模式时,hostapd 会将请求发送到内核,内核接收并调用 cfg80211 的 start_ap等函数来处理 AP 启动。这个设计使得用户空间能够灵活地管理无线接入点,同时保持与内核的高效通信

static int __init cfg80211_init(void)
{int err;err = register_pernet_device(&cfg80211_pernet_ops); //注册 cfg80211 作为一个网络命名空间的设备。这使得每个网络命名空间都能够独立地管理自己的无线设备if (err)goto out_fail_pernet;err = wiphy_sysfs_init(); //此函数创建并初始化与 wiphy 相关的 SysFS 属性,允许用户通过 /sys 文件系统管理和查看无线设备的状态if (err)goto out_fail_sysfs;err = register_netdevice_notifier(&cfg80211_netdev_notifier);if (err)goto out_fail_notifier;err = nl80211_init(); //初始化 cfg80211 的 Netlink 接口,使得用户空间可以通过 Netlink 与内核进行无线配置和管理通信if (err)goto out_fail_nl80211;ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL); //创建一个调试文件系统目录 ieee80211,用于调试和特定信息输出err = regulatory_init(); //初始化监管域(Regulatory Domain)子系统,负责管理无线设备的频谱使用和符合法规的需求if (err)goto out_fail_reg;cfg80211_wq = create_singlethread_workqueue("cfg80211"); //工作队列提供了异步任务处理机制,使得无线配置任务可以在后台线程中执行,不阻塞主要系统线程。if (!cfg80211_wq) {err = -ENOMEM;goto out_fail_wq;}return 0;
}

cfg80211_netdev_notifier的实例

这个notifier,再被操作网络设备时,会执行cfg80211对应的操作:比如注册,启动,停止,注销等行为

static int cfg80211_netdev_notifier_call(struct notifier_block *nb,unsigned long state,void *ndev)
{struct net_device *dev = ndev;struct wireless_dev *wdev = dev->ieee80211_ptr;struct cfg80211_registered_device *rdev;int ret;if (!wdev)return NOTIFY_DONE;rdev = wiphy_to_dev(wdev->wiphy);WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);switch (state) {case NETDEV_POST_INIT:SET_NETDEV_DEVTYPE(dev, &wiphy_type);break;case NETDEV_REGISTER:/** NB: cannot take rdev->mtx here because this may be* called within code protected by it when interfaces* are added with nl80211.*/mutex_init(&wdev->mtx);INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);INIT_LIST_HEAD(&wdev->event_list);spin_lock_init(&wdev->event_lock);INIT_LIST_HEAD(&wdev->mgmt_registrations);spin_lock_init(&wdev->mgmt_registrations_lock);mutex_lock(&rdev->devlist_mtx);wdev->identifier = ++rdev->wdev_id;list_add_rcu(&wdev->list, &rdev->wdev_list);rdev->devlist_generation++;/* can only change netns with wiphy */dev->features |= NETIF_F_NETNS_LOCAL;if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,"phy80211")) {pr_err("failed to add phy80211 symlink to netdev!\n");}wdev->netdev = dev;wdev->sme_state = CFG80211_SME_IDLE;mutex_unlock(&rdev->devlist_mtx);
#ifdef CONFIG_CFG80211_WEXTwdev->wext.default_key = -1;wdev->wext.default_mgmt_key = -1;wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
#endifif (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)wdev->ps = true;elsewdev->ps = false;/* allow mac80211 to determine the timeout */wdev->ps_timeout = -1;netdev_set_default_ethtool_ops(dev, &cfg80211_ethtool_ops);if ((wdev->iftype == NL80211_IFTYPE_STATION ||wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)dev->priv_flags |= IFF_DONT_BRIDGE;break;case NETDEV_GOING_DOWN:cfg80211_leave(rdev, wdev);break;case NETDEV_DOWN:cfg80211_update_iface_num(rdev, wdev->iftype, -1);dev_hold(dev);queue_work(cfg80211_wq, &wdev->cleanup_work);break;case NETDEV_UP:/** If we have a really quick DOWN/UP succession we may* have this work still pending ... cancel it and see* if it was pending, in which case we need to account* for some of the work it would have done.*/if (cancel_work_sync(&wdev->cleanup_work)) {mutex_lock(&rdev->devlist_mtx);rdev->opencount--;mutex_unlock(&rdev->devlist_mtx);dev_put(dev);}cfg80211_update_iface_num(rdev, wdev->iftype, 1);cfg80211_lock_rdev(rdev);mutex_lock(&rdev->devlist_mtx);mutex_lock(&rdev->sched_scan_mtx);wdev_lock(wdev);switch (wdev->iftype) {
#ifdef CONFIG_CFG80211_WEXTcase NL80211_IFTYPE_ADHOC:cfg80211_ibss_wext_join(rdev, wdev);break;case NL80211_IFTYPE_STATION:cfg80211_mgd_wext_connect(rdev, wdev);break;
#endif
#ifdef CONFIG_MAC80211_MESHcase NL80211_IFTYPE_MESH_POINT:{/* backward compat code... */struct mesh_setup setup;memcpy(&setup, &default_mesh_setup,sizeof(setup));/* back compat only needed for mesh_id */setup.mesh_id = wdev->ssid;setup.mesh_id_len = wdev->mesh_id_up_len;if (wdev->mesh_id_up_len)__cfg80211_join_mesh(rdev, dev,&setup,&default_mesh_config);break;}
#endifdefault:break;}wdev_unlock(wdev);mutex_unlock(&rdev->sched_scan_mtx);rdev->opencount++;mutex_unlock(&rdev->devlist_mtx);cfg80211_unlock_rdev(rdev);/** Configure power management to the driver here so that its* correctly set also after interface type changes etc.*/if ((wdev->iftype == NL80211_IFTYPE_STATION ||wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) &&rdev->ops->set_power_mgmt)if (rdev_set_power_mgmt(rdev, dev, wdev->ps,wdev->ps_timeout)) {/* assume this means it's off */wdev->ps = false;}break;case NETDEV_UNREGISTER:/** NB: cannot take rdev->mtx here because this may be* called within code protected by it when interfaces* are removed with nl80211.*/mutex_lock(&rdev->devlist_mtx);/** It is possible to get NETDEV_UNREGISTER* multiple times. To detect that, check* that the interface is still on the list* of registered interfaces, and only then* remove and clean it up.*/if (!list_empty(&wdev->list)) {sysfs_remove_link(&dev->dev.kobj, "phy80211");list_del_rcu(&wdev->list);rdev->devlist_generation++;cfg80211_mlme_purge_registrations(wdev);
#ifdef CONFIG_CFG80211_WEXTkfree(wdev->wext.keys);
#endif}mutex_unlock(&rdev->devlist_mtx);/** synchronise (so that we won't find this netdev* from other code any more) and then clear the list* head so that the above code can safely check for* !list_empty() to avoid double-cleanup.*/synchronize_rcu();INIT_LIST_HEAD(&wdev->list);/** Ensure that all events have been processed and* freed.*/cfg80211_process_wdev_events(wdev);break;case NETDEV_PRE_UP:if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))return notifier_from_errno(-EOPNOTSUPP);if (rfkill_blocked(rdev->rfkill))return notifier_from_errno(-ERFKILL);mutex_lock(&rdev->devlist_mtx);ret = cfg80211_can_add_interface(rdev, wdev->iftype);mutex_unlock(&rdev->devlist_mtx);if (ret)return notifier_from_errno(ret);break;}return NOTIFY_DONE;
}static struct notifier_block cfg80211_netdev_notifier = {.notifier_call = cfg80211_netdev_notifier_call,
};

NETDEV_GOING_DOWN

比如调用这个通知链时的事件是down钓一个wlan0设备,就会调用cfg80211_leave的cfg80211_stop_ap

void cfg80211_leave(struct cfg80211_registered_device *rdev,struct wireless_dev *wdev)
{struct net_device *dev = wdev->netdev;switch (wdev->iftype) {case NL80211_IFTYPE_ADHOC:cfg80211_leave_ibss(rdev, dev, true);break;case NL80211_IFTYPE_P2P_CLIENT:case NL80211_IFTYPE_STATION:mutex_lock(&rdev->sched_scan_mtx);__cfg80211_stop_sched_scan(rdev, false);mutex_unlock(&rdev->sched_scan_mtx);wdev_lock(wdev);
#ifdef CONFIG_CFG80211_WEXTkfree(wdev->wext.ie);wdev->wext.ie = NULL;wdev->wext.ie_len = 0;wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
#endif__cfg80211_disconnect(rdev, dev,WLAN_REASON_DEAUTH_LEAVING, true);wdev_unlock(wdev);break;case NL80211_IFTYPE_MESH_POINT:cfg80211_leave_mesh(rdev, dev);break;case NL80211_IFTYPE_AP:case NL80211_IFTYPE_P2P_GO:cfg80211_stop_ap(rdev, dev);break;default:break;}wdev->beacon_interval = 0;
}

会判断网络设备的ops有没有stop_ap成员

static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,struct net_device *dev)
{struct wireless_dev *wdev = dev->ieee80211_ptr;int err;ASSERT_WDEV_LOCK(wdev);if (!rdev->ops->stop_ap)return -EOPNOTSUPP;if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)return -EOPNOTSUPP;if (!wdev->beacon_interval)return -ENOENT;err = rdev_stop_ap(rdev, dev);if (!err) {wdev->beacon_interval = 0;wdev->channel = NULL;wdev->ssid_len = 0;}return err;
}

rdev_stop_ap会最终调用注册的设备的ops成员--stop_ap

static inline int rdev_stop_ap(struct cfg80211_registered_device *rdev,struct net_device *dev)
{int ret;trace_rdev_stop_ap(&rdev->wiphy, dev);ret = rdev->ops->stop_ap(&rdev->wiphy, dev);trace_rdev_return_int(&rdev->wiphy, ret);return ret;
}

cfg80211_registered_device是怎么初始化的?

某个wifi驱动将具体实现的ops,赋值给要注册的cfg80211_registered_device的ops成员

void my_wifi_init(){wiphy = wiphy_new(&ssv_cfg80211_ops, sizeof(struct ssv_softc));
}struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
{static int wiphy_counter;struct cfg80211_registered_device *rdev;int alloc_size;WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key));WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc));WARN_ON(ops->connect && !ops->disconnect);WARN_ON(ops->join_ibss && !ops->leave_ibss);WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf);WARN_ON(ops->add_station && !ops->del_station);WARN_ON(ops->add_mpath && !ops->del_mpath);WARN_ON(ops->join_mesh && !ops->leave_mesh);alloc_size = sizeof(*rdev) + sizeof_priv;rdev = kzalloc(alloc_size, GFP_KERNEL);if (!rdev)return NULL;rdev->ops = ops;mutex_lock(&cfg80211_mutex);rdev->wiphy_idx = wiphy_counter++;if (unlikely(rdev->wiphy_idx < 0)) {wiphy_counter--;mutex_unlock(&cfg80211_mutex);/* ugh, wrapped! */kfree(rdev);return NULL;}mutex_unlock(&cfg80211_mutex);/* give it a proper name */dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);mutex_init(&rdev->mtx);mutex_init(&rdev->devlist_mtx);mutex_init(&rdev->sched_scan_mtx);INIT_LIST_HEAD(&rdev->wdev_list);INIT_LIST_HEAD(&rdev->beacon_registrations);spin_lock_init(&rdev->beacon_registrations_lock);spin_lock_init(&rdev->bss_lock);INIT_LIST_HEAD(&rdev->bss_list);INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results);INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk,cfg80211_dfs_channels_update_work);
#ifdef CONFIG_CFG80211_WEXTrdev->wiphy.wext = &cfg80211_wext_handler;
#endifdevice_initialize(&rdev->wiphy.dev);rdev->wiphy.dev.class = &ieee80211_class;rdev->wiphy.dev.platform_data = rdev;#ifdef CONFIG_CFG80211_DEFAULT_PSrdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
#endifwiphy_net_set(&rdev->wiphy, &init_net);rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block;rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev),&rdev->wiphy.dev, RFKILL_TYPE_WLAN,&rdev->rfkill_ops, rdev);if (!rdev->rfkill) {kfree(rdev);return NULL;}INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work);INIT_WORK(&rdev->conn_work, cfg80211_conn_work);INIT_WORK(&rdev->event_work, cfg80211_event_work);init_waitqueue_head(&rdev->dev_wait);/** Initialize wiphy parameters to IEEE 802.11 MIB default values.* Fragmentation and RTS threshold are disabled by default with the* special -1 value.*/rdev->wiphy.retry_short = 7;rdev->wiphy.retry_long = 4;rdev->wiphy.frag_threshold = (u32) -1;rdev->wiphy.rts_threshold = (u32) -1;rdev->wiphy.coverage_class = 0;rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH;return &rdev->wiphy;
}
EXPORT_SYMBOL(wiphy_new);

wifi驱动会初始化一个cfg80211_ops的实例,并填充对应的操作函数

struct cfg80211_ops ssv_cfg80211_ops = {.add_virtual_intf = ssv_cfg80211_add_iface,.del_virtual_intf = ssv_cfg80211_del_iface,.change_virtual_intf = ssv_cfg80211_change_iface,.scan = ssv_cfg80211_scan,.connect = ssv_cfg80211_connect,.disconnect = ssv_cfg80211_disconnect,.add_key = ssv_cfg80211_add_key,.get_key = ssv_cfg80211_get_key,.del_key = ssv_cfg80211_del_key,.set_default_key = ssv_cfg80211_set_default_key,.set_default_mgmt_key = ssv_cfg80211_set_default_mgmt_key,.add_station = ssv_cfg80211_add_station,.del_station = ssv_cfg80211_del_station,.change_station = ssv_cfg80211_change_station,.mgmt_tx = ssv_cfg80211_mgmt_tx,.start_ap = ssv_cfg80211_start_ap,.change_beacon = ssv_cfg80211_change_beacon,.stop_ap = ssv_cfg80211_stop_ap,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0).set_monitor_channel = ssv_cfg80211_set_monitor_channel,
#endif.probe_client = ssv_cfg80211_probe_client,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0).update_mgmt_frame_registrations = ssv_cfg80211_update_mgmt_frame_registrations,
#else.mgmt_frame_register = ssv_cfg80211_mgmt_frame_register,
#endif.set_wiphy_params = ssv_cfg80211_set_wiphy_params,.set_txq_params = ssv_cfg80211_set_txq_params,.set_tx_power = ssv_cfg80211_set_tx_power,.remain_on_channel = ssv_cfg80211_remain_on_channel,.cancel_remain_on_channel = ssv_cfg80211_cancel_remain_on_channel,.dump_survey = ssv_cfg80211_dump_survey,
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0).set_channel = ssv_cfg80211_set_channel,
#endif.get_channel = ssv_cfg80211_get_channel,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0).update_ft_ies = ssv_cfg80211_update_ft_ies,
#endif.set_cqm_rssi_config = ssv_cfg80211_set_cqm_rssi_config,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0).channel_switch = ssv_cfg80211_channel_switch,
#endif.change_bss = ssv_cfg80211_change_bss,.get_station = ssv_cfg80211_get_station,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_SUPPORT_WPA3)).external_auth = ssv_cfg80211_external_auth,
#endif
};

比如stop_ap的实现如下

static int ssv_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{struct ssv_softc *sc = wiphy_priv(wiphy);struct ssv_vif *ssv_vif = netdev_priv(dev);struct ssv_sta *sta;int mgmt_txq;struct ssv_sta *cur, *tmp;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)struct station_del_parameters params;params.mac = NULL;
#endifSSV_LOG_DBG("[%s][%d]\n", __FUNCTION__, __LINE__);sc->is_stoping_apm=true;{ // turn off traffic for use_monitor interfacestruct ssv_vif *tmp_vif = NULL;list_for_each_entry(tmp_vif, &sc->vifs, list) {if (tmp_vif->use_monitor) {netif_tx_stop_all_queues(tmp_vif->ndev);netif_carrier_off(tmp_vif->ndev);break;}}}netif_tx_stop_all_queues(dev);netif_carrier_off(dev);mgmt_txq = (0 == ssv_vif->drv_vif_index) ? SSV_SW_TXQ_ID_MNG0 : SSV_SW_TXQ_ID_MNG1;ssv_drv_hci_tx_pause_by_sta(sc->hci_priv, sc->hci_ops, mgmt_txq);     //pause mgmt txqssv_drv_hci_tx_inactive_by_sta(sc->hci_priv, sc->hci_ops, mgmt_txq);  //inactive mgmt txqlist_for_each_entry_safe(cur, tmp, &ssv_vif->ap.sta_list, list) {ssv_drv_hci_tx_pause_by_sta(sc->hci_priv, sc->hci_ops, cur->sta_idx);     //pause hci tx queue by stassv_drv_hci_tx_inactive_by_sta(sc->hci_priv, sc->hci_ops, cur->sta_idx);  //inactive hci tx queue by sta}msleep(200);
#if 0ssv_send_apm_stop_req(sc, ssv_vif);mutex_lock(&sc->cb_lock);ssv_chanctx_unlink(ssv_vif);mutex_unlock(&sc->cb_lock);
#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)ssv_vif->bchan_setting = false;
#endif/* delete any remaining STA*/while (!list_empty(&ssv_vif->ap.sta_list)){
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)ssv_cfg80211_del_station(wiphy, dev, &params);
#elsessv_cfg80211_del_station(wiphy, dev, NULL);
#endif}
#if 1//give more times to cousmer the all tx packets//msleep(100);ssv_send_apm_stop_req(sc, ssv_vif);mutex_lock(&sc->cb_lock);ssv_chanctx_unlink(ssv_vif);mutex_unlock(&sc->cb_lock);
#endif/* delete BC/MC STA */sta = &sc->sta_table[ssv_vif->ap.bcmc_index];ssv_del_bcn(&ssv_vif->ap.bcn);ssv_del_csa(ssv_vif);ssv_drv_hci_tx_active_by_sta(sc->hci_priv, sc->hci_ops, mgmt_txq); //active hci mng. queuessv_drv_hci_tx_resume_by_sta(sc->hci_priv, sc->hci_ops, mgmt_txq); //resume hci mng. queueSSV_LOG_DBG(KERN_ERR"AP stop!!\r\n");sc->is_stoping_apm=false;return 0;
}

register_netdevice_notifier的使用

各网络模块的使用

主要是以通知链的形式,来对内核的各个模块。比如mac80211,ipv4/6,bridge,netfilter等模块也会调用register_netdevice_notifier注册对应函数,来响应网络设备的某种操作,以做出该模块需要做出的操作

int register_netdevice_notifier(struct notifier_block *nb)
{struct net_device *dev;struct net_device *last;struct net *net;int err;rtnl_lock();err = raw_notifier_chain_register(&netdev_chain, nb);if (err)goto unlock;if (dev_boot_phase)goto unlock;for_each_net(net) {for_each_netdev(net, dev) {err = nb->notifier_call(nb, NETDEV_REGISTER, dev);err = notifier_to_errno(err);if (err)goto rollback;if (!(dev->flags & IFF_UP))continue;nb->notifier_call(nb, NETDEV_UP, dev);}}unlock:rtnl_unlock();return err;rollback:last = dev;for_each_net(net) {for_each_netdev(net, dev) {if (dev == last)goto outroll;if (dev->flags & IFF_UP) {nb->notifier_call(nb, NETDEV_GOING_DOWN, dev);nb->notifier_call(nb, NETDEV_DOWN, dev);}nb->notifier_call(nb, NETDEV_UNREGISTER, dev);}}outroll:raw_notifier_chain_unregister(&netdev_chain, nb);goto unlock;
}
EXPORT_SYMBOL(register_netdevice_notifier);

比如bridge在初始化的时候也会调用register_netdevice_notifier来在netdev_chain链上注册一个对事件响应的notifier

static int __init br_init(void)
{int err;BUILD_BUG_ON(sizeof(struct br_input_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb));err = stp_proto_register(&br_stp_proto);if (err < 0) {pr_err("bridge: can't register sap for STP\n");return err;}err = br_fdb_init();if (err)goto err_out;err = register_pernet_subsys(&br_net_ops);if (err)goto err_out1;err = br_nf_core_init();if (err)goto err_out2;err = register_netdevice_notifier(&br_device_notifier);if (err)goto err_out3;err = register_switchdev_notifier(&br_switchdev_notifier);if (err)goto err_out4;err = br_netlink_init();if (err)goto err_out5;brioctl_set(br_ioctl_deviceless_stub);#if IS_ENABLED(CONFIG_ATM_LANE)br_fdb_test_addr_hook = br_fdb_test_addr;
#endif#if IS_MODULE(CONFIG_BRIDGE_NETFILTER)pr_info("bridge: filtering via arp/ip/ip6tables is no longer available ""by default. Update your scripts to load br_netfilter if you ""need this.\n");
#endifreturn 0;err_out5:unregister_switchdev_notifier(&br_switchdev_notifier);
err_out4:unregister_netdevice_notifier(&br_device_notifier);
err_out3:br_nf_core_fini();
err_out2:unregister_pernet_subsys(&br_net_ops);
err_out1:br_fdb_fini();
err_out:stp_proto_unregister(&br_stp_proto);return err;
}

会对各种事件,比如网络设备的up,down,register等做出桥的对应操作

static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
{struct net_device *dev = netdev_notifier_info_to_dev(ptr);struct net_bridge_port *p;struct net_bridge *br;bool changed_addr;int err;/* register of bridge completed, add sysfs entries */if ((dev->priv_flags & IFF_EBRIDGE) && event == NETDEV_REGISTER) {br_sysfs_addbr(dev);return NOTIFY_DONE;}/* not a port of a bridge */p = br_port_get_rtnl(dev);if (!p)return NOTIFY_DONE;br = p->br;switch (event) {case NETDEV_CHANGEMTU:dev_set_mtu(br->dev, br_min_mtu(br));break;case NETDEV_CHANGEADDR:spin_lock_bh(&br->lock);br_fdb_changeaddr(p, dev->dev_addr);changed_addr = br_stp_recalculate_bridge_id(br);spin_unlock_bh(&br->lock);if (changed_addr)call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);break;case NETDEV_CHANGE:br_port_carrier_check(p);break;case NETDEV_FEAT_CHANGE:netdev_update_features(br->dev);break;case NETDEV_DOWN:spin_lock_bh(&br->lock);if (br->dev->flags & IFF_UP)br_stp_disable_port(p);spin_unlock_bh(&br->lock);break;case NETDEV_UP:if (netif_running(br->dev) && netif_oper_up(dev)) {spin_lock_bh(&br->lock);br_stp_enable_port(p);spin_unlock_bh(&br->lock);}break;case NETDEV_UNREGISTER:br_del_if(br, dev);break;case NETDEV_CHANGENAME:err = br_sysfs_renameif(p);if (err)return notifier_from_errno(err);break;case NETDEV_PRE_TYPE_CHANGE:/* Forbid underlaying device to change its type. */return NOTIFY_BAD;case NETDEV_RESEND_IGMP:/* Propagate to master device */call_netdevice_notifiers(event, br->dev);break;}/* Events that may cause spanning tree to refresh */if (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||event == NETDEV_CHANGE || event == NETDEV_DOWN)br_ifinfo_notify(RTM_NEWLINK, p);return NOTIFY_DONE;
}static struct notifier_block br_device_notifier = {.notifier_call = br_device_event
};

ifconfig wlan0 up怎么实现的?

ioctl

针对这个最常见的命令,是通过ioctl来实现的,核心在/net/core/dev_ioctl.c

int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{struct ifreq ifr;int ret;char *colon;/* One special case: SIOCGIFCONF takes ifconf argumentand requires shared lock, because it sleeps writingto user space.*/if (cmd == SIOCGIFCONF) {rtnl_lock();ret = dev_ifconf(net, (char __user *) arg);rtnl_unlock();return ret;}if (cmd == SIOCGIFNAME)return dev_ifname(net, (struct ifreq __user *)arg);/** Take care of Wireless Extensions. Unfortunately struct iwreq* isn't a proper subset of struct ifreq (it's 8 byte shorter)* so we need to treat it specially, otherwise applications may* fault if the struct they're passing happens to land at the* end of a mapped page.*/if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {struct iwreq iwr;if (copy_from_user(&iwr, arg, sizeof(iwr)))return -EFAULT;iwr.ifr_name[sizeof(iwr.ifr_name) - 1] = 0;return wext_handle_ioctl(net, &iwr, cmd, arg);}if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))return -EFAULT;ifr.ifr_name[IFNAMSIZ-1] = 0;colon = strchr(ifr.ifr_name, ':');if (colon)*colon = 0;/**	See which interface the caller is talking about.*/switch (cmd) {/**	These ioctl calls:*	- can be done by all.*	- atomic and do not require locking.*	- return a value*/case SIOCGIFFLAGS:case SIOCGIFMETRIC:case SIOCGIFMTU:case SIOCGIFHWADDR:case SIOCGIFSLAVE:case SIOCGIFMAP:case SIOCGIFINDEX:case SIOCGIFTXQLEN:dev_load(net, ifr.ifr_name);rcu_read_lock();ret = dev_ifsioc_locked(net, &ifr, cmd);rcu_read_unlock();if (!ret) {if (colon)*colon = ':';if (copy_to_user(arg, &ifr,sizeof(struct ifreq)))ret = -EFAULT;}return ret;case SIOCETHTOOL:dev_load(net, ifr.ifr_name);rtnl_lock();ret = dev_ethtool(net, &ifr);rtnl_unlock();if (!ret) {if (colon)*colon = ':';if (copy_to_user(arg, &ifr,sizeof(struct ifreq)))ret = -EFAULT;}return ret;/**	These ioctl calls:*	- require superuser power.*	- require strict serialization.*	- return a value*/case SIOCGMIIPHY:case SIOCGMIIREG:case SIOCSIFNAME:if (!ns_capable(net->user_ns, CAP_NET_ADMIN))return -EPERM;dev_load(net, ifr.ifr_name);rtnl_lock();ret = dev_ifsioc(net, &ifr, cmd);rtnl_unlock();if (!ret) {if (colon)*colon = ':';if (copy_to_user(arg, &ifr,sizeof(struct ifreq)))ret = -EFAULT;}return ret;/**	These ioctl calls:*	- require superuser power.*	- require strict serialization.*	- do not return a value*/case SIOCSIFMAP:case SIOCSIFTXQLEN:if (!capable(CAP_NET_ADMIN))return -EPERM;/* fall through *//**	These ioctl calls:*	- require local superuser power.*	- require strict serialization.*	- do not return a value*/case SIOCSIFFLAGS:case SIOCSIFMETRIC:case SIOCSIFMTU:case SIOCSIFHWADDR:case SIOCSIFSLAVE:case SIOCADDMULTI:case SIOCDELMULTI:case SIOCSIFHWBROADCAST:case SIOCSMIIREG:case SIOCBONDENSLAVE:case SIOCBONDRELEASE:case SIOCBONDSETHWADDR:case SIOCBONDCHANGEACTIVE:case SIOCBRADDIF:case SIOCBRDELIF:case SIOCSHWTSTAMP:if (!ns_capable(net->user_ns, CAP_NET_ADMIN))return -EPERM;/* fall through */case SIOCBONDSLAVEINFOQUERY:case SIOCBONDINFOQUERY:dev_load(net, ifr.ifr_name);rtnl_lock();ret = dev_ifsioc(net, &ifr, cmd);rtnl_unlock();return ret;case SIOCGIFMEM:/* Get the per device memory space. We can add this but* currently do not support it */case SIOCSIFMEM:/* Set the per device memory buffer space.* Not applicable in our case */case SIOCSIFLINK:return -ENOTTY;/**	Unknown or private ioctl.*/default:if (cmd == SIOCWANDEV ||cmd == SIOCGHWTSTAMP ||(cmd >= SIOCDEVPRIVATE &&cmd <= SIOCDEVPRIVATE + 15)) {dev_load(net, ifr.ifr_name);rtnl_lock();ret = dev_ifsioc(net, &ifr, cmd);rtnl_unlock();if (!ret && copy_to_user(arg, &ifr,sizeof(struct ifreq)))ret = -EFAULT;return ret;}return -ENOTTY;}
}

dev_ifsioc就是对ifocnfig命令做出响应的具体函数

static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
{int err;struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);const struct net_device_ops *ops;if (!dev)return -ENODEV;ops = dev->netdev_ops;switch (cmd) {case SIOCSIFFLAGS:	/* Set interface flags */return dev_change_flags(dev, ifr->ifr_flags);case SIOCSIFMETRIC:	/* Set the metric on the interface(currently unused) */return -EOPNOTSUPP;case SIOCSIFMTU:	/* Set the MTU of a device */return dev_set_mtu(dev, ifr->ifr_mtu);case SIOCSIFHWADDR:if (dev->addr_len > sizeof(struct sockaddr))return -EINVAL;return dev_set_mac_address(dev, &ifr->ifr_hwaddr);case SIOCSIFHWBROADCAST:if (ifr->ifr_hwaddr.sa_family != dev->type)return -EINVAL;memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,min(sizeof(ifr->ifr_hwaddr.sa_data),(size_t)dev->addr_len));call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);return 0;case SIOCSIFMAP:if (ops->ndo_set_config) {if (!netif_device_present(dev))return -ENODEV;return ops->ndo_set_config(dev, &ifr->ifr_map);}return -EOPNOTSUPP;case SIOCADDMULTI:if (!ops->ndo_set_rx_mode ||ifr->ifr_hwaddr.sa_family != AF_UNSPEC)return -EINVAL;if (!netif_device_present(dev))return -ENODEV;return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);case SIOCDELMULTI:if (!ops->ndo_set_rx_mode ||ifr->ifr_hwaddr.sa_family != AF_UNSPEC)return -EINVAL;if (!netif_device_present(dev))return -ENODEV;return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data);case SIOCSIFTXQLEN:if (ifr->ifr_qlen < 0)return -EINVAL;if (dev->tx_queue_len ^ ifr->ifr_qlen) {unsigned int orig_len = dev->tx_queue_len;dev->tx_queue_len = ifr->ifr_qlen;err = call_netdevice_notifiers(NETDEV_CHANGE_TX_QUEUE_LEN, dev);err = notifier_to_errno(err);if (err) {dev->tx_queue_len = orig_len;return err;}}return 0;case SIOCSIFNAME:ifr->ifr_newname[IFNAMSIZ-1] = '\0';return dev_change_name(dev, ifr->ifr_newname);case SIOCSHWTSTAMP:err = net_hwtstamp_validate(ifr);if (err)return err;/* fall through *//**	Unknown or private ioctl*/default:if ((cmd >= SIOCDEVPRIVATE &&cmd <= SIOCDEVPRIVATE + 15) ||cmd == SIOCBONDENSLAVE ||cmd == SIOCBONDRELEASE ||cmd == SIOCBONDSETHWADDR ||cmd == SIOCBONDSLAVEINFOQUERY ||cmd == SIOCBONDINFOQUERY ||cmd == SIOCBONDCHANGEACTIVE ||cmd == SIOCGMIIPHY ||cmd == SIOCGMIIREG ||cmd == SIOCSMIIREG ||cmd == SIOCBRADDIF ||cmd == SIOCBRDELIF ||cmd == SIOCSHWTSTAMP ||cmd == SIOCGHWTSTAMP ||cmd == SIOCWANDEV) {err = -EOPNOTSUPP;if (ops->ndo_do_ioctl) {if (netif_device_present(dev))err = ops->ndo_do_ioctl(dev, ifr, cmd);elseerr = -ENODEV;}} elseerr = -EINVAL;}return err;
}

这个dev_change_flags就会检测对应的flag是否更改,以对更改的做出响应

int dev_change_flags(struct net_device *dev, unsigned int flags)
{int ret;unsigned int changes, old_flags = dev->flags, old_gflags = dev->gflags;ret = __dev_change_flags(dev, flags);if (ret < 0)return ret;changes = (old_flags ^ dev->flags) | (old_gflags ^ dev->gflags);__dev_notify_flags(dev, old_flags, changes);return ret;
}

call_netdevice_notifiers

最终通过通知连的形式去调用netdev_chain链的通知函数,cfg80211注册的有,最终是调用的是网络设备驱动提供的函数

void __dev_notify_flags(struct net_device *dev, unsigned int old_flags)
{unsigned int changes = dev->flags ^ old_flags;if (changes & IFF_UP) {if (dev->flags & IFF_UP)call_netdevice_notifiers(NETDEV_UP, dev);elsecall_netdevice_notifiers(NETDEV_DOWN, dev);}if (dev->flags & IFF_UP &&(changes & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE)))call_netdevice_notifiers(NETDEV_CHANGE, dev);
}int call_netdevice_notifiers(unsigned long val, struct net_device *dev)
{ASSERT_RTNL();return raw_notifier_call_chain(&netdev_chain, val, dev);
}
EXPORT_SYMBOL(call_netdevice_notifiers);

wlan0的注册

通过register_netdevice来注册网络设备,比如wlan0;call_netdevice_notifiers(NETDEV_POST_INIT, dev)调用事件为初始化call_netdevice_notifiers(NETDEV_REGISTER, dev);调用事件为注册

int register_netdevice(struct net_device *dev)
{int ret;struct net *net = dev_net(dev);BUG_ON(dev_boot_phase);ASSERT_RTNL();might_sleep();/* When net_device's are persistent, this will be fatal. */BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);BUG_ON(!net);spin_lock_init(&dev->addr_list_lock);netdev_set_addr_lockdep_class(dev);ret = dev_get_valid_name(net, dev, dev->name);if (ret < 0)goto out;/* Init, if this function is available */if (dev->netdev_ops->ndo_init) {ret = dev->netdev_ops->ndo_init(dev);if (ret) {if (ret > 0)ret = -EIO;goto out;}}if (((dev->hw_features | dev->features) &NETIF_F_HW_VLAN_CTAG_FILTER) &&(!dev->netdev_ops->ndo_vlan_rx_add_vid ||!dev->netdev_ops->ndo_vlan_rx_kill_vid)) {netdev_WARN(dev, "Buggy VLAN acceleration in driver!\n");ret = -EINVAL;goto err_uninit;}ret = -EBUSY;if (!dev->ifindex)dev->ifindex = dev_new_index(net);else if (__dev_get_by_index(net, dev->ifindex))goto err_uninit;/* Transfer changeable features to wanted_features and enable* software offloads (GSO and GRO).*/dev->hw_features |= NETIF_F_SOFT_FEATURES;dev->features |= NETIF_F_SOFT_FEATURES;if (dev->netdev_ops->ndo_udp_tunnel_add) {dev->features |= NETIF_F_RX_UDP_TUNNEL_PORT;dev->hw_features |= NETIF_F_RX_UDP_TUNNEL_PORT;}dev->wanted_features = dev->features & dev->hw_features;if (!(dev->flags & IFF_LOOPBACK))dev->hw_features |= NETIF_F_NOCACHE_COPY;/* If IPv4 TCP segmentation offload is supported we should also* allow the device to enable segmenting the frame with the option* of ignoring a static IP ID value.  This doesn't enable the* feature itself but allows the user to enable it later.*/if (dev->hw_features & NETIF_F_TSO)dev->hw_features |= NETIF_F_TSO_MANGLEID;if (dev->vlan_features & NETIF_F_TSO)dev->vlan_features |= NETIF_F_TSO_MANGLEID;if (dev->mpls_features & NETIF_F_TSO)dev->mpls_features |= NETIF_F_TSO_MANGLEID;if (dev->hw_enc_features & NETIF_F_TSO)dev->hw_enc_features |= NETIF_F_TSO_MANGLEID;/* Make NETIF_F_HIGHDMA inheritable to VLAN devices.*/dev->vlan_features |= NETIF_F_HIGHDMA;/* Make NETIF_F_SG inheritable to tunnel devices.*/dev->hw_enc_features |= NETIF_F_SG | NETIF_F_GSO_PARTIAL;/* Make NETIF_F_SG inheritable to MPLS.*/dev->mpls_features |= NETIF_F_SG;ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev); //调用初始化ret = notifier_to_errno(ret);if (ret)goto err_uninit;ret = netdev_register_kobject(dev);if (ret)goto err_uninit;dev->reg_state = NETREG_REGISTERED;__netdev_update_features(dev);/**	Default initial state at registry is that the*	device is present.*/set_bit(__LINK_STATE_PRESENT, &dev->state);linkwatch_init_dev(dev);dev_init_scheduler(dev);dev_hold(dev);list_netdevice(dev);add_device_randomness(dev->dev_addr, dev->addr_len);/* If the device has permanent device address, driver should* set dev_addr and also addr_assign_type should be set to* NET_ADDR_PERM (default value).*/if (dev->addr_assign_type == NET_ADDR_PERM)memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);/* Notify protocols, that a new device appeared. */ret = call_netdevice_notifiers(NETDEV_REGISTER, dev); //调用注册ret = notifier_to_errno(ret);if (ret) {rollback_registered(dev);dev->reg_state = NETREG_UNREGISTERED;}/**	Prevent userspace races by waiting until the network*	device is fully setup before sending notifications.*/if (!dev->rtnl_link_ops ||dev->rtnl_link_state == RTNL_LINK_INITIALIZED)rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL);out:return ret;err_uninit:if (dev->netdev_ops->ndo_uninit)dev->netdev_ops->ndo_uninit(dev);if (dev->priv_destructor)dev->priv_destructor(dev);goto out;
}
EXPORT_SYMBOL(register_netdevice);

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com