aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/rtnetlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r--net/core/rtnetlink.c176
1 files changed, 164 insertions, 12 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index eca2976abb25..3fcfa9c59e1f 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -35,6 +35,7 @@
35#include <linux/skbuff.h> 35#include <linux/skbuff.h>
36#include <linux/init.h> 36#include <linux/init.h>
37#include <linux/security.h> 37#include <linux/security.h>
38#include <linux/mutex.h>
38 39
39#include <asm/uaccess.h> 40#include <asm/uaccess.h>
40#include <asm/system.h> 41#include <asm/system.h>
@@ -50,26 +51,36 @@
50#include <net/sock.h> 51#include <net/sock.h>
51#include <net/pkt_sched.h> 52#include <net/pkt_sched.h>
52#include <net/netlink.h> 53#include <net/netlink.h>
54#ifdef CONFIG_NET_WIRELESS_RTNETLINK
55#include <linux/wireless.h>
56#include <net/iw_handler.h>
57#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
53 58
54DECLARE_MUTEX(rtnl_sem); 59static DEFINE_MUTEX(rtnl_mutex);
55 60
56void rtnl_lock(void) 61void rtnl_lock(void)
57{ 62{
58 rtnl_shlock(); 63 mutex_lock(&rtnl_mutex);
59} 64}
60 65
61int rtnl_lock_interruptible(void) 66void __rtnl_unlock(void)
62{ 67{
63 return down_interruptible(&rtnl_sem); 68 mutex_unlock(&rtnl_mutex);
64} 69}
65 70
66void rtnl_unlock(void) 71void rtnl_unlock(void)
67{ 72{
68 rtnl_shunlock(); 73 mutex_unlock(&rtnl_mutex);
69 74 if (rtnl && rtnl->sk_receive_queue.qlen)
75 rtnl->sk_data_ready(rtnl, 0);
70 netdev_run_todo(); 76 netdev_run_todo();
71} 77}
72 78
79int rtnl_trylock(void)
80{
81 return mutex_trylock(&rtnl_mutex);
82}
83
73int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len) 84int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
74{ 85{
75 memset(tb, 0, sizeof(struct rtattr*)*maxattr); 86 memset(tb, 0, sizeof(struct rtattr*)*maxattr);
@@ -179,6 +190,33 @@ rtattr_failure:
179} 190}
180 191
181 192
193static void set_operstate(struct net_device *dev, unsigned char transition)
194{
195 unsigned char operstate = dev->operstate;
196
197 switch(transition) {
198 case IF_OPER_UP:
199 if ((operstate == IF_OPER_DORMANT ||
200 operstate == IF_OPER_UNKNOWN) &&
201 !netif_dormant(dev))
202 operstate = IF_OPER_UP;
203 break;
204
205 case IF_OPER_DORMANT:
206 if (operstate == IF_OPER_UP ||
207 operstate == IF_OPER_UNKNOWN)
208 operstate = IF_OPER_DORMANT;
209 break;
210 };
211
212 if (dev->operstate != operstate) {
213 write_lock_bh(&dev_base_lock);
214 dev->operstate = operstate;
215 write_unlock_bh(&dev_base_lock);
216 netdev_state_change(dev);
217 }
218}
219
182static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, 220static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
183 int type, u32 pid, u32 seq, u32 change, 221 int type, u32 pid, u32 seq, u32 change,
184 unsigned int flags) 222 unsigned int flags)
@@ -209,6 +247,13 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
209 } 247 }
210 248
211 if (1) { 249 if (1) {
250 u8 operstate = netif_running(dev)?dev->operstate:IF_OPER_DOWN;
251 u8 link_mode = dev->link_mode;
252 RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate);
253 RTA_PUT(skb, IFLA_LINKMODE, sizeof(link_mode), &link_mode);
254 }
255
256 if (1) {
212 struct rtnl_link_ifmap map = { 257 struct rtnl_link_ifmap map = {
213 .mem_start = dev->mem_start, 258 .mem_start = dev->mem_start,
214 .mem_end = dev->mem_end, 259 .mem_end = dev->mem_end,
@@ -399,6 +444,22 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
399 dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1])); 444 dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1]));
400 } 445 }
401 446
447 if (ida[IFLA_OPERSTATE - 1]) {
448 if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
449 goto out;
450
451 set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1])));
452 }
453
454 if (ida[IFLA_LINKMODE - 1]) {
455 if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
456 goto out;
457
458 write_lock_bh(&dev_base_lock);
459 dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1]));
460 write_unlock_bh(&dev_base_lock);
461 }
462
402 if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) { 463 if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
403 char ifname[IFNAMSIZ]; 464 char ifname[IFNAMSIZ];
404 465
@@ -410,6 +471,17 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
410 goto out; 471 goto out;
411 } 472 }
412 473
474#ifdef CONFIG_NET_WIRELESS_RTNETLINK
475 if (ida[IFLA_WIRELESS - 1]) {
476
477 /* Call Wireless Extensions.
478 * Various stuff checked in there... */
479 err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len);
480 if (err)
481 goto out;
482 }
483#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
484
413 err = 0; 485 err = 0;
414 486
415out: 487out:
@@ -420,6 +492,83 @@ out:
420 return err; 492 return err;
421} 493}
422 494
495#ifdef CONFIG_NET_WIRELESS_RTNETLINK
496static int do_getlink(struct sk_buff *in_skb, struct nlmsghdr* in_nlh, void *arg)
497{
498 struct ifinfomsg *ifm = NLMSG_DATA(in_nlh);
499 struct rtattr **ida = arg;
500 struct net_device *dev;
501 struct ifinfomsg *r;
502 struct nlmsghdr *nlh;
503 int err = -ENOBUFS;
504 struct sk_buff *skb;
505 unsigned char *b;
506 char *iw_buf = NULL;
507 int iw_buf_len = 0;
508
509 if (ifm->ifi_index >= 0)
510 dev = dev_get_by_index(ifm->ifi_index);
511 else
512 return -EINVAL;
513 if (!dev)
514 return -ENODEV;
515
516#ifdef CONFIG_NET_WIRELESS_RTNETLINK
517 if (ida[IFLA_WIRELESS - 1]) {
518
519 /* Call Wireless Extensions. We need to know the size before
520 * we can alloc. Various stuff checked in there... */
521 err = wireless_rtnetlink_get(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len, &iw_buf, &iw_buf_len);
522 if (err)
523 goto out;
524 }
525#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
526
527 /* Create a skb big enough to include all the data.
528 * Some requests are way bigger than 4k... Jean II */
529 skb = alloc_skb((NLMSG_LENGTH(sizeof(*r))) + (RTA_SPACE(iw_buf_len)),
530 GFP_KERNEL);
531 if (!skb)
532 goto out;
533 b = skb->tail;
534
535 /* Put in the message the usual good stuff */
536 nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, in_nlh->nlmsg_seq,
537 RTM_NEWLINK, sizeof(*r));
538 r = NLMSG_DATA(nlh);
539 r->ifi_family = AF_UNSPEC;
540 r->__ifi_pad = 0;
541 r->ifi_type = dev->type;
542 r->ifi_index = dev->ifindex;
543 r->ifi_flags = dev->flags;
544 r->ifi_change = 0;
545
546 /* Put the wireless payload if it exist */
547 if(iw_buf != NULL)
548 RTA_PUT(skb, IFLA_WIRELESS, iw_buf_len,
549 iw_buf + IW_EV_POINT_OFF);
550
551 nlh->nlmsg_len = skb->tail - b;
552
553 /* Needed ? */
554 NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
555
556 err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
557 if (err > 0)
558 err = 0;
559out:
560 if(iw_buf != NULL)
561 kfree(iw_buf);
562 dev_put(dev);
563 return err;
564
565rtattr_failure:
566nlmsg_failure:
567 kfree_skb(skb);
568 goto out;
569}
570#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
571
423static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb) 572static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
424{ 573{
425 int idx; 574 int idx;
@@ -575,9 +724,9 @@ static void rtnetlink_rcv(struct sock *sk, int len)
575 unsigned int qlen = 0; 724 unsigned int qlen = 0;
576 725
577 do { 726 do {
578 rtnl_lock(); 727 mutex_lock(&rtnl_mutex);
579 netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg); 728 netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg);
580 up(&rtnl_sem); 729 mutex_unlock(&rtnl_mutex);
581 730
582 netdev_run_todo(); 731 netdev_run_todo();
583 } while (qlen); 732 } while (qlen);
@@ -585,7 +734,11 @@ static void rtnetlink_rcv(struct sock *sk, int len)
585 734
586static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = 735static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
587{ 736{
588 [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, 737 [RTM_GETLINK - RTM_BASE] = {
738#ifdef CONFIG_NET_WIRELESS_RTNETLINK
739 .doit = do_getlink,
740#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
741 .dumpit = rtnetlink_dump_ifinfo },
589 [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, 742 [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink },
590 [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 743 [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
591 [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 744 [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
@@ -654,6 +807,5 @@ EXPORT_SYMBOL(rtnetlink_links);
654EXPORT_SYMBOL(rtnetlink_put_metrics); 807EXPORT_SYMBOL(rtnetlink_put_metrics);
655EXPORT_SYMBOL(rtnl); 808EXPORT_SYMBOL(rtnl);
656EXPORT_SYMBOL(rtnl_lock); 809EXPORT_SYMBOL(rtnl_lock);
657EXPORT_SYMBOL(rtnl_lock_interruptible); 810EXPORT_SYMBOL(rtnl_trylock);
658EXPORT_SYMBOL(rtnl_sem);
659EXPORT_SYMBOL(rtnl_unlock); 811EXPORT_SYMBOL(rtnl_unlock);