diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 190 |
1 files changed, 88 insertions, 102 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index b312a5f7a759..a5e8d207a51b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -232,7 +232,7 @@ static inline unsigned ipv6_addr_scope2type(unsigned scope) | |||
232 | 232 | ||
233 | int __ipv6_addr_type(const struct in6_addr *addr) | 233 | int __ipv6_addr_type(const struct in6_addr *addr) |
234 | { | 234 | { |
235 | u32 st; | 235 | __be32 st; |
236 | 236 | ||
237 | st = addr->s6_addr32[0]; | 237 | st = addr->s6_addr32[0]; |
238 | 238 | ||
@@ -1164,7 +1164,7 @@ record_it: | |||
1164 | int ipv6_get_saddr(struct dst_entry *dst, | 1164 | int ipv6_get_saddr(struct dst_entry *dst, |
1165 | struct in6_addr *daddr, struct in6_addr *saddr) | 1165 | struct in6_addr *daddr, struct in6_addr *saddr) |
1166 | { | 1166 | { |
1167 | return ipv6_dev_get_saddr(dst ? ((struct rt6_info *)dst)->rt6i_idev->dev : NULL, daddr, saddr); | 1167 | return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr); |
1168 | } | 1168 | } |
1169 | 1169 | ||
1170 | 1170 | ||
@@ -3098,10 +3098,9 @@ static inline int rt_scope(int ifa_scope) | |||
3098 | 3098 | ||
3099 | static inline int inet6_ifaddr_msgsize(void) | 3099 | static inline int inet6_ifaddr_msgsize(void) |
3100 | { | 3100 | { |
3101 | return nlmsg_total_size(sizeof(struct ifaddrmsg) + | 3101 | return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) |
3102 | nla_total_size(16) + | 3102 | + nla_total_size(16) /* IFA_ADDRESS */ |
3103 | nla_total_size(sizeof(struct ifa_cacheinfo)) + | 3103 | + nla_total_size(sizeof(struct ifa_cacheinfo)); |
3104 | 128); | ||
3105 | } | 3104 | } |
3106 | 3105 | ||
3107 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | 3106 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, |
@@ -3329,10 +3328,8 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, | |||
3329 | 3328 | ||
3330 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, | 3329 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, |
3331 | nlh->nlmsg_seq, RTM_NEWADDR, 0); | 3330 | nlh->nlmsg_seq, RTM_NEWADDR, 0); |
3332 | if (err < 0) { | 3331 | /* failure implies BUG in inet6_ifaddr_msgsize() */ |
3333 | kfree_skb(skb); | 3332 | BUG_ON(err < 0); |
3334 | goto errout_ifa; | ||
3335 | } | ||
3336 | 3333 | ||
3337 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); | 3334 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
3338 | errout_ifa: | 3335 | errout_ifa: |
@@ -3351,10 +3348,8 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) | |||
3351 | goto errout; | 3348 | goto errout; |
3352 | 3349 | ||
3353 | err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); | 3350 | err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); |
3354 | if (err < 0) { | 3351 | /* failure implies BUG in inet6_ifaddr_msgsize() */ |
3355 | kfree_skb(skb); | 3352 | BUG_ON(err < 0); |
3356 | goto errout; | ||
3357 | } | ||
3358 | 3353 | ||
3359 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); | 3354 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); |
3360 | errout: | 3355 | errout: |
@@ -3365,6 +3360,8 @@ errout: | |||
3365 | static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | 3360 | static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, |
3366 | __s32 *array, int bytes) | 3361 | __s32 *array, int bytes) |
3367 | { | 3362 | { |
3363 | BUG_ON(bytes < (DEVCONF_MAX * 4)); | ||
3364 | |||
3368 | memset(array, 0, bytes); | 3365 | memset(array, 0, bytes); |
3369 | array[DEVCONF_FORWARDING] = cnf->forwarding; | 3366 | array[DEVCONF_FORWARDING] = cnf->forwarding; |
3370 | array[DEVCONF_HOPLIMIT] = cnf->hop_limit; | 3367 | array[DEVCONF_HOPLIMIT] = cnf->hop_limit; |
@@ -3397,80 +3394,76 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3397 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; | 3394 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; |
3398 | } | 3395 | } |
3399 | 3396 | ||
3400 | /* Maximum length of ifinfomsg attributes */ | 3397 | static inline size_t inet6_if_nlmsg_size(void) |
3401 | #define INET6_IFINFO_RTA_SPACE \ | 3398 | { |
3402 | RTA_SPACE(IFNAMSIZ) /* IFNAME */ + \ | 3399 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) |
3403 | RTA_SPACE(MAX_ADDR_LEN) /* ADDRESS */ + \ | 3400 | + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ |
3404 | RTA_SPACE(sizeof(u32)) /* MTU */ + \ | 3401 | + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ |
3405 | RTA_SPACE(sizeof(int)) /* LINK */ + \ | 3402 | + nla_total_size(4) /* IFLA_MTU */ |
3406 | RTA_SPACE(0) /* PROTINFO */ + \ | 3403 | + nla_total_size(4) /* IFLA_LINK */ |
3407 | RTA_SPACE(sizeof(u32)) /* FLAGS */ + \ | 3404 | + nla_total_size( /* IFLA_PROTINFO */ |
3408 | RTA_SPACE(sizeof(struct ifla_cacheinfo)) /* CACHEINFO */ + \ | 3405 | nla_total_size(4) /* IFLA_INET6_FLAGS */ |
3409 | RTA_SPACE(sizeof(__s32[DEVCONF_MAX])) /* CONF */ | 3406 | + nla_total_size(sizeof(struct ifla_cacheinfo)) |
3407 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ | ||
3408 | ); | ||
3409 | } | ||
3410 | 3410 | ||
3411 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 3411 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, |
3412 | u32 pid, u32 seq, int event, unsigned int flags) | 3412 | u32 pid, u32 seq, int event, unsigned int flags) |
3413 | { | 3413 | { |
3414 | struct net_device *dev = idev->dev; | 3414 | struct net_device *dev = idev->dev; |
3415 | __s32 *array = NULL; | 3415 | struct nlattr *conf; |
3416 | struct ifinfomsg *r; | 3416 | struct ifinfomsg *hdr; |
3417 | struct nlmsghdr *nlh; | 3417 | struct nlmsghdr *nlh; |
3418 | unsigned char *b = skb->tail; | 3418 | void *protoinfo; |
3419 | struct rtattr *subattr; | 3419 | struct ifla_cacheinfo ci; |
3420 | __u32 mtu = dev->mtu; | 3420 | |
3421 | struct ifla_cacheinfo ci; | 3421 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); |
3422 | 3422 | if (nlh == NULL) | |
3423 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags); | 3423 | return -ENOBUFS; |
3424 | r = NLMSG_DATA(nlh); | 3424 | |
3425 | r->ifi_family = AF_INET6; | 3425 | hdr = nlmsg_data(nlh); |
3426 | r->__ifi_pad = 0; | 3426 | hdr->ifi_family = AF_INET6; |
3427 | r->ifi_type = dev->type; | 3427 | hdr->__ifi_pad = 0; |
3428 | r->ifi_index = dev->ifindex; | 3428 | hdr->ifi_type = dev->type; |
3429 | r->ifi_flags = dev_get_flags(dev); | 3429 | hdr->ifi_index = dev->ifindex; |
3430 | r->ifi_change = 0; | 3430 | hdr->ifi_flags = dev_get_flags(dev); |
3431 | 3431 | hdr->ifi_change = 0; | |
3432 | RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name); | 3432 | |
3433 | NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); | ||
3433 | 3434 | ||
3434 | if (dev->addr_len) | 3435 | if (dev->addr_len) |
3435 | RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); | 3436 | NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); |
3436 | 3437 | ||
3437 | RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu); | 3438 | NLA_PUT_U32(skb, IFLA_MTU, dev->mtu); |
3438 | if (dev->ifindex != dev->iflink) | 3439 | if (dev->ifindex != dev->iflink) |
3439 | RTA_PUT(skb, IFLA_LINK, sizeof(int), &dev->iflink); | 3440 | NLA_PUT_U32(skb, IFLA_LINK, dev->iflink); |
3440 | |||
3441 | subattr = (struct rtattr*)skb->tail; | ||
3442 | 3441 | ||
3443 | RTA_PUT(skb, IFLA_PROTINFO, 0, NULL); | 3442 | protoinfo = nla_nest_start(skb, IFLA_PROTINFO); |
3443 | if (protoinfo == NULL) | ||
3444 | goto nla_put_failure; | ||
3444 | 3445 | ||
3445 | /* return the device flags */ | 3446 | NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); |
3446 | RTA_PUT(skb, IFLA_INET6_FLAGS, sizeof(__u32), &idev->if_flags); | ||
3447 | 3447 | ||
3448 | /* return interface cacheinfo */ | ||
3449 | ci.max_reasm_len = IPV6_MAXPLEN; | 3448 | ci.max_reasm_len = IPV6_MAXPLEN; |
3450 | ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100 | 3449 | ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100 |
3451 | + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | 3450 | + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); |
3452 | ci.reachable_time = idev->nd_parms->reachable_time; | 3451 | ci.reachable_time = idev->nd_parms->reachable_time; |
3453 | ci.retrans_time = idev->nd_parms->retrans_time; | 3452 | ci.retrans_time = idev->nd_parms->retrans_time; |
3454 | RTA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); | 3453 | NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); |
3455 | 3454 | ||
3456 | /* return the device sysctl params */ | 3455 | conf = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); |
3457 | if ((array = kmalloc(DEVCONF_MAX * sizeof(*array), GFP_ATOMIC)) == NULL) | 3456 | if (conf == NULL) |
3458 | goto rtattr_failure; | 3457 | goto nla_put_failure; |
3459 | ipv6_store_devconf(&idev->cnf, array, DEVCONF_MAX * sizeof(*array)); | 3458 | ipv6_store_devconf(&idev->cnf, nla_data(conf), nla_len(conf)); |
3460 | RTA_PUT(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(*array), array); | ||
3461 | 3459 | ||
3462 | /* XXX - Statistics/MC not implemented */ | 3460 | /* XXX - Statistics/MC not implemented */ |
3463 | subattr->rta_len = skb->tail - (u8*)subattr; | ||
3464 | 3461 | ||
3465 | nlh->nlmsg_len = skb->tail - b; | 3462 | nla_nest_end(skb, protoinfo); |
3466 | kfree(array); | 3463 | return nlmsg_end(skb, nlh); |
3467 | return skb->len; | ||
3468 | 3464 | ||
3469 | nlmsg_failure: | 3465 | nla_put_failure: |
3470 | rtattr_failure: | 3466 | return nlmsg_cancel(skb, nlh); |
3471 | kfree(array); | ||
3472 | skb_trim(skb, b - skb->data); | ||
3473 | return -1; | ||
3474 | } | 3467 | } |
3475 | 3468 | ||
3476 | static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | 3469 | static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) |
@@ -3501,18 +3494,15 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
3501 | void inet6_ifinfo_notify(int event, struct inet6_dev *idev) | 3494 | void inet6_ifinfo_notify(int event, struct inet6_dev *idev) |
3502 | { | 3495 | { |
3503 | struct sk_buff *skb; | 3496 | struct sk_buff *skb; |
3504 | int payload = sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE; | ||
3505 | int err = -ENOBUFS; | 3497 | int err = -ENOBUFS; |
3506 | 3498 | ||
3507 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); | 3499 | skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC); |
3508 | if (skb == NULL) | 3500 | if (skb == NULL) |
3509 | goto errout; | 3501 | goto errout; |
3510 | 3502 | ||
3511 | err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0); | 3503 | err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0); |
3512 | if (err < 0) { | 3504 | /* failure implies BUG in inet6_if_nlmsg_size() */ |
3513 | kfree_skb(skb); | 3505 | BUG_ON(err < 0); |
3514 | goto errout; | ||
3515 | } | ||
3516 | 3506 | ||
3517 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); | 3507 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); |
3518 | errout: | 3508 | errout: |
@@ -3520,22 +3510,26 @@ errout: | |||
3520 | rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); | 3510 | rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); |
3521 | } | 3511 | } |
3522 | 3512 | ||
3523 | /* Maximum length of prefix_cacheinfo attributes */ | 3513 | static inline size_t inet6_prefix_nlmsg_size(void) |
3524 | #define INET6_PREFIX_RTA_SPACE \ | 3514 | { |
3525 | RTA_SPACE(sizeof(((struct prefix_info *)NULL)->prefix)) /* ADDRESS */ + \ | 3515 | return NLMSG_ALIGN(sizeof(struct prefixmsg)) |
3526 | RTA_SPACE(sizeof(struct prefix_cacheinfo)) /* CACHEINFO */ | 3516 | + nla_total_size(sizeof(struct in6_addr)) |
3517 | + nla_total_size(sizeof(struct prefix_cacheinfo)); | ||
3518 | } | ||
3527 | 3519 | ||
3528 | static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, | 3520 | static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, |
3529 | struct prefix_info *pinfo, u32 pid, u32 seq, | 3521 | struct prefix_info *pinfo, u32 pid, u32 seq, |
3530 | int event, unsigned int flags) | 3522 | int event, unsigned int flags) |
3531 | { | 3523 | { |
3532 | struct prefixmsg *pmsg; | 3524 | struct prefixmsg *pmsg; |
3533 | struct nlmsghdr *nlh; | 3525 | struct nlmsghdr *nlh; |
3534 | unsigned char *b = skb->tail; | ||
3535 | struct prefix_cacheinfo ci; | 3526 | struct prefix_cacheinfo ci; |
3536 | 3527 | ||
3537 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*pmsg), flags); | 3528 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*pmsg), flags); |
3538 | pmsg = NLMSG_DATA(nlh); | 3529 | if (nlh == NULL) |
3530 | return -ENOBUFS; | ||
3531 | |||
3532 | pmsg = nlmsg_data(nlh); | ||
3539 | pmsg->prefix_family = AF_INET6; | 3533 | pmsg->prefix_family = AF_INET6; |
3540 | pmsg->prefix_pad1 = 0; | 3534 | pmsg->prefix_pad1 = 0; |
3541 | pmsg->prefix_pad2 = 0; | 3535 | pmsg->prefix_pad2 = 0; |
@@ -3543,44 +3537,37 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, | |||
3543 | pmsg->prefix_len = pinfo->prefix_len; | 3537 | pmsg->prefix_len = pinfo->prefix_len; |
3544 | pmsg->prefix_type = pinfo->type; | 3538 | pmsg->prefix_type = pinfo->type; |
3545 | pmsg->prefix_pad3 = 0; | 3539 | pmsg->prefix_pad3 = 0; |
3546 | |||
3547 | pmsg->prefix_flags = 0; | 3540 | pmsg->prefix_flags = 0; |
3548 | if (pinfo->onlink) | 3541 | if (pinfo->onlink) |
3549 | pmsg->prefix_flags |= IF_PREFIX_ONLINK; | 3542 | pmsg->prefix_flags |= IF_PREFIX_ONLINK; |
3550 | if (pinfo->autoconf) | 3543 | if (pinfo->autoconf) |
3551 | pmsg->prefix_flags |= IF_PREFIX_AUTOCONF; | 3544 | pmsg->prefix_flags |= IF_PREFIX_AUTOCONF; |
3552 | 3545 | ||
3553 | RTA_PUT(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix); | 3546 | NLA_PUT(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix); |
3554 | 3547 | ||
3555 | ci.preferred_time = ntohl(pinfo->prefered); | 3548 | ci.preferred_time = ntohl(pinfo->prefered); |
3556 | ci.valid_time = ntohl(pinfo->valid); | 3549 | ci.valid_time = ntohl(pinfo->valid); |
3557 | RTA_PUT(skb, PREFIX_CACHEINFO, sizeof(ci), &ci); | 3550 | NLA_PUT(skb, PREFIX_CACHEINFO, sizeof(ci), &ci); |
3558 | 3551 | ||
3559 | nlh->nlmsg_len = skb->tail - b; | 3552 | return nlmsg_end(skb, nlh); |
3560 | return skb->len; | ||
3561 | 3553 | ||
3562 | nlmsg_failure: | 3554 | nla_put_failure: |
3563 | rtattr_failure: | 3555 | return nlmsg_cancel(skb, nlh); |
3564 | skb_trim(skb, b - skb->data); | ||
3565 | return -1; | ||
3566 | } | 3556 | } |
3567 | 3557 | ||
3568 | static void inet6_prefix_notify(int event, struct inet6_dev *idev, | 3558 | static void inet6_prefix_notify(int event, struct inet6_dev *idev, |
3569 | struct prefix_info *pinfo) | 3559 | struct prefix_info *pinfo) |
3570 | { | 3560 | { |
3571 | struct sk_buff *skb; | 3561 | struct sk_buff *skb; |
3572 | int payload = sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE; | ||
3573 | int err = -ENOBUFS; | 3562 | int err = -ENOBUFS; |
3574 | 3563 | ||
3575 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); | 3564 | skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC); |
3576 | if (skb == NULL) | 3565 | if (skb == NULL) |
3577 | goto errout; | 3566 | goto errout; |
3578 | 3567 | ||
3579 | err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0); | 3568 | err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0); |
3580 | if (err < 0) { | 3569 | /* failure implies BUG in inet6_prefix_nlmsg_size() */ |
3581 | kfree_skb(skb); | 3570 | BUG_ON(err < 0); |
3582 | goto errout; | ||
3583 | } | ||
3584 | 3571 | ||
3585 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); | 3572 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); |
3586 | errout: | 3573 | errout: |
@@ -3982,10 +3969,9 @@ static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf | |||
3982 | struct addrconf_sysctl_table *t; | 3969 | struct addrconf_sysctl_table *t; |
3983 | char *dev_name = NULL; | 3970 | char *dev_name = NULL; |
3984 | 3971 | ||
3985 | t = kmalloc(sizeof(*t), GFP_KERNEL); | 3972 | t = kmemdup(&addrconf_sysctl, sizeof(*t), GFP_KERNEL); |
3986 | if (t == NULL) | 3973 | if (t == NULL) |
3987 | return; | 3974 | return; |
3988 | memcpy(t, &addrconf_sysctl, sizeof(*t)); | ||
3989 | for (i=0; t->addrconf_vars[i].data; i++) { | 3975 | for (i=0; t->addrconf_vars[i].data; i++) { |
3990 | t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf; | 3976 | t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf; |
3991 | t->addrconf_vars[i].de = NULL; | 3977 | t->addrconf_vars[i].de = NULL; |