aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-03-24 05:28:39 -0400
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-04-02 21:06:00 -0400
commit300aaeeaab5f447fcf40e911afe96df3de28f0db (patch)
tree43bc6509b745561e538972c168f1cf8d7abd4bf1
parent0009ae1f50fb10178b5f54216ce567f3cb1d7267 (diff)
[IPV6] SIT: Add SIOCGETPRL ioctl to get/dump PRL.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
-rw-r--r--include/linux/if_tunnel.h4
-rw-r--r--include/net/ipip.h5
-rw-r--r--net/ipv6/sit.c96
3 files changed, 95 insertions, 10 deletions
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index f20c224d544c..f1fbe9c930d7 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -7,6 +7,7 @@
7#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1) 7#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1)
8#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2) 8#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2)
9#define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3) 9#define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3)
10#define SIOCGETPRL (SIOCDEVPRIVATE + 4)
10#define SIOCADDPRL (SIOCDEVPRIVATE + 5) 11#define SIOCADDPRL (SIOCDEVPRIVATE + 5)
11#define SIOCDELPRL (SIOCDEVPRIVATE + 6) 12#define SIOCDELPRL (SIOCDEVPRIVATE + 6)
12#define SIOCCHGPRL (SIOCDEVPRIVATE + 7) 13#define SIOCCHGPRL (SIOCDEVPRIVATE + 7)
@@ -38,6 +39,9 @@ struct ip_tunnel_prl {
38 __be32 addr; 39 __be32 addr;
39 __u16 flags; 40 __u16 flags;
40 __u16 __reserved; 41 __u16 __reserved;
42 __u32 datalen;
43 __u32 __reserved2;
44 void __user *data;
41}; 45};
42 46
43/* PRL flags */ 47/* PRL flags */
diff --git a/include/net/ipip.h b/include/net/ipip.h
index 205536a014e8..633ed4def8e3 100644
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -24,13 +24,16 @@ struct ip_tunnel
24 int mlink; 24 int mlink;
25 25
26 struct ip_tunnel_parm parms; 26 struct ip_tunnel_parm parms;
27
27 struct ip_tunnel_prl_entry *prl; /* potential router list */ 28 struct ip_tunnel_prl_entry *prl; /* potential router list */
29 unsigned int prl_count; /* # of entries in PRL */
28}; 30};
29 31
30struct ip_tunnel_prl_entry 32struct ip_tunnel_prl_entry
31{ 33{
32 struct ip_tunnel_prl_entry *next; 34 struct ip_tunnel_prl_entry *next;
33 struct ip_tunnel_prl entry; 35 __be32 addr;
36 u16 flags;
34}; 37};
35 38
36#define IPTUNNEL_XMIT() do { \ 39#define IPTUNNEL_XMIT() do { \
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: