diff options
-rw-r--r-- | net/ipv6/addrconf.c | 52 |
1 files changed, 24 insertions, 28 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 61627036eb2b..b2c38b3edb39 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -3234,58 +3234,54 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
3234 | return inet6_dump_addr(skb, cb, type); | 3234 | return inet6_dump_addr(skb, cb, type); |
3235 | } | 3235 | } |
3236 | 3236 | ||
3237 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, | 3237 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, |
3238 | struct nlmsghdr* nlh, void *arg) | 3238 | void *arg) |
3239 | { | 3239 | { |
3240 | struct rtattr **rta = arg; | 3240 | struct ifaddrmsg *ifm; |
3241 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 3241 | struct nlattr *tb[IFA_MAX+1]; |
3242 | struct in6_addr *addr = NULL; | 3242 | struct in6_addr *addr = NULL; |
3243 | struct net_device *dev = NULL; | 3243 | struct net_device *dev = NULL; |
3244 | struct inet6_ifaddr *ifa; | 3244 | struct inet6_ifaddr *ifa; |
3245 | struct sk_buff *skb; | 3245 | struct sk_buff *skb; |
3246 | int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE); | 3246 | int payload = sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE; |
3247 | int err; | 3247 | int err; |
3248 | 3248 | ||
3249 | if (rta[IFA_ADDRESS-1]) { | 3249 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
3250 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr)) | 3250 | if (err < 0) |
3251 | return -EINVAL; | 3251 | goto errout; |
3252 | addr = RTA_DATA(rta[IFA_ADDRESS-1]); | 3252 | |
3253 | } | 3253 | addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); |
3254 | if (rta[IFA_LOCAL-1]) { | 3254 | if (addr == NULL) { |
3255 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) || | 3255 | err = -EINVAL; |
3256 | (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr)))) | 3256 | goto errout; |
3257 | return -EINVAL; | ||
3258 | addr = RTA_DATA(rta[IFA_LOCAL-1]); | ||
3259 | } | 3257 | } |
3260 | if (addr == NULL) | ||
3261 | return -EINVAL; | ||
3262 | 3258 | ||
3259 | ifm = nlmsg_data(nlh); | ||
3263 | if (ifm->ifa_index) | 3260 | if (ifm->ifa_index) |
3264 | dev = __dev_get_by_index(ifm->ifa_index); | 3261 | dev = __dev_get_by_index(ifm->ifa_index); |
3265 | 3262 | ||
3266 | if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) | 3263 | if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) { |
3267 | return -EADDRNOTAVAIL; | 3264 | err = -EADDRNOTAVAIL; |
3265 | goto errout; | ||
3266 | } | ||
3268 | 3267 | ||
3269 | if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) { | 3268 | if ((skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL)) == NULL) { |
3270 | err = -ENOBUFS; | 3269 | err = -ENOBUFS; |
3271 | goto out; | 3270 | goto errout_ifa; |
3272 | } | 3271 | } |
3273 | 3272 | ||
3274 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
3275 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, | 3273 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, |
3276 | nlh->nlmsg_seq, RTM_NEWADDR, 0); | 3274 | nlh->nlmsg_seq, RTM_NEWADDR, 0); |
3277 | if (err < 0) { | 3275 | if (err < 0) { |
3278 | err = -EMSGSIZE; | 3276 | kfree_skb(skb); |
3279 | goto out_free; | 3277 | goto errout_ifa; |
3280 | } | 3278 | } |
3281 | 3279 | ||
3282 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); | 3280 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
3283 | out: | 3281 | errout_ifa: |
3284 | in6_ifa_put(ifa); | 3282 | in6_ifa_put(ifa); |
3283 | errout: | ||
3285 | return err; | 3284 | return err; |
3286 | out_free: | ||
3287 | kfree_skb(skb); | ||
3288 | goto out; | ||
3289 | } | 3285 | } |
3290 | 3286 | ||
3291 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) | 3287 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) |