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.c191
1 files changed, 100 insertions, 91 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 35712031e2c3..2adc966d981e 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -336,52 +336,69 @@ static int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *c
336 return skb->len; 336 return skb->len;
337} 337}
338 338
339static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 339static struct nla_policy ifla_policy[IFLA_MAX+1] __read_mostly = {
340 [IFLA_IFNAME] = { .type = NLA_STRING },
341 [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
342 [IFLA_MTU] = { .type = NLA_U32 },
343 [IFLA_TXQLEN] = { .type = NLA_U32 },
344 [IFLA_WEIGHT] = { .type = NLA_U32 },
345 [IFLA_OPERSTATE] = { .type = NLA_U8 },
346 [IFLA_LINKMODE] = { .type = NLA_U8 },
347};
348
349static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
340{ 350{
341 struct ifinfomsg *ifm = NLMSG_DATA(nlh); 351 struct ifinfomsg *ifm;
342 struct rtattr **ida = arg;
343 struct net_device *dev; 352 struct net_device *dev;
344 int err, send_addr_notify = 0; 353 int err, send_addr_notify = 0, modified = 0;
354 struct nlattr *tb[IFLA_MAX+1];
355 char ifname[IFNAMSIZ];
345 356
357 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
358 if (err < 0)
359 goto errout;
360
361 if (tb[IFLA_IFNAME] &&
362 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ) >= IFNAMSIZ)
363 return -EINVAL;
364
365 err = -EINVAL;
366 ifm = nlmsg_data(nlh);
346 if (ifm->ifi_index >= 0) 367 if (ifm->ifi_index >= 0)
347 dev = dev_get_by_index(ifm->ifi_index); 368 dev = dev_get_by_index(ifm->ifi_index);
348 else if (ida[IFLA_IFNAME - 1]) { 369 else if (tb[IFLA_IFNAME])
349 char ifname[IFNAMSIZ];
350
351 if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
352 IFNAMSIZ) >= IFNAMSIZ)
353 return -EINVAL;
354 dev = dev_get_by_name(ifname); 370 dev = dev_get_by_name(ifname);
355 } else 371 else
356 return -EINVAL; 372 goto errout;
357 373
358 if (!dev) 374 if (dev == NULL) {
359 return -ENODEV; 375 err = -ENODEV;
376 goto errout;
377 }
360 378
361 err = -EINVAL; 379 if (tb[IFLA_ADDRESS] &&
380 nla_len(tb[IFLA_ADDRESS]) < dev->addr_len)
381 goto errout_dev;
362 382
363 if (ifm->ifi_flags) 383 if (tb[IFLA_BROADCAST] &&
364 dev_change_flags(dev, ifm->ifi_flags); 384 nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
385 goto errout_dev;
365 386
366 if (ida[IFLA_MAP - 1]) { 387 if (tb[IFLA_MAP]) {
367 struct rtnl_link_ifmap *u_map; 388 struct rtnl_link_ifmap *u_map;
368 struct ifmap k_map; 389 struct ifmap k_map;
369 390
370 if (!dev->set_config) { 391 if (!dev->set_config) {
371 err = -EOPNOTSUPP; 392 err = -EOPNOTSUPP;
372 goto out; 393 goto errout_dev;
373 } 394 }
374 395
375 if (!netif_device_present(dev)) { 396 if (!netif_device_present(dev)) {
376 err = -ENODEV; 397 err = -ENODEV;
377 goto out; 398 goto errout_dev;
378 } 399 }
379
380 if (ida[IFLA_MAP - 1]->rta_len != RTA_LENGTH(sizeof(*u_map)))
381 goto out;
382
383 u_map = RTA_DATA(ida[IFLA_MAP - 1]);
384 400
401 u_map = nla_data(tb[IFLA_MAP]);
385 k_map.mem_start = (unsigned long) u_map->mem_start; 402 k_map.mem_start = (unsigned long) u_map->mem_start;
386 k_map.mem_end = (unsigned long) u_map->mem_end; 403 k_map.mem_end = (unsigned long) u_map->mem_end;
387 k_map.base_addr = (unsigned short) u_map->base_addr; 404 k_map.base_addr = (unsigned short) u_map->base_addr;
@@ -390,119 +407,111 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
390 k_map.port = (unsigned char) u_map->port; 407 k_map.port = (unsigned char) u_map->port;
391 408
392 err = dev->set_config(dev, &k_map); 409 err = dev->set_config(dev, &k_map);
410 if (err < 0)
411 goto errout_dev;
393 412
394 if (err) 413 modified = 1;
395 goto out;
396 } 414 }
397 415
398 if (ida[IFLA_ADDRESS - 1]) { 416 if (tb[IFLA_ADDRESS]) {
399 struct sockaddr *sa; 417 struct sockaddr *sa;
400 int len; 418 int len;
401 419
402 if (!dev->set_mac_address) { 420 if (!dev->set_mac_address) {
403 err = -EOPNOTSUPP; 421 err = -EOPNOTSUPP;
404 goto out; 422 goto errout_dev;
405 } 423 }
424
406 if (!netif_device_present(dev)) { 425 if (!netif_device_present(dev)) {
407 err = -ENODEV; 426 err = -ENODEV;
408 goto out; 427 goto errout_dev;
409 } 428 }
410 if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len))
411 goto out;
412 429
413 len = sizeof(sa_family_t) + dev->addr_len; 430 len = sizeof(sa_family_t) + dev->addr_len;
414 sa = kmalloc(len, GFP_KERNEL); 431 sa = kmalloc(len, GFP_KERNEL);
415 if (!sa) { 432 if (!sa) {
416 err = -ENOMEM; 433 err = -ENOMEM;
417 goto out; 434 goto errout_dev;
418 } 435 }
419 sa->sa_family = dev->type; 436 sa->sa_family = dev->type;
420 memcpy(sa->sa_data, RTA_DATA(ida[IFLA_ADDRESS - 1]), 437 memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
421 dev->addr_len); 438 dev->addr_len);
422 err = dev->set_mac_address(dev, sa); 439 err = dev->set_mac_address(dev, sa);
423 kfree(sa); 440 kfree(sa);
424 if (err) 441 if (err)
425 goto out; 442 goto errout_dev;
426 send_addr_notify = 1; 443 send_addr_notify = 1;
444 modified = 1;
427 } 445 }
428 446
429 if (ida[IFLA_BROADCAST - 1]) { 447 if (tb[IFLA_MTU]) {
430 if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len)) 448 err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
431 goto out; 449 if (err < 0)
432 memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]), 450 goto errout_dev;
433 dev->addr_len); 451 modified = 1;
434 send_addr_notify = 1;
435 } 452 }
436 453
437 if (ida[IFLA_MTU - 1]) { 454 /*
438 if (ida[IFLA_MTU - 1]->rta_len != RTA_LENGTH(sizeof(u32))) 455 * Interface selected by interface index but interface
439 goto out; 456 * name provided implies that a name change has been
440 err = dev_set_mtu(dev, *((u32 *) RTA_DATA(ida[IFLA_MTU - 1]))); 457 * requested.
441 458 */
442 if (err) 459 if (ifm->ifi_index >= 0 && ifname[0]) {
443 goto out; 460 err = dev_change_name(dev, ifname);
444 461 if (err < 0)
462 goto errout_dev;
463 modified = 1;
445 } 464 }
446 465
447 if (ida[IFLA_TXQLEN - 1]) { 466#ifdef CONFIG_NET_WIRELESS_RTNETLINK
448 if (ida[IFLA_TXQLEN - 1]->rta_len != RTA_LENGTH(sizeof(u32))) 467 if (tb[IFLA_WIRELESS]) {
449 goto out; 468 /* Call Wireless Extensions.
469 * Various stuff checked in there... */
470 err = wireless_rtnetlink_set(dev, nla_data(tb[IFLA_WIRELESS]),
471 nla_len(tb[IFLA_WIRELESS]));
472 if (err < 0)
473 goto errout_dev;
474 }
475#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
450 476
451 dev->tx_queue_len = *((u32 *) RTA_DATA(ida[IFLA_TXQLEN - 1])); 477 if (tb[IFLA_BROADCAST]) {
478 nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len);
479 send_addr_notify = 1;
452 } 480 }
453 481
454 if (ida[IFLA_WEIGHT - 1]) {
455 if (ida[IFLA_WEIGHT - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
456 goto out;
457 482
458 dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1])); 483 if (ifm->ifi_flags)
459 } 484 dev_change_flags(dev, ifm->ifi_flags);
460 485
461 if (ida[IFLA_OPERSTATE - 1]) { 486 if (tb[IFLA_TXQLEN])
462 if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8))) 487 dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
463 goto out;
464 488
465 set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1]))); 489 if (tb[IFLA_WEIGHT])
466 } 490 dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);
467 491
468 if (ida[IFLA_LINKMODE - 1]) { 492 if (tb[IFLA_OPERSTATE])
469 if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8))) 493 set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
470 goto out;
471 494
495 if (tb[IFLA_LINKMODE]) {
472 write_lock_bh(&dev_base_lock); 496 write_lock_bh(&dev_base_lock);
473 dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1])); 497 dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
474 write_unlock_bh(&dev_base_lock); 498 write_unlock_bh(&dev_base_lock);
475 } 499 }
476 500
477 if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
478 char ifname[IFNAMSIZ];
479
480 if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
481 IFNAMSIZ) >= IFNAMSIZ)
482 goto out;
483 err = dev_change_name(dev, ifname);
484 if (err)
485 goto out;
486 }
487
488#ifdef CONFIG_NET_WIRELESS_RTNETLINK
489 if (ida[IFLA_WIRELESS - 1]) {
490
491 /* Call Wireless Extensions.
492 * Various stuff checked in there... */
493 err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len);
494 if (err)
495 goto out;
496 }
497#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
498
499 err = 0; 501 err = 0;
500 502
501out: 503errout_dev:
504 if (err < 0 && modified && net_ratelimit())
505 printk(KERN_WARNING "A link change request failed with "
506 "some changes comitted already. Interface %s may "
507 "have been left with an inconsistent configuration, "
508 "please check.\n", dev->name);
509
502 if (send_addr_notify) 510 if (send_addr_notify)
503 call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); 511 call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
504 512
505 dev_put(dev); 513 dev_put(dev);
514errout:
506 return err; 515 return err;
507} 516}
508 517
@@ -753,7 +762,7 @@ static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
753 .doit = do_getlink, 762 .doit = do_getlink,
754#endif /* CONFIG_NET_WIRELESS_RTNETLINK */ 763#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
755 .dumpit = rtnetlink_dump_ifinfo }, 764 .dumpit = rtnetlink_dump_ifinfo },
756 [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, 765 [RTM_SETLINK - RTM_BASE] = { .doit = rtnl_setlink },
757 [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 766 [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
758 [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 767 [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
759 [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, 768 [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add },