1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * INET An implementation of the TCP/IP protocol suite for the LINUX 3*1da177e4SLinus Torvalds * operating system. INET is implemented using the BSD Socket 4*1da177e4SLinus Torvalds * interface as the means of communication with the user level. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * Routing netlink socket interface: protocol independent part. 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 9*1da177e4SLinus Torvalds * 10*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 11*1da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 12*1da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 13*1da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 14*1da177e4SLinus Torvalds * 15*1da177e4SLinus Torvalds * Fixes: 16*1da177e4SLinus Torvalds * Vitaly E. Lavrov RTA_OK arithmetics was wrong. 17*1da177e4SLinus Torvalds */ 18*1da177e4SLinus Torvalds 19*1da177e4SLinus Torvalds #include <linux/config.h> 20*1da177e4SLinus Torvalds #include <linux/errno.h> 21*1da177e4SLinus Torvalds #include <linux/module.h> 22*1da177e4SLinus Torvalds #include <linux/types.h> 23*1da177e4SLinus Torvalds #include <linux/socket.h> 24*1da177e4SLinus Torvalds #include <linux/kernel.h> 25*1da177e4SLinus Torvalds #include <linux/major.h> 26*1da177e4SLinus Torvalds #include <linux/sched.h> 27*1da177e4SLinus Torvalds #include <linux/timer.h> 28*1da177e4SLinus Torvalds #include <linux/string.h> 29*1da177e4SLinus Torvalds #include <linux/sockios.h> 30*1da177e4SLinus Torvalds #include <linux/net.h> 31*1da177e4SLinus Torvalds #include <linux/fcntl.h> 32*1da177e4SLinus Torvalds #include <linux/mm.h> 33*1da177e4SLinus Torvalds #include <linux/slab.h> 34*1da177e4SLinus Torvalds #include <linux/interrupt.h> 35*1da177e4SLinus Torvalds #include <linux/capability.h> 36*1da177e4SLinus Torvalds #include <linux/skbuff.h> 37*1da177e4SLinus Torvalds #include <linux/init.h> 38*1da177e4SLinus Torvalds #include <linux/security.h> 39*1da177e4SLinus Torvalds 40*1da177e4SLinus Torvalds #include <asm/uaccess.h> 41*1da177e4SLinus Torvalds #include <asm/system.h> 42*1da177e4SLinus Torvalds #include <asm/string.h> 43*1da177e4SLinus Torvalds 44*1da177e4SLinus Torvalds #include <linux/inet.h> 45*1da177e4SLinus Torvalds #include <linux/netdevice.h> 46*1da177e4SLinus Torvalds #include <net/ip.h> 47*1da177e4SLinus Torvalds #include <net/protocol.h> 48*1da177e4SLinus Torvalds #include <net/arp.h> 49*1da177e4SLinus Torvalds #include <net/route.h> 50*1da177e4SLinus Torvalds #include <net/udp.h> 51*1da177e4SLinus Torvalds #include <net/sock.h> 52*1da177e4SLinus Torvalds #include <net/pkt_sched.h> 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds DECLARE_MUTEX(rtnl_sem); 55*1da177e4SLinus Torvalds 56*1da177e4SLinus Torvalds void rtnl_lock(void) 57*1da177e4SLinus Torvalds { 58*1da177e4SLinus Torvalds rtnl_shlock(); 59*1da177e4SLinus Torvalds } 60*1da177e4SLinus Torvalds 61*1da177e4SLinus Torvalds int rtnl_lock_interruptible(void) 62*1da177e4SLinus Torvalds { 63*1da177e4SLinus Torvalds return down_interruptible(&rtnl_sem); 64*1da177e4SLinus Torvalds } 65*1da177e4SLinus Torvalds 66*1da177e4SLinus Torvalds void rtnl_unlock(void) 67*1da177e4SLinus Torvalds { 68*1da177e4SLinus Torvalds rtnl_shunlock(); 69*1da177e4SLinus Torvalds 70*1da177e4SLinus Torvalds netdev_run_todo(); 71*1da177e4SLinus Torvalds } 72*1da177e4SLinus Torvalds 73*1da177e4SLinus Torvalds int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len) 74*1da177e4SLinus Torvalds { 75*1da177e4SLinus Torvalds memset(tb, 0, sizeof(struct rtattr*)*maxattr); 76*1da177e4SLinus Torvalds 77*1da177e4SLinus Torvalds while (RTA_OK(rta, len)) { 78*1da177e4SLinus Torvalds unsigned flavor = rta->rta_type; 79*1da177e4SLinus Torvalds if (flavor && flavor <= maxattr) 80*1da177e4SLinus Torvalds tb[flavor-1] = rta; 81*1da177e4SLinus Torvalds rta = RTA_NEXT(rta, len); 82*1da177e4SLinus Torvalds } 83*1da177e4SLinus Torvalds return 0; 84*1da177e4SLinus Torvalds } 85*1da177e4SLinus Torvalds 86*1da177e4SLinus Torvalds struct sock *rtnl; 87*1da177e4SLinus Torvalds 88*1da177e4SLinus Torvalds struct rtnetlink_link * rtnetlink_links[NPROTO]; 89*1da177e4SLinus Torvalds 90*1da177e4SLinus Torvalds static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] = 91*1da177e4SLinus Torvalds { 92*1da177e4SLinus Torvalds NLMSG_LENGTH(sizeof(struct ifinfomsg)), 93*1da177e4SLinus Torvalds NLMSG_LENGTH(sizeof(struct ifaddrmsg)), 94*1da177e4SLinus Torvalds NLMSG_LENGTH(sizeof(struct rtmsg)), 95*1da177e4SLinus Torvalds NLMSG_LENGTH(sizeof(struct ndmsg)), 96*1da177e4SLinus Torvalds NLMSG_LENGTH(sizeof(struct rtmsg)), 97*1da177e4SLinus Torvalds NLMSG_LENGTH(sizeof(struct tcmsg)), 98*1da177e4SLinus Torvalds NLMSG_LENGTH(sizeof(struct tcmsg)), 99*1da177e4SLinus Torvalds NLMSG_LENGTH(sizeof(struct tcmsg)), 100*1da177e4SLinus Torvalds NLMSG_LENGTH(sizeof(struct tcamsg)) 101*1da177e4SLinus Torvalds }; 102*1da177e4SLinus Torvalds 103*1da177e4SLinus Torvalds static const int rta_max[(RTM_MAX+1-RTM_BASE)/4] = 104*1da177e4SLinus Torvalds { 105*1da177e4SLinus Torvalds IFLA_MAX, 106*1da177e4SLinus Torvalds IFA_MAX, 107*1da177e4SLinus Torvalds RTA_MAX, 108*1da177e4SLinus Torvalds NDA_MAX, 109*1da177e4SLinus Torvalds RTA_MAX, 110*1da177e4SLinus Torvalds TCA_MAX, 111*1da177e4SLinus Torvalds TCA_MAX, 112*1da177e4SLinus Torvalds TCA_MAX, 113*1da177e4SLinus Torvalds TCAA_MAX 114*1da177e4SLinus Torvalds }; 115*1da177e4SLinus Torvalds 116*1da177e4SLinus Torvalds void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) 117*1da177e4SLinus Torvalds { 118*1da177e4SLinus Torvalds struct rtattr *rta; 119*1da177e4SLinus Torvalds int size = RTA_LENGTH(attrlen); 120*1da177e4SLinus Torvalds 121*1da177e4SLinus Torvalds rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size)); 122*1da177e4SLinus Torvalds rta->rta_type = attrtype; 123*1da177e4SLinus Torvalds rta->rta_len = size; 124*1da177e4SLinus Torvalds memcpy(RTA_DATA(rta), data, attrlen); 125*1da177e4SLinus Torvalds } 126*1da177e4SLinus Torvalds 127*1da177e4SLinus Torvalds size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size) 128*1da177e4SLinus Torvalds { 129*1da177e4SLinus Torvalds size_t ret = RTA_PAYLOAD(rta); 130*1da177e4SLinus Torvalds char *src = RTA_DATA(rta); 131*1da177e4SLinus Torvalds 132*1da177e4SLinus Torvalds if (ret > 0 && src[ret - 1] == '\0') 133*1da177e4SLinus Torvalds ret--; 134*1da177e4SLinus Torvalds if (size > 0) { 135*1da177e4SLinus Torvalds size_t len = (ret >= size) ? size - 1 : ret; 136*1da177e4SLinus Torvalds memset(dest, 0, size); 137*1da177e4SLinus Torvalds memcpy(dest, src, len); 138*1da177e4SLinus Torvalds } 139*1da177e4SLinus Torvalds return ret; 140*1da177e4SLinus Torvalds } 141*1da177e4SLinus Torvalds 142*1da177e4SLinus Torvalds int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) 143*1da177e4SLinus Torvalds { 144*1da177e4SLinus Torvalds int err = 0; 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds NETLINK_CB(skb).dst_groups = group; 147*1da177e4SLinus Torvalds if (echo) 148*1da177e4SLinus Torvalds atomic_inc(&skb->users); 149*1da177e4SLinus Torvalds netlink_broadcast(rtnl, skb, pid, group, GFP_KERNEL); 150*1da177e4SLinus Torvalds if (echo) 151*1da177e4SLinus Torvalds err = netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); 152*1da177e4SLinus Torvalds return err; 153*1da177e4SLinus Torvalds } 154*1da177e4SLinus Torvalds 155*1da177e4SLinus Torvalds int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics) 156*1da177e4SLinus Torvalds { 157*1da177e4SLinus Torvalds struct rtattr *mx = (struct rtattr*)skb->tail; 158*1da177e4SLinus Torvalds int i; 159*1da177e4SLinus Torvalds 160*1da177e4SLinus Torvalds RTA_PUT(skb, RTA_METRICS, 0, NULL); 161*1da177e4SLinus Torvalds for (i=0; i<RTAX_MAX; i++) { 162*1da177e4SLinus Torvalds if (metrics[i]) 163*1da177e4SLinus Torvalds RTA_PUT(skb, i+1, sizeof(u32), metrics+i); 164*1da177e4SLinus Torvalds } 165*1da177e4SLinus Torvalds mx->rta_len = skb->tail - (u8*)mx; 166*1da177e4SLinus Torvalds if (mx->rta_len == RTA_LENGTH(0)) 167*1da177e4SLinus Torvalds skb_trim(skb, (u8*)mx - skb->data); 168*1da177e4SLinus Torvalds return 0; 169*1da177e4SLinus Torvalds 170*1da177e4SLinus Torvalds rtattr_failure: 171*1da177e4SLinus Torvalds skb_trim(skb, (u8*)mx - skb->data); 172*1da177e4SLinus Torvalds return -1; 173*1da177e4SLinus Torvalds } 174*1da177e4SLinus Torvalds 175*1da177e4SLinus Torvalds 176*1da177e4SLinus Torvalds static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, 177*1da177e4SLinus Torvalds int type, u32 pid, u32 seq, u32 change) 178*1da177e4SLinus Torvalds { 179*1da177e4SLinus Torvalds struct ifinfomsg *r; 180*1da177e4SLinus Torvalds struct nlmsghdr *nlh; 181*1da177e4SLinus Torvalds unsigned char *b = skb->tail; 182*1da177e4SLinus Torvalds 183*1da177e4SLinus Torvalds nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*r)); 184*1da177e4SLinus Torvalds if (pid) nlh->nlmsg_flags |= NLM_F_MULTI; 185*1da177e4SLinus Torvalds r = NLMSG_DATA(nlh); 186*1da177e4SLinus Torvalds r->ifi_family = AF_UNSPEC; 187*1da177e4SLinus Torvalds r->ifi_type = dev->type; 188*1da177e4SLinus Torvalds r->ifi_index = dev->ifindex; 189*1da177e4SLinus Torvalds r->ifi_flags = dev_get_flags(dev); 190*1da177e4SLinus Torvalds r->ifi_change = change; 191*1da177e4SLinus Torvalds 192*1da177e4SLinus Torvalds RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name); 193*1da177e4SLinus Torvalds 194*1da177e4SLinus Torvalds if (1) { 195*1da177e4SLinus Torvalds u32 txqlen = dev->tx_queue_len; 196*1da177e4SLinus Torvalds RTA_PUT(skb, IFLA_TXQLEN, sizeof(txqlen), &txqlen); 197*1da177e4SLinus Torvalds } 198*1da177e4SLinus Torvalds 199*1da177e4SLinus Torvalds if (1) { 200*1da177e4SLinus Torvalds u32 weight = dev->weight; 201*1da177e4SLinus Torvalds RTA_PUT(skb, IFLA_WEIGHT, sizeof(weight), &weight); 202*1da177e4SLinus Torvalds } 203*1da177e4SLinus Torvalds 204*1da177e4SLinus Torvalds if (1) { 205*1da177e4SLinus Torvalds struct rtnl_link_ifmap map = { 206*1da177e4SLinus Torvalds .mem_start = dev->mem_start, 207*1da177e4SLinus Torvalds .mem_end = dev->mem_end, 208*1da177e4SLinus Torvalds .base_addr = dev->base_addr, 209*1da177e4SLinus Torvalds .irq = dev->irq, 210*1da177e4SLinus Torvalds .dma = dev->dma, 211*1da177e4SLinus Torvalds .port = dev->if_port, 212*1da177e4SLinus Torvalds }; 213*1da177e4SLinus Torvalds RTA_PUT(skb, IFLA_MAP, sizeof(map), &map); 214*1da177e4SLinus Torvalds } 215*1da177e4SLinus Torvalds 216*1da177e4SLinus Torvalds if (dev->addr_len) { 217*1da177e4SLinus Torvalds RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); 218*1da177e4SLinus Torvalds RTA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast); 219*1da177e4SLinus Torvalds } 220*1da177e4SLinus Torvalds 221*1da177e4SLinus Torvalds if (1) { 222*1da177e4SLinus Torvalds u32 mtu = dev->mtu; 223*1da177e4SLinus Torvalds RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu); 224*1da177e4SLinus Torvalds } 225*1da177e4SLinus Torvalds 226*1da177e4SLinus Torvalds if (dev->ifindex != dev->iflink) { 227*1da177e4SLinus Torvalds u32 iflink = dev->iflink; 228*1da177e4SLinus Torvalds RTA_PUT(skb, IFLA_LINK, sizeof(iflink), &iflink); 229*1da177e4SLinus Torvalds } 230*1da177e4SLinus Torvalds 231*1da177e4SLinus Torvalds if (dev->qdisc_sleeping) 232*1da177e4SLinus Torvalds RTA_PUT(skb, IFLA_QDISC, 233*1da177e4SLinus Torvalds strlen(dev->qdisc_sleeping->ops->id) + 1, 234*1da177e4SLinus Torvalds dev->qdisc_sleeping->ops->id); 235*1da177e4SLinus Torvalds 236*1da177e4SLinus Torvalds if (dev->master) { 237*1da177e4SLinus Torvalds u32 master = dev->master->ifindex; 238*1da177e4SLinus Torvalds RTA_PUT(skb, IFLA_MASTER, sizeof(master), &master); 239*1da177e4SLinus Torvalds } 240*1da177e4SLinus Torvalds 241*1da177e4SLinus Torvalds if (dev->get_stats) { 242*1da177e4SLinus Torvalds unsigned long *stats = (unsigned long*)dev->get_stats(dev); 243*1da177e4SLinus Torvalds if (stats) { 244*1da177e4SLinus Torvalds struct rtattr *a; 245*1da177e4SLinus Torvalds __u32 *s; 246*1da177e4SLinus Torvalds int i; 247*1da177e4SLinus Torvalds int n = sizeof(struct rtnl_link_stats)/4; 248*1da177e4SLinus Torvalds 249*1da177e4SLinus Torvalds a = __RTA_PUT(skb, IFLA_STATS, n*4); 250*1da177e4SLinus Torvalds s = RTA_DATA(a); 251*1da177e4SLinus Torvalds for (i=0; i<n; i++) 252*1da177e4SLinus Torvalds s[i] = stats[i]; 253*1da177e4SLinus Torvalds } 254*1da177e4SLinus Torvalds } 255*1da177e4SLinus Torvalds nlh->nlmsg_len = skb->tail - b; 256*1da177e4SLinus Torvalds return skb->len; 257*1da177e4SLinus Torvalds 258*1da177e4SLinus Torvalds nlmsg_failure: 259*1da177e4SLinus Torvalds rtattr_failure: 260*1da177e4SLinus Torvalds skb_trim(skb, b - skb->data); 261*1da177e4SLinus Torvalds return -1; 262*1da177e4SLinus Torvalds } 263*1da177e4SLinus Torvalds 264*1da177e4SLinus Torvalds static int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) 265*1da177e4SLinus Torvalds { 266*1da177e4SLinus Torvalds int idx; 267*1da177e4SLinus Torvalds int s_idx = cb->args[0]; 268*1da177e4SLinus Torvalds struct net_device *dev; 269*1da177e4SLinus Torvalds 270*1da177e4SLinus Torvalds read_lock(&dev_base_lock); 271*1da177e4SLinus Torvalds for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { 272*1da177e4SLinus Torvalds if (idx < s_idx) 273*1da177e4SLinus Torvalds continue; 274*1da177e4SLinus Torvalds if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 0) <= 0) 275*1da177e4SLinus Torvalds break; 276*1da177e4SLinus Torvalds } 277*1da177e4SLinus Torvalds read_unlock(&dev_base_lock); 278*1da177e4SLinus Torvalds cb->args[0] = idx; 279*1da177e4SLinus Torvalds 280*1da177e4SLinus Torvalds return skb->len; 281*1da177e4SLinus Torvalds } 282*1da177e4SLinus Torvalds 283*1da177e4SLinus Torvalds static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 284*1da177e4SLinus Torvalds { 285*1da177e4SLinus Torvalds struct ifinfomsg *ifm = NLMSG_DATA(nlh); 286*1da177e4SLinus Torvalds struct rtattr **ida = arg; 287*1da177e4SLinus Torvalds struct net_device *dev; 288*1da177e4SLinus Torvalds int err, send_addr_notify = 0; 289*1da177e4SLinus Torvalds 290*1da177e4SLinus Torvalds if (ifm->ifi_index >= 0) 291*1da177e4SLinus Torvalds dev = dev_get_by_index(ifm->ifi_index); 292*1da177e4SLinus Torvalds else if (ida[IFLA_IFNAME - 1]) { 293*1da177e4SLinus Torvalds char ifname[IFNAMSIZ]; 294*1da177e4SLinus Torvalds 295*1da177e4SLinus Torvalds if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1], 296*1da177e4SLinus Torvalds IFNAMSIZ) >= IFNAMSIZ) 297*1da177e4SLinus Torvalds return -EINVAL; 298*1da177e4SLinus Torvalds dev = dev_get_by_name(ifname); 299*1da177e4SLinus Torvalds } else 300*1da177e4SLinus Torvalds return -EINVAL; 301*1da177e4SLinus Torvalds 302*1da177e4SLinus Torvalds if (!dev) 303*1da177e4SLinus Torvalds return -ENODEV; 304*1da177e4SLinus Torvalds 305*1da177e4SLinus Torvalds err = -EINVAL; 306*1da177e4SLinus Torvalds 307*1da177e4SLinus Torvalds if (ifm->ifi_flags) 308*1da177e4SLinus Torvalds dev_change_flags(dev, ifm->ifi_flags); 309*1da177e4SLinus Torvalds 310*1da177e4SLinus Torvalds if (ida[IFLA_MAP - 1]) { 311*1da177e4SLinus Torvalds struct rtnl_link_ifmap *u_map; 312*1da177e4SLinus Torvalds struct ifmap k_map; 313*1da177e4SLinus Torvalds 314*1da177e4SLinus Torvalds if (!dev->set_config) { 315*1da177e4SLinus Torvalds err = -EOPNOTSUPP; 316*1da177e4SLinus Torvalds goto out; 317*1da177e4SLinus Torvalds } 318*1da177e4SLinus Torvalds 319*1da177e4SLinus Torvalds if (!netif_device_present(dev)) { 320*1da177e4SLinus Torvalds err = -ENODEV; 321*1da177e4SLinus Torvalds goto out; 322*1da177e4SLinus Torvalds } 323*1da177e4SLinus Torvalds 324*1da177e4SLinus Torvalds if (ida[IFLA_MAP - 1]->rta_len != RTA_LENGTH(sizeof(*u_map))) 325*1da177e4SLinus Torvalds goto out; 326*1da177e4SLinus Torvalds 327*1da177e4SLinus Torvalds u_map = RTA_DATA(ida[IFLA_MAP - 1]); 328*1da177e4SLinus Torvalds 329*1da177e4SLinus Torvalds k_map.mem_start = (unsigned long) u_map->mem_start; 330*1da177e4SLinus Torvalds k_map.mem_end = (unsigned long) u_map->mem_end; 331*1da177e4SLinus Torvalds k_map.base_addr = (unsigned short) u_map->base_addr; 332*1da177e4SLinus Torvalds k_map.irq = (unsigned char) u_map->irq; 333*1da177e4SLinus Torvalds k_map.dma = (unsigned char) u_map->dma; 334*1da177e4SLinus Torvalds k_map.port = (unsigned char) u_map->port; 335*1da177e4SLinus Torvalds 336*1da177e4SLinus Torvalds err = dev->set_config(dev, &k_map); 337*1da177e4SLinus Torvalds 338*1da177e4SLinus Torvalds if (err) 339*1da177e4SLinus Torvalds goto out; 340*1da177e4SLinus Torvalds } 341*1da177e4SLinus Torvalds 342*1da177e4SLinus Torvalds if (ida[IFLA_ADDRESS - 1]) { 343*1da177e4SLinus Torvalds if (!dev->set_mac_address) { 344*1da177e4SLinus Torvalds err = -EOPNOTSUPP; 345*1da177e4SLinus Torvalds goto out; 346*1da177e4SLinus Torvalds } 347*1da177e4SLinus Torvalds if (!netif_device_present(dev)) { 348*1da177e4SLinus Torvalds err = -ENODEV; 349*1da177e4SLinus Torvalds goto out; 350*1da177e4SLinus Torvalds } 351*1da177e4SLinus Torvalds if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len)) 352*1da177e4SLinus Torvalds goto out; 353*1da177e4SLinus Torvalds 354*1da177e4SLinus Torvalds err = dev->set_mac_address(dev, RTA_DATA(ida[IFLA_ADDRESS - 1])); 355*1da177e4SLinus Torvalds if (err) 356*1da177e4SLinus Torvalds goto out; 357*1da177e4SLinus Torvalds send_addr_notify = 1; 358*1da177e4SLinus Torvalds } 359*1da177e4SLinus Torvalds 360*1da177e4SLinus Torvalds if (ida[IFLA_BROADCAST - 1]) { 361*1da177e4SLinus Torvalds if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len)) 362*1da177e4SLinus Torvalds goto out; 363*1da177e4SLinus Torvalds memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]), 364*1da177e4SLinus Torvalds dev->addr_len); 365*1da177e4SLinus Torvalds send_addr_notify = 1; 366*1da177e4SLinus Torvalds } 367*1da177e4SLinus Torvalds 368*1da177e4SLinus Torvalds if (ida[IFLA_MTU - 1]) { 369*1da177e4SLinus Torvalds if (ida[IFLA_MTU - 1]->rta_len != RTA_LENGTH(sizeof(u32))) 370*1da177e4SLinus Torvalds goto out; 371*1da177e4SLinus Torvalds err = dev_set_mtu(dev, *((u32 *) RTA_DATA(ida[IFLA_MTU - 1]))); 372*1da177e4SLinus Torvalds 373*1da177e4SLinus Torvalds if (err) 374*1da177e4SLinus Torvalds goto out; 375*1da177e4SLinus Torvalds 376*1da177e4SLinus Torvalds } 377*1da177e4SLinus Torvalds 378*1da177e4SLinus Torvalds if (ida[IFLA_TXQLEN - 1]) { 379*1da177e4SLinus Torvalds if (ida[IFLA_TXQLEN - 1]->rta_len != RTA_LENGTH(sizeof(u32))) 380*1da177e4SLinus Torvalds goto out; 381*1da177e4SLinus Torvalds 382*1da177e4SLinus Torvalds dev->tx_queue_len = *((u32 *) RTA_DATA(ida[IFLA_TXQLEN - 1])); 383*1da177e4SLinus Torvalds } 384*1da177e4SLinus Torvalds 385*1da177e4SLinus Torvalds if (ida[IFLA_WEIGHT - 1]) { 386*1da177e4SLinus Torvalds if (ida[IFLA_WEIGHT - 1]->rta_len != RTA_LENGTH(sizeof(u32))) 387*1da177e4SLinus Torvalds goto out; 388*1da177e4SLinus Torvalds 389*1da177e4SLinus Torvalds dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1])); 390*1da177e4SLinus Torvalds } 391*1da177e4SLinus Torvalds 392*1da177e4SLinus Torvalds if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) { 393*1da177e4SLinus Torvalds char ifname[IFNAMSIZ]; 394*1da177e4SLinus Torvalds 395*1da177e4SLinus Torvalds if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1], 396*1da177e4SLinus Torvalds IFNAMSIZ) >= IFNAMSIZ) 397*1da177e4SLinus Torvalds goto out; 398*1da177e4SLinus Torvalds err = dev_change_name(dev, ifname); 399*1da177e4SLinus Torvalds if (err) 400*1da177e4SLinus Torvalds goto out; 401*1da177e4SLinus Torvalds } 402*1da177e4SLinus Torvalds 403*1da177e4SLinus Torvalds err = 0; 404*1da177e4SLinus Torvalds 405*1da177e4SLinus Torvalds out: 406*1da177e4SLinus Torvalds if (send_addr_notify) 407*1da177e4SLinus Torvalds call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); 408*1da177e4SLinus Torvalds 409*1da177e4SLinus Torvalds dev_put(dev); 410*1da177e4SLinus Torvalds return err; 411*1da177e4SLinus Torvalds } 412*1da177e4SLinus Torvalds 413*1da177e4SLinus Torvalds static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb) 414*1da177e4SLinus Torvalds { 415*1da177e4SLinus Torvalds int idx; 416*1da177e4SLinus Torvalds int s_idx = cb->family; 417*1da177e4SLinus Torvalds 418*1da177e4SLinus Torvalds if (s_idx == 0) 419*1da177e4SLinus Torvalds s_idx = 1; 420*1da177e4SLinus Torvalds for (idx=1; idx<NPROTO; idx++) { 421*1da177e4SLinus Torvalds int type = cb->nlh->nlmsg_type-RTM_BASE; 422*1da177e4SLinus Torvalds if (idx < s_idx || idx == PF_PACKET) 423*1da177e4SLinus Torvalds continue; 424*1da177e4SLinus Torvalds if (rtnetlink_links[idx] == NULL || 425*1da177e4SLinus Torvalds rtnetlink_links[idx][type].dumpit == NULL) 426*1da177e4SLinus Torvalds continue; 427*1da177e4SLinus Torvalds if (idx > s_idx) 428*1da177e4SLinus Torvalds memset(&cb->args[0], 0, sizeof(cb->args)); 429*1da177e4SLinus Torvalds if (rtnetlink_links[idx][type].dumpit(skb, cb)) 430*1da177e4SLinus Torvalds break; 431*1da177e4SLinus Torvalds } 432*1da177e4SLinus Torvalds cb->family = idx; 433*1da177e4SLinus Torvalds 434*1da177e4SLinus Torvalds return skb->len; 435*1da177e4SLinus Torvalds } 436*1da177e4SLinus Torvalds 437*1da177e4SLinus Torvalds void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) 438*1da177e4SLinus Torvalds { 439*1da177e4SLinus Torvalds struct sk_buff *skb; 440*1da177e4SLinus Torvalds int size = NLMSG_SPACE(sizeof(struct ifinfomsg) + 441*1da177e4SLinus Torvalds sizeof(struct rtnl_link_ifmap) + 442*1da177e4SLinus Torvalds sizeof(struct rtnl_link_stats) + 128); 443*1da177e4SLinus Torvalds 444*1da177e4SLinus Torvalds skb = alloc_skb(size, GFP_KERNEL); 445*1da177e4SLinus Torvalds if (!skb) 446*1da177e4SLinus Torvalds return; 447*1da177e4SLinus Torvalds 448*1da177e4SLinus Torvalds if (rtnetlink_fill_ifinfo(skb, dev, type, 0, 0, change) < 0) { 449*1da177e4SLinus Torvalds kfree_skb(skb); 450*1da177e4SLinus Torvalds return; 451*1da177e4SLinus Torvalds } 452*1da177e4SLinus Torvalds NETLINK_CB(skb).dst_groups = RTMGRP_LINK; 453*1da177e4SLinus Torvalds netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_KERNEL); 454*1da177e4SLinus Torvalds } 455*1da177e4SLinus Torvalds 456*1da177e4SLinus Torvalds static int rtnetlink_done(struct netlink_callback *cb) 457*1da177e4SLinus Torvalds { 458*1da177e4SLinus Torvalds return 0; 459*1da177e4SLinus Torvalds } 460*1da177e4SLinus Torvalds 461*1da177e4SLinus Torvalds /* Protected by RTNL sempahore. */ 462*1da177e4SLinus Torvalds static struct rtattr **rta_buf; 463*1da177e4SLinus Torvalds static int rtattr_max; 464*1da177e4SLinus Torvalds 465*1da177e4SLinus Torvalds /* Process one rtnetlink message. */ 466*1da177e4SLinus Torvalds 467*1da177e4SLinus Torvalds static __inline__ int 468*1da177e4SLinus Torvalds rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) 469*1da177e4SLinus Torvalds { 470*1da177e4SLinus Torvalds struct rtnetlink_link *link; 471*1da177e4SLinus Torvalds struct rtnetlink_link *link_tab; 472*1da177e4SLinus Torvalds int sz_idx, kind; 473*1da177e4SLinus Torvalds int min_len; 474*1da177e4SLinus Torvalds int family; 475*1da177e4SLinus Torvalds int type; 476*1da177e4SLinus Torvalds int err; 477*1da177e4SLinus Torvalds 478*1da177e4SLinus Torvalds /* Only requests are handled by kernel now */ 479*1da177e4SLinus Torvalds if (!(nlh->nlmsg_flags&NLM_F_REQUEST)) 480*1da177e4SLinus Torvalds return 0; 481*1da177e4SLinus Torvalds 482*1da177e4SLinus Torvalds type = nlh->nlmsg_type; 483*1da177e4SLinus Torvalds 484*1da177e4SLinus Torvalds /* A control message: ignore them */ 485*1da177e4SLinus Torvalds if (type < RTM_BASE) 486*1da177e4SLinus Torvalds return 0; 487*1da177e4SLinus Torvalds 488*1da177e4SLinus Torvalds /* Unknown message: reply with EINVAL */ 489*1da177e4SLinus Torvalds if (type > RTM_MAX) 490*1da177e4SLinus Torvalds goto err_inval; 491*1da177e4SLinus Torvalds 492*1da177e4SLinus Torvalds type -= RTM_BASE; 493*1da177e4SLinus Torvalds 494*1da177e4SLinus Torvalds /* All the messages must have at least 1 byte length */ 495*1da177e4SLinus Torvalds if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg))) 496*1da177e4SLinus Torvalds return 0; 497*1da177e4SLinus Torvalds 498*1da177e4SLinus Torvalds family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family; 499*1da177e4SLinus Torvalds if (family >= NPROTO) { 500*1da177e4SLinus Torvalds *errp = -EAFNOSUPPORT; 501*1da177e4SLinus Torvalds return -1; 502*1da177e4SLinus Torvalds } 503*1da177e4SLinus Torvalds 504*1da177e4SLinus Torvalds link_tab = rtnetlink_links[family]; 505*1da177e4SLinus Torvalds if (link_tab == NULL) 506*1da177e4SLinus Torvalds link_tab = rtnetlink_links[PF_UNSPEC]; 507*1da177e4SLinus Torvalds link = &link_tab[type]; 508*1da177e4SLinus Torvalds 509*1da177e4SLinus Torvalds sz_idx = type>>2; 510*1da177e4SLinus Torvalds kind = type&3; 511*1da177e4SLinus Torvalds 512*1da177e4SLinus Torvalds if (kind != 2 && security_netlink_recv(skb)) { 513*1da177e4SLinus Torvalds *errp = -EPERM; 514*1da177e4SLinus Torvalds return -1; 515*1da177e4SLinus Torvalds } 516*1da177e4SLinus Torvalds 517*1da177e4SLinus Torvalds if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { 518*1da177e4SLinus Torvalds u32 rlen; 519*1da177e4SLinus Torvalds 520*1da177e4SLinus Torvalds if (link->dumpit == NULL) 521*1da177e4SLinus Torvalds link = &(rtnetlink_links[PF_UNSPEC][type]); 522*1da177e4SLinus Torvalds 523*1da177e4SLinus Torvalds if (link->dumpit == NULL) 524*1da177e4SLinus Torvalds goto err_inval; 525*1da177e4SLinus Torvalds 526*1da177e4SLinus Torvalds if ((*errp = netlink_dump_start(rtnl, skb, nlh, 527*1da177e4SLinus Torvalds link->dumpit, 528*1da177e4SLinus Torvalds rtnetlink_done)) != 0) { 529*1da177e4SLinus Torvalds return -1; 530*1da177e4SLinus Torvalds } 531*1da177e4SLinus Torvalds rlen = NLMSG_ALIGN(nlh->nlmsg_len); 532*1da177e4SLinus Torvalds if (rlen > skb->len) 533*1da177e4SLinus Torvalds rlen = skb->len; 534*1da177e4SLinus Torvalds skb_pull(skb, rlen); 535*1da177e4SLinus Torvalds return -1; 536*1da177e4SLinus Torvalds } 537*1da177e4SLinus Torvalds 538*1da177e4SLinus Torvalds memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); 539*1da177e4SLinus Torvalds 540*1da177e4SLinus Torvalds min_len = rtm_min[sz_idx]; 541*1da177e4SLinus Torvalds if (nlh->nlmsg_len < min_len) 542*1da177e4SLinus Torvalds goto err_inval; 543*1da177e4SLinus Torvalds 544*1da177e4SLinus Torvalds if (nlh->nlmsg_len > min_len) { 545*1da177e4SLinus Torvalds int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); 546*1da177e4SLinus Torvalds struct rtattr *attr = (void*)nlh + NLMSG_ALIGN(min_len); 547*1da177e4SLinus Torvalds 548*1da177e4SLinus Torvalds while (RTA_OK(attr, attrlen)) { 549*1da177e4SLinus Torvalds unsigned flavor = attr->rta_type; 550*1da177e4SLinus Torvalds if (flavor) { 551*1da177e4SLinus Torvalds if (flavor > rta_max[sz_idx]) 552*1da177e4SLinus Torvalds goto err_inval; 553*1da177e4SLinus Torvalds rta_buf[flavor-1] = attr; 554*1da177e4SLinus Torvalds } 555*1da177e4SLinus Torvalds attr = RTA_NEXT(attr, attrlen); 556*1da177e4SLinus Torvalds } 557*1da177e4SLinus Torvalds } 558*1da177e4SLinus Torvalds 559*1da177e4SLinus Torvalds if (link->doit == NULL) 560*1da177e4SLinus Torvalds link = &(rtnetlink_links[PF_UNSPEC][type]); 561*1da177e4SLinus Torvalds if (link->doit == NULL) 562*1da177e4SLinus Torvalds goto err_inval; 563*1da177e4SLinus Torvalds err = link->doit(skb, nlh, (void *)&rta_buf[0]); 564*1da177e4SLinus Torvalds 565*1da177e4SLinus Torvalds *errp = err; 566*1da177e4SLinus Torvalds return err; 567*1da177e4SLinus Torvalds 568*1da177e4SLinus Torvalds err_inval: 569*1da177e4SLinus Torvalds *errp = -EINVAL; 570*1da177e4SLinus Torvalds return -1; 571*1da177e4SLinus Torvalds } 572*1da177e4SLinus Torvalds 573*1da177e4SLinus Torvalds /* 574*1da177e4SLinus Torvalds * Process one packet of messages. 575*1da177e4SLinus Torvalds * Malformed skbs with wrong lengths of messages are discarded silently. 576*1da177e4SLinus Torvalds */ 577*1da177e4SLinus Torvalds 578*1da177e4SLinus Torvalds static inline int rtnetlink_rcv_skb(struct sk_buff *skb) 579*1da177e4SLinus Torvalds { 580*1da177e4SLinus Torvalds int err; 581*1da177e4SLinus Torvalds struct nlmsghdr * nlh; 582*1da177e4SLinus Torvalds 583*1da177e4SLinus Torvalds while (skb->len >= NLMSG_SPACE(0)) { 584*1da177e4SLinus Torvalds u32 rlen; 585*1da177e4SLinus Torvalds 586*1da177e4SLinus Torvalds nlh = (struct nlmsghdr *)skb->data; 587*1da177e4SLinus Torvalds if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) 588*1da177e4SLinus Torvalds return 0; 589*1da177e4SLinus Torvalds rlen = NLMSG_ALIGN(nlh->nlmsg_len); 590*1da177e4SLinus Torvalds if (rlen > skb->len) 591*1da177e4SLinus Torvalds rlen = skb->len; 592*1da177e4SLinus Torvalds if (rtnetlink_rcv_msg(skb, nlh, &err)) { 593*1da177e4SLinus Torvalds /* Not error, but we must interrupt processing here: 594*1da177e4SLinus Torvalds * Note, that in this case we do not pull message 595*1da177e4SLinus Torvalds * from skb, it will be processed later. 596*1da177e4SLinus Torvalds */ 597*1da177e4SLinus Torvalds if (err == 0) 598*1da177e4SLinus Torvalds return -1; 599*1da177e4SLinus Torvalds netlink_ack(skb, nlh, err); 600*1da177e4SLinus Torvalds } else if (nlh->nlmsg_flags&NLM_F_ACK) 601*1da177e4SLinus Torvalds netlink_ack(skb, nlh, 0); 602*1da177e4SLinus Torvalds skb_pull(skb, rlen); 603*1da177e4SLinus Torvalds } 604*1da177e4SLinus Torvalds 605*1da177e4SLinus Torvalds return 0; 606*1da177e4SLinus Torvalds } 607*1da177e4SLinus Torvalds 608*1da177e4SLinus Torvalds /* 609*1da177e4SLinus Torvalds * rtnetlink input queue processing routine: 610*1da177e4SLinus Torvalds * - try to acquire shared lock. If it is failed, defer processing. 611*1da177e4SLinus Torvalds * - feed skbs to rtnetlink_rcv_skb, until it refuse a message, 612*1da177e4SLinus Torvalds * that will occur, when a dump started and/or acquisition of 613*1da177e4SLinus Torvalds * exclusive lock failed. 614*1da177e4SLinus Torvalds */ 615*1da177e4SLinus Torvalds 616*1da177e4SLinus Torvalds static void rtnetlink_rcv(struct sock *sk, int len) 617*1da177e4SLinus Torvalds { 618*1da177e4SLinus Torvalds do { 619*1da177e4SLinus Torvalds struct sk_buff *skb; 620*1da177e4SLinus Torvalds 621*1da177e4SLinus Torvalds if (rtnl_shlock_nowait()) 622*1da177e4SLinus Torvalds return; 623*1da177e4SLinus Torvalds 624*1da177e4SLinus Torvalds while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 625*1da177e4SLinus Torvalds if (rtnetlink_rcv_skb(skb)) { 626*1da177e4SLinus Torvalds if (skb->len) 627*1da177e4SLinus Torvalds skb_queue_head(&sk->sk_receive_queue, 628*1da177e4SLinus Torvalds skb); 629*1da177e4SLinus Torvalds else 630*1da177e4SLinus Torvalds kfree_skb(skb); 631*1da177e4SLinus Torvalds break; 632*1da177e4SLinus Torvalds } 633*1da177e4SLinus Torvalds kfree_skb(skb); 634*1da177e4SLinus Torvalds } 635*1da177e4SLinus Torvalds 636*1da177e4SLinus Torvalds up(&rtnl_sem); 637*1da177e4SLinus Torvalds 638*1da177e4SLinus Torvalds netdev_run_todo(); 639*1da177e4SLinus Torvalds } while (rtnl && rtnl->sk_receive_queue.qlen); 640*1da177e4SLinus Torvalds } 641*1da177e4SLinus Torvalds 642*1da177e4SLinus Torvalds static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] = 643*1da177e4SLinus Torvalds { 644*1da177e4SLinus Torvalds [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, 645*1da177e4SLinus Torvalds [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, 646*1da177e4SLinus Torvalds [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 647*1da177e4SLinus Torvalds [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 648*1da177e4SLinus Torvalds [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, 649*1da177e4SLinus Torvalds [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete }, 650*1da177e4SLinus Torvalds [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info } 651*1da177e4SLinus Torvalds }; 652*1da177e4SLinus Torvalds 653*1da177e4SLinus Torvalds static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) 654*1da177e4SLinus Torvalds { 655*1da177e4SLinus Torvalds struct net_device *dev = ptr; 656*1da177e4SLinus Torvalds switch (event) { 657*1da177e4SLinus Torvalds case NETDEV_UNREGISTER: 658*1da177e4SLinus Torvalds rtmsg_ifinfo(RTM_DELLINK, dev, ~0U); 659*1da177e4SLinus Torvalds break; 660*1da177e4SLinus Torvalds case NETDEV_REGISTER: 661*1da177e4SLinus Torvalds rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); 662*1da177e4SLinus Torvalds break; 663*1da177e4SLinus Torvalds case NETDEV_UP: 664*1da177e4SLinus Torvalds case NETDEV_DOWN: 665*1da177e4SLinus Torvalds rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING); 666*1da177e4SLinus Torvalds break; 667*1da177e4SLinus Torvalds case NETDEV_CHANGE: 668*1da177e4SLinus Torvalds case NETDEV_GOING_DOWN: 669*1da177e4SLinus Torvalds break; 670*1da177e4SLinus Torvalds default: 671*1da177e4SLinus Torvalds rtmsg_ifinfo(RTM_NEWLINK, dev, 0); 672*1da177e4SLinus Torvalds break; 673*1da177e4SLinus Torvalds } 674*1da177e4SLinus Torvalds return NOTIFY_DONE; 675*1da177e4SLinus Torvalds } 676*1da177e4SLinus Torvalds 677*1da177e4SLinus Torvalds static struct notifier_block rtnetlink_dev_notifier = { 678*1da177e4SLinus Torvalds .notifier_call = rtnetlink_event, 679*1da177e4SLinus Torvalds }; 680*1da177e4SLinus Torvalds 681*1da177e4SLinus Torvalds void __init rtnetlink_init(void) 682*1da177e4SLinus Torvalds { 683*1da177e4SLinus Torvalds int i; 684*1da177e4SLinus Torvalds 685*1da177e4SLinus Torvalds rtattr_max = 0; 686*1da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(rta_max); i++) 687*1da177e4SLinus Torvalds if (rta_max[i] > rtattr_max) 688*1da177e4SLinus Torvalds rtattr_max = rta_max[i]; 689*1da177e4SLinus Torvalds rta_buf = kmalloc(rtattr_max * sizeof(struct rtattr *), GFP_KERNEL); 690*1da177e4SLinus Torvalds if (!rta_buf) 691*1da177e4SLinus Torvalds panic("rtnetlink_init: cannot allocate rta_buf\n"); 692*1da177e4SLinus Torvalds 693*1da177e4SLinus Torvalds rtnl = netlink_kernel_create(NETLINK_ROUTE, rtnetlink_rcv); 694*1da177e4SLinus Torvalds if (rtnl == NULL) 695*1da177e4SLinus Torvalds panic("rtnetlink_init: cannot initialize rtnetlink\n"); 696*1da177e4SLinus Torvalds netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); 697*1da177e4SLinus Torvalds register_netdevice_notifier(&rtnetlink_dev_notifier); 698*1da177e4SLinus Torvalds rtnetlink_links[PF_UNSPEC] = link_rtnetlink_table; 699*1da177e4SLinus Torvalds rtnetlink_links[PF_PACKET] = link_rtnetlink_table; 700*1da177e4SLinus Torvalds } 701*1da177e4SLinus Torvalds 702*1da177e4SLinus Torvalds EXPORT_SYMBOL(__rta_fill); 703*1da177e4SLinus Torvalds EXPORT_SYMBOL(rtattr_strlcpy); 704*1da177e4SLinus Torvalds EXPORT_SYMBOL(rtattr_parse); 705*1da177e4SLinus Torvalds EXPORT_SYMBOL(rtnetlink_links); 706*1da177e4SLinus Torvalds EXPORT_SYMBOL(rtnetlink_put_metrics); 707*1da177e4SLinus Torvalds EXPORT_SYMBOL(rtnl); 708*1da177e4SLinus Torvalds EXPORT_SYMBOL(rtnl_lock); 709*1da177e4SLinus Torvalds EXPORT_SYMBOL(rtnl_lock_interruptible); 710*1da177e4SLinus Torvalds EXPORT_SYMBOL(rtnl_sem); 711*1da177e4SLinus Torvalds EXPORT_SYMBOL(rtnl_unlock); 712