diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 93a40a8ade88..3ef3fe20283f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -3165,6 +3165,62 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
3165 | return inet6_dump_addr(skb, cb, type); | 3165 | return inet6_dump_addr(skb, cb, type); |
3166 | } | 3166 | } |
3167 | 3167 | ||
3168 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, | ||
3169 | struct nlmsghdr* nlh, void *arg) | ||
3170 | { | ||
3171 | struct rtattr **rta = arg; | ||
3172 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | ||
3173 | struct in6_addr *addr = NULL; | ||
3174 | struct net_device *dev = NULL; | ||
3175 | struct inet6_ifaddr *ifa; | ||
3176 | struct sk_buff *skb; | ||
3177 | int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE); | ||
3178 | int err; | ||
3179 | |||
3180 | if (rta[IFA_ADDRESS-1]) { | ||
3181 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr)) | ||
3182 | return -EINVAL; | ||
3183 | addr = RTA_DATA(rta[IFA_ADDRESS-1]); | ||
3184 | } | ||
3185 | if (rta[IFA_LOCAL-1]) { | ||
3186 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) || | ||
3187 | (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr)))) | ||
3188 | return -EINVAL; | ||
3189 | addr = RTA_DATA(rta[IFA_LOCAL-1]); | ||
3190 | } | ||
3191 | if (addr == NULL) | ||
3192 | return -EINVAL; | ||
3193 | |||
3194 | if (ifm->ifa_index) | ||
3195 | dev = __dev_get_by_index(ifm->ifa_index); | ||
3196 | |||
3197 | if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) | ||
3198 | return -EADDRNOTAVAIL; | ||
3199 | |||
3200 | if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) { | ||
3201 | err = -ENOBUFS; | ||
3202 | goto out; | ||
3203 | } | ||
3204 | |||
3205 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
3206 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, | ||
3207 | nlh->nlmsg_seq, RTM_NEWADDR, 0); | ||
3208 | if (err < 0) { | ||
3209 | err = -EMSGSIZE; | ||
3210 | goto out_free; | ||
3211 | } | ||
3212 | |||
3213 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | ||
3214 | if (err > 0) | ||
3215 | err = 0; | ||
3216 | out: | ||
3217 | in6_ifa_put(ifa); | ||
3218 | return err; | ||
3219 | out_free: | ||
3220 | kfree_skb(skb); | ||
3221 | goto out; | ||
3222 | } | ||
3223 | |||
3168 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) | 3224 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) |
3169 | { | 3225 | { |
3170 | struct sk_buff *skb; | 3226 | struct sk_buff *skb; |
@@ -3407,7 +3463,8 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { | |||
3407 | [RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, }, | 3463 | [RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, }, |
3408 | [RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, }, | 3464 | [RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, }, |
3409 | [RTM_DELADDR - RTM_BASE] = { .doit = inet6_rtm_deladdr, }, | 3465 | [RTM_DELADDR - RTM_BASE] = { .doit = inet6_rtm_deladdr, }, |
3410 | [RTM_GETADDR - RTM_BASE] = { .dumpit = inet6_dump_ifaddr, }, | 3466 | [RTM_GETADDR - RTM_BASE] = { .doit = inet6_rtm_getaddr, |
3467 | .dumpit = inet6_dump_ifaddr, }, | ||
3411 | [RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, }, | 3468 | [RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, }, |
3412 | [RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, }, | 3469 | [RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, }, |
3413 | [RTM_NEWROUTE - RTM_BASE] = { .doit = inet6_rtm_newroute, }, | 3470 | [RTM_NEWROUTE - RTM_BASE] = { .doit = inet6_rtm_newroute, }, |