]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/core/rtnetlink.c
[NET] core: add RFC2863 operstate
[net-next-2.6.git] / net / core / rtnetlink.c
index 8700379685e0d7b1b7c74d6d6e5a5e46f7faed85..1c15a907066ff26f1e960771d39d70ea6ab7c6c8 100644 (file)
@@ -179,6 +179,33 @@ rtattr_failure:
 }
 
 
+static void set_operstate(struct net_device *dev, unsigned char transition)
+{
+       unsigned char operstate = dev->operstate;
+
+       switch(transition) {
+       case IF_OPER_UP:
+               if ((operstate == IF_OPER_DORMANT ||
+                    operstate == IF_OPER_UNKNOWN) &&
+                   !netif_dormant(dev))
+                       operstate = IF_OPER_UP;
+               break;
+
+       case IF_OPER_DORMANT:
+               if (operstate == IF_OPER_UP ||
+                   operstate == IF_OPER_UNKNOWN)
+                       operstate = IF_OPER_DORMANT;
+               break;
+       };
+
+       if (dev->operstate != operstate) {
+               write_lock_bh(&dev_base_lock);
+               dev->operstate = operstate;
+               write_unlock_bh(&dev_base_lock);
+               netdev_state_change(dev);
+       }
+}
+
 static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                                 int type, u32 pid, u32 seq, u32 change, 
                                 unsigned int flags)
@@ -208,6 +235,13 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                RTA_PUT(skb, IFLA_WEIGHT, sizeof(weight), &weight);
        }
 
+       if (1) {
+               u8 operstate = netif_running(dev)?dev->operstate:IF_OPER_DOWN;
+               u8 link_mode = dev->link_mode;
+               RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate);
+               RTA_PUT(skb, IFLA_LINKMODE, sizeof(link_mode), &link_mode);
+       }
+
        if (1) {
                struct rtnl_link_ifmap map = {
                        .mem_start   = dev->mem_start,
@@ -399,6 +433,22 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1]));
        }
 
+       if (ida[IFLA_OPERSTATE - 1]) {
+               if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
+                       goto out;
+
+               set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1])));
+       }
+
+       if (ida[IFLA_LINKMODE - 1]) {
+               if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
+                       goto out;
+
+               write_lock_bh(&dev_base_lock);
+               dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1]));
+               write_unlock_bh(&dev_base_lock);
+       }
+
        if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
                char ifname[IFNAMSIZ];
 
@@ -455,7 +505,7 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
        if (!skb)
                return;
 
-       if (rtnetlink_fill_ifinfo(skb, dev, type, current->pid, 0, change, 0) < 0) {
+       if (rtnetlink_fill_ifinfo(skb, dev, type, 0, 0, change, 0) < 0) {
                kfree_skb(skb);
                return;
        }