aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c59
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
3168static 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;
3216out:
3217 in6_ifa_put(ifa);
3218 return err;
3219out_free:
3220 kfree_skb(skb);
3221 goto out;
3222}
3223
3168static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) 3224static 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, },