网络子系统6_设备开启与关闭

来源:互联网 发布:女生宿舍关系 知乎 编辑:程序博客网 时间:2024/05/22 14:33
//网络设备开启//函数主要任务://1.设置dev->state=__LINK_STATE_START//2.调用驱动程序的回调函数open//3.设置dev->flags |= IFF_UP表示设备开启//4.更新多播列表,//5.激活设备//6.通知监听器,设置dev->flags//设备开启之后应该具备的特征://1.dev->state, 表示设备可以进行传输接收//2.dev->flags,表示设备已经开启//3.设备使用了正确的队列规则1.1 int dev_open(struct net_device *dev){int ret = 0;//检查设备是否已经开启if (dev->flags & IFF_UP)return 0;//检查设备是否存在if (!netif_device_present(dev))return -ENODEV;//设置设备可以进行接收set_bit(__LINK_STATE_START, &dev->state);if (dev->open) {//如果驱动程序提供了open函数,则调用ret = dev->open(dev);if (ret)clear_bit(__LINK_STATE_START, &dev->state);}if (!ret) {//设置开启标志dev->flags |= IFF_UP;//加载多播地址列表dev_mc_upload(dev);//激活设备,使能传输队列dev_activate(dev);//向netdev_chain通知有设备开启notifier_call_chain(&netdev_chain, NETDEV_UP, dev);}return ret;}//加载设备多播地址//调用路径:dev_open->dev_mc_upload//ip地址,mac地址之间的映射,参照http://blog.csdn.net/hxg130435477/article/details/80492711.2 void dev_mc_upload(struct net_device *dev){spin_lock_bh(&dev->xmit_lock);__dev_mc_upload(dev);spin_unlock_bh(&dev->xmit_lock);}//调用路径:dev_open->dev_mc_upload->__dev_mc_upload//通过驱动程序的回调函数,设置设备的l2多播地址列表1.3 static void __dev_mc_upload(struct net_device *dev){//设备应该处于关闭状态if (!(dev->flags&IFF_UP))return;//设备驱动提供了设置多播地址的方法if (dev->set_multicast_list == NULL ||    !netif_device_present(dev))return;//调用设备提供的设置多播地址的方法dev->set_multicast_list(dev);}//调用路径:dev_open->dev_activate//函数主要任务://1.更新设备的队列规则//1.1 如果设备没有使用队列规则,则dev->qdisc设置为noqueue_disc,防止不正确的使用该驱动的队列规则//1.2 如果设备使用队列规则://1.2.1 如果设置第一次被激活,则分配新的队列规则,保存在dev->qdisc_sleeping//1.2.2 如果设备非第一次被激活//1.2.3 设置dev->qdisc=dev->qdisc_sleeping//2.启动看门狗1.4 void dev_activate(struct net_device *dev){//设备没有关联队列规则if (dev->qdisc_sleeping == &noop_qdisc) {struct Qdisc *qdisc;//设备存在传输队列//dev->tx_queue_len的值由设备驱动程序设置if (dev->tx_queue_len) {//创建先进先出队列qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops);if (qdisc == NULL) {printk(KERN_INFO "%s: activation failed\n", dev->name);return;}//将队列规则添加到dev的队列规则链表头//说明一个dev可以有多个队列规则write_lock_bh(&qdisc_tree_lock);list_add_tail(&qdisc->list, &dev->qdisc_list);write_unlock_bh(&qdisc_tree_lock);} else {//如果驱动程序没有提供tx_queue_len,即=0//设置默认的队列qdisc =  &noqueue_qdisc;}write_lock_bh(&qdisc_tree_lock);//设置dev的qdisc_sleepingdev->qdisc_sleeping = qdisc;write_unlock_bh(&qdisc_tree_lock);}spin_lock_bh(&dev->queue_lock);//设置qdisc_sleep到qdisc字段rcu_assign_pointer(dev->qdisc, dev->qdisc_sleeping);if (dev->qdisc != &noqueue_qdisc) {dev->trans_start = jiffies;//唤醒看门狗dev_watchdog_up(dev);}spin_unlock_bh(&dev->queue_lock);}//设备关闭//函数主要任务://1.向netdev_chain发送消息NETDEV_GOING_DOWN//2.deactivate设备,//3.清除dev->state的__LINK_STATE_START//4.等待设备完成数据接收//5.调用驱动程序提供的关闭函数//6清除dev->flags中的IFF_UP//7.向netdev_chain发送消息NETDEV_DOWN2.1 int dev_close(struct net_device *dev){//设备已经关闭,则直接返回if (!(dev->flags & IFF_UP))return 0;//向netdev_chain发送设备正在关闭消息notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);//关闭设备队列规则dev_deactivate(dev);//设置设备关闭传输clear_bit(__LINK_STATE_START, &dev->state);//内存屏障smp_mb__after_clear_bit(); //设备还在接收输入流量while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) {//调度当前线程等待current->state = TASK_INTERRUPTIBLE;schedule_timeout(1);}//驱动提供了停止函数,则调用if (dev->stop)dev->stop(dev);//清除IFF_UP标志,表示设备已被关闭dev->flags &= ~IFF_UP;//通知netdev_chain已关闭消息notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);return 0;}//网络设备的看门狗://1.当网络设备由于被开启而激活传输时,同时激活设备驱动程序的开门狗机制。//2.看门狗的定时周期由驱动程序通过dev->watchdog_time指定//3.看门狗的定时器由驱动程序通过dev->watchdog_timer提供//调用路径:dev_activate->dev_watchdog_up3.1 static void dev_watchdog_up(struct net_device *dev){//在获取dev->xmit_lock传输锁时设置看门狗定时器spin_lock_bh(&dev->xmit_lock);__netdev_watchdog_up(dev);spin_unlock_bh(&dev->xmit_lock);}// 调用路径dev_activate->dev_watchdog_up->__netdev_watchdog_upvoid __netdev_watchdog_up(struct net_device *dev){if (dev->tx_timeout) {if (dev->watchdog_timeo <= 0)//设备驱动没有设置看门狗的到期时间dev->watchdog_timeo = 5*HZ;if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))dev_hold(dev);}}


原创粉丝点击