aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/sit.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r--net/ipv6/sit.c96
1 files changed, 87 insertions, 9 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 84c1ed246afb..08a483a8de50 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -203,12 +203,73 @@ __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
203 struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL; 203 struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL;
204 204
205 for (p = t->prl; p; p = p->next) 205 for (p = t->prl; p; p = p->next)
206 if (p->entry.addr == addr) 206 if (p->addr == addr)
207 break; 207 break;
208 return p; 208 return p;
209 209
210} 210}
211 211
212static int ipip6_tunnel_get_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
213{
214 struct ip_tunnel_prl *kp;
215 struct ip_tunnel_prl_entry *prl;
216 unsigned int cmax, c = 0, ca, len;
217 int ret = 0;
218
219 cmax = a->datalen / sizeof(*a);
220 if (cmax > 1 && a->addr != htonl(INADDR_ANY))
221 cmax = 1;
222
223 /* For simple GET or for root users,
224 * we try harder to allocate.
225 */
226 kp = (cmax <= 1 || capable(CAP_NET_ADMIN)) ?
227 kcalloc(cmax, sizeof(*kp), GFP_KERNEL) :
228 NULL;
229
230 read_lock(&ipip6_lock);
231
232 ca = t->prl_count < cmax ? t->prl_count : cmax;
233
234 if (!kp) {
235 /* We don't try hard to allocate much memory for
236 * non-root users.
237 * For root users, retry allocating enough memory for
238 * the answer.
239 */
240 kp = kcalloc(ca, sizeof(*kp), GFP_ATOMIC);
241 if (!kp) {
242 ret = -ENOMEM;
243 goto out;
244 }
245 }
246
247 c = 0;
248 for (prl = t->prl; prl; prl = prl->next) {
249 if (c > cmax)
250 break;
251 if (a->addr != htonl(INADDR_ANY) && prl->addr != a->addr)
252 continue;
253 kp[c].addr = prl->addr;
254 kp[c].flags = prl->flags;
255 c++;
256 if (a->addr != htonl(INADDR_ANY))
257 break;
258 }
259out:
260 read_unlock(&ipip6_lock);
261
262 len = sizeof(*kp) * c;
263 ret = len ? copy_to_user(a->data, kp, len) : 0;
264
265 kfree(kp);
266 if (ret)
267 return -EFAULT;
268
269 a->datalen = len;
270 return 0;
271}
272
212static int 273static int
213ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) 274ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
214{ 275{
@@ -221,7 +282,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
221 write_lock(&ipip6_lock); 282 write_lock(&ipip6_lock);
222 283
223 for (p = t->prl; p; p = p->next) { 284 for (p = t->prl; p; p = p->next) {
224 if (p->entry.addr == a->addr) { 285 if (p->addr == a->addr) {
225 if (chg) 286 if (chg)
226 goto update; 287 goto update;
227 err = -EEXIST; 288 err = -EEXIST;
@@ -242,8 +303,10 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
242 303
243 p->next = t->prl; 304 p->next = t->prl;
244 t->prl = p; 305 t->prl = p;
306 t->prl_count++;
245update: 307update:
246 p->entry = *a; 308 p->addr = a->addr;
309 p->flags = a->flags;
247out: 310out:
248 write_unlock(&ipip6_lock); 311 write_unlock(&ipip6_lock);
249 return err; 312 return err;
@@ -259,10 +322,11 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
259 322
260 if (a && a->addr != htonl(INADDR_ANY)) { 323 if (a && a->addr != htonl(INADDR_ANY)) {
261 for (p = &t->prl; *p; p = &(*p)->next) { 324 for (p = &t->prl; *p; p = &(*p)->next) {
262 if ((*p)->entry.addr == a->addr) { 325 if ((*p)->addr == a->addr) {
263 x = *p; 326 x = *p;
264 *p = x->next; 327 *p = x->next;
265 kfree(x); 328 kfree(x);
329 t->prl_count--;
266 goto out; 330 goto out;
267 } 331 }
268 } 332 }
@@ -272,6 +336,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
272 x = t->prl; 336 x = t->prl;
273 t->prl = t->prl->next; 337 t->prl = t->prl->next;
274 kfree(x); 338 kfree(x);
339 t->prl_count--;
275 } 340 }
276 } 341 }
277out: 342out:
@@ -313,7 +378,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
313 read_lock(&ipip6_lock); 378 read_lock(&ipip6_lock);
314 p = __ipip6_tunnel_locate_prl(t, iph->saddr); 379 p = __ipip6_tunnel_locate_prl(t, iph->saddr);
315 if (p) { 380 if (p) {
316 if (p->entry.flags & PRL_DEFAULT) 381 if (p->flags & PRL_DEFAULT)
317 skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT; 382 skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT;
318 else 383 else
319 skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; 384 skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT;
@@ -899,11 +964,12 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
899 err = 0; 964 err = 0;
900 break; 965 break;
901 966
967 case SIOCGETPRL:
902 case SIOCADDPRL: 968 case SIOCADDPRL:
903 case SIOCDELPRL: 969 case SIOCDELPRL:
904 case SIOCCHGPRL: 970 case SIOCCHGPRL:
905 err = -EPERM; 971 err = -EPERM;
906 if (!capable(CAP_NET_ADMIN)) 972 if (cmd != SIOCGETPRL && !capable(CAP_NET_ADMIN))
907 goto done; 973 goto done;
908 err = -EINVAL; 974 err = -EINVAL;
909 if (dev == ipip6_fb_tunnel_dev) 975 if (dev == ipip6_fb_tunnel_dev)
@@ -915,11 +981,23 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
915 if (!(t = netdev_priv(dev))) 981 if (!(t = netdev_priv(dev)))
916 goto done; 982 goto done;
917 983
918 if (cmd == SIOCDELPRL) 984 switch (cmd) {
985 case SIOCGETPRL:
986 err = ipip6_tunnel_get_prl(t, &prl);
987 if (!err && copy_to_user(ifr->ifr_ifru.ifru_data,
988 &prl, sizeof(prl)))
989 err = -EFAULT;
990 break;
991 case SIOCDELPRL:
919 err = ipip6_tunnel_del_prl(t, &prl); 992 err = ipip6_tunnel_del_prl(t, &prl);
920 else 993 break;
994 case SIOCADDPRL:
995 case SIOCCHGPRL:
921 err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); 996 err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
922 netdev_state_change(dev); 997 break;
998 }
999 if (cmd != SIOCGETPRL)
1000 netdev_state_change(dev);
923 break; 1001 break;
924 1002
925 default: 1003 default: