aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2006-08-11 00:17:37 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 17:53:48 -0400
commitda5e0494c542dddc56a1f1edfd30310ea30f41ff (patch)
tree7b1a0d32607fa184f6b5a807cd877e9fe31a2bef /net/core
parent1823730fbc89fadde72a7bb3b7bdf03cc7b8835c (diff)
[NET]: Convert link modification to new netlink api
Transforms do_setlink() into rtnl_setlink() using the new netlink api. A warning message printed to the console is added in the event that a change request fails while part of the change request has been comitted already. The ioctl() based nature of net devices makes it almost impossible to move on to atomic netlink operations without obsoleting some of the functionality. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-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 },