Blame view

net/ipv6/addrlabel.c 13.8 KB
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * IPv6 Address Label subsystem
   * for the IPv6 "Default" Source Address Selection
   *
   * Copyright (C)2007 USAGI/WIDE Project
   */
  /*
   * Author:
   * 	YOSHIFUJI Hideaki @ USAGI/WIDE Project <yoshfuji@linux-ipv6.org>
   */
  
  #include <linux/kernel.h>
  #include <linux/list.h>
  #include <linux/rcupdate.h>
  #include <linux/in6.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
16
  #include <linux/slab.h>
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  #include <net/addrconf.h>
  #include <linux/if_addrlabel.h>
  #include <linux/netlink.h>
  #include <linux/rtnetlink.h>
  
  #if 0
  #define ADDRLABEL(x...) printk(x)
  #else
  #define ADDRLABEL(x...) do { ; } while(0)
  #endif
  
  /*
   * Policy Table
   */
  struct ip6addrlbl_entry
  {
3de232554   Benjamin Thery   ipv6 netns: Addre...
33
34
35
  #ifdef CONFIG_NET_NS
  	struct net *lbl_net;
  #endif
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  	struct in6_addr prefix;
  	int prefixlen;
  	int ifindex;
  	int addrtype;
  	u32 label;
  	struct hlist_node list;
  	atomic_t refcnt;
  	struct rcu_head rcu;
  };
  
  static struct ip6addrlbl_table
  {
  	struct hlist_head head;
  	spinlock_t lock;
  	u32 seq;
  } ip6addrlbl_table;
3de232554   Benjamin Thery   ipv6 netns: Addre...
52
53
54
  static inline
  struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
  {
c2d9ba9bc   Eric Dumazet   net: CONFIG_NET_N...
55
  	return read_pnet(&lbl->lbl_net);
3de232554   Benjamin Thery   ipv6 netns: Addre...
56
  }
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
57
58
59
60
61
62
63
64
65
66
67
68
  /*
   * Default policy table (RFC3484 + extensions)
   *
   * prefix		addr_type	label
   * -------------------------------------------------------------------------
   * ::1/128		LOOPBACK	0
   * ::/0			N/A		1
   * 2002::/16		N/A		2
   * ::/96		COMPATv4	3
   * ::ffff:0:0/96	V4MAPPED	4
   * fc00::/7		N/A		5		ULA (RFC 4193)
   * 2001::/32		N/A		6		Teredo (RFC 4380)
5fe47b8a6   Juha-Matti Tapio   [IPV6]: Add ORCHI...
69
   * 2001:10::/28		N/A		7		ORCHID (RFC 4843)
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
70
71
72
73
74
   *
   * Note: 0xffffffff is used if we do not have any policies.
   */
  
  #define IPV6_ADDR_LABEL_DEFAULT	0xffffffffUL
3de232554   Benjamin Thery   ipv6 netns: Addre...
75
  static const __net_initdata struct ip6addrlbl_init_table
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  {
  	const struct in6_addr *prefix;
  	int prefixlen;
  	u32 label;
  } ip6addrlbl_init_table[] = {
  	{	/* ::/0 */
  		.prefix = &in6addr_any,
  		.label = 1,
  	},{	/* fc00::/7 */
  		.prefix = &(struct in6_addr){{{ 0xfc }}},
  		.prefixlen = 7,
  		.label = 5,
  	},{	/* 2002::/16 */
  		.prefix = &(struct in6_addr){{{ 0x20, 0x02 }}},
  		.prefixlen = 16,
  		.label = 2,
  	},{	/* 2001::/32 */
  		.prefix = &(struct in6_addr){{{ 0x20, 0x01 }}},
  		.prefixlen = 32,
  		.label = 6,
5fe47b8a6   Juha-Matti Tapio   [IPV6]: Add ORCHI...
96
97
98
99
  	},{	/* 2001:10::/28 */
  		.prefix = &(struct in6_addr){{{ 0x20, 0x01, 0x00, 0x10 }}},
  		.prefixlen = 28,
  		.label = 7,
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  	},{	/* ::ffff:0:0 */
  		.prefix = &(struct in6_addr){{{ [10] = 0xff, [11] = 0xff }}},
  		.prefixlen = 96,
  		.label = 4,
  	},{	/* ::/96 */
  		.prefix = &in6addr_any,
  		.prefixlen = 96,
  		.label = 3,
  	},{	/* ::1/128 */
  		.prefix = &in6addr_loopback,
  		.prefixlen = 128,
  		.label = 0,
  	}
  };
  
  /* Object management */
  static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p)
  {
3de232554   Benjamin Thery   ipv6 netns: Addre...
118
119
120
  #ifdef CONFIG_NET_NS
  	release_net(p->lbl_net);
  #endif
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
121
122
  	kfree(p);
  }
85040bcb4   YOSHIFUJI Hideaki   [IPV6] ADDRLABEL:...
123
124
125
126
  static void ip6addrlbl_free_rcu(struct rcu_head *h)
  {
  	ip6addrlbl_free(container_of(h, struct ip6addrlbl_entry, rcu));
  }
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
127
128
129
130
131
132
133
134
  static inline int ip6addrlbl_hold(struct ip6addrlbl_entry *p)
  {
  	return atomic_inc_not_zero(&p->refcnt);
  }
  
  static inline void ip6addrlbl_put(struct ip6addrlbl_entry *p)
  {
  	if (atomic_dec_and_test(&p->refcnt))
85040bcb4   YOSHIFUJI Hideaki   [IPV6] ADDRLABEL:...
135
  		call_rcu(&p->rcu, ip6addrlbl_free_rcu);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
136
137
138
  }
  
  /* Find label */
3de232554   Benjamin Thery   ipv6 netns: Addre...
139
140
  static int __ip6addrlbl_match(struct net *net,
  			      struct ip6addrlbl_entry *p,
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
141
142
143
  			      const struct in6_addr *addr,
  			      int addrtype, int ifindex)
  {
3de232554   Benjamin Thery   ipv6 netns: Addre...
144
145
  	if (!net_eq(ip6addrlbl_net(p), net))
  		return 0;
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
146
147
148
149
150
151
152
153
  	if (p->ifindex && p->ifindex != ifindex)
  		return 0;
  	if (p->addrtype && p->addrtype != addrtype)
  		return 0;
  	if (!ipv6_prefix_equal(addr, &p->prefix, p->prefixlen))
  		return 0;
  	return 1;
  }
3de232554   Benjamin Thery   ipv6 netns: Addre...
154
155
  static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net,
  						  const struct in6_addr *addr,
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
156
157
158
159
160
  						  int type, int ifindex)
  {
  	struct hlist_node *pos;
  	struct ip6addrlbl_entry *p;
  	hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
3de232554   Benjamin Thery   ipv6 netns: Addre...
161
  		if (__ip6addrlbl_match(net, p, addr, type, ifindex))
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
162
163
164
165
  			return p;
  	}
  	return NULL;
  }
3de232554   Benjamin Thery   ipv6 netns: Addre...
166
167
  u32 ipv6_addr_label(struct net *net,
  		    const struct in6_addr *addr, int type, int ifindex)
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
168
169
170
171
172
173
174
  {
  	u32 label;
  	struct ip6addrlbl_entry *p;
  
  	type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK;
  
  	rcu_read_lock();
3de232554   Benjamin Thery   ipv6 netns: Addre...
175
  	p = __ipv6_addr_label(net, addr, type, ifindex);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
176
177
  	label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT;
  	rcu_read_unlock();
5b095d989   Harvey Harrison   net: replace %p6 ...
178
179
  	ADDRLABEL(KERN_DEBUG "%s(addr=%pI6, type=%d, ifindex=%d) => %08x
  ",
0c6ce78ab   Harvey Harrison   net: replace uses...
180
  		  __func__, addr, type, ifindex, label);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
181
182
183
184
185
  
  	return label;
  }
  
  /* allocate one entry */
3de232554   Benjamin Thery   ipv6 netns: Addre...
186
187
  static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net,
  						 const struct in6_addr *prefix,
40fee36e1   YOSHIFUJI Hideaki   [IPV6] ADDRLABEL:...
188
189
  						 int prefixlen, int ifindex,
  						 u32 label)
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
190
191
192
  {
  	struct ip6addrlbl_entry *newp;
  	int addrtype;
5b095d989   Harvey Harrison   net: replace %p6 ...
193
194
  	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u)
  ",
0c6ce78ab   Harvey Harrison   net: replace uses...
195
  		  __func__, prefix, prefixlen, ifindex, (unsigned int)label);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  
  	addrtype = ipv6_addr_type(prefix) & (IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK);
  
  	switch (addrtype) {
  	case IPV6_ADDR_MAPPED:
  		if (prefixlen > 96)
  			return ERR_PTR(-EINVAL);
  		if (prefixlen < 96)
  			addrtype = 0;
  		break;
  	case IPV6_ADDR_COMPATv4:
  		if (prefixlen != 96)
  			addrtype = 0;
  		break;
  	case IPV6_ADDR_LOOPBACK:
  		if (prefixlen != 128)
  			addrtype = 0;
  		break;
  	}
  
  	newp = kmalloc(sizeof(*newp), GFP_KERNEL);
  	if (!newp)
  		return ERR_PTR(-ENOMEM);
  
  	ipv6_addr_prefix(&newp->prefix, prefix, prefixlen);
  	newp->prefixlen = prefixlen;
  	newp->ifindex = ifindex;
  	newp->addrtype = addrtype;
  	newp->label = label;
  	INIT_HLIST_NODE(&newp->list);
3de232554   Benjamin Thery   ipv6 netns: Addre...
226
227
228
  #ifdef CONFIG_NET_NS
  	newp->lbl_net = hold_net(net);
  #endif
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
229
230
231
232
233
  	atomic_set(&newp->refcnt, 1);
  	return newp;
  }
  
  /* add a label */
40fee36e1   YOSHIFUJI Hideaki   [IPV6] ADDRLABEL:...
234
  static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace)
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
235
236
237
238
239
  {
  	int ret = 0;
  
  	ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)
  ",
0dc47877a   Harvey Harrison   net: replace rema...
240
  			__func__,
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
241
242
243
244
245
246
247
248
249
250
  			newp, replace);
  
  	if (hlist_empty(&ip6addrlbl_table.head)) {
  		hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head);
  	} else {
  		struct hlist_node *pos, *n;
  		struct ip6addrlbl_entry *p = NULL;
  		hlist_for_each_entry_safe(p, pos, n,
  					  &ip6addrlbl_table.head, list) {
  			if (p->prefixlen == newp->prefixlen &&
3de232554   Benjamin Thery   ipv6 netns: Addre...
251
  			    net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
252
253
254
255
256
257
258
259
  			    p->ifindex == newp->ifindex &&
  			    ipv6_addr_equal(&p->prefix, &newp->prefix)) {
  				if (!replace) {
  					ret = -EEXIST;
  					goto out;
  				}
  				hlist_replace_rcu(&p->list, &newp->list);
  				ip6addrlbl_put(p);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  				goto out;
  			} else if ((p->prefixlen == newp->prefixlen && !p->ifindex) ||
  				   (p->prefixlen < newp->prefixlen)) {
  				hlist_add_before_rcu(&newp->list, &p->list);
  				goto out;
  			}
  		}
  		hlist_add_after_rcu(&p->list, &newp->list);
  	}
  out:
  	if (!ret)
  		ip6addrlbl_table.seq++;
  	return ret;
  }
  
  /* add a label */
3de232554   Benjamin Thery   ipv6 netns: Addre...
276
277
  static int ip6addrlbl_add(struct net *net,
  			  const struct in6_addr *prefix, int prefixlen,
40fee36e1   YOSHIFUJI Hideaki   [IPV6] ADDRLABEL:...
278
  			  int ifindex, u32 label, int replace)
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
279
280
281
  {
  	struct ip6addrlbl_entry *newp;
  	int ret = 0;
5b095d989   Harvey Harrison   net: replace %p6 ...
282
283
  	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u, replace=%d)
  ",
0c6ce78ab   Harvey Harrison   net: replace uses...
284
285
  		  __func__, prefix, prefixlen, ifindex, (unsigned int)label,
  		  replace);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
286

3de232554   Benjamin Thery   ipv6 netns: Addre...
287
  	newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
288
289
290
291
292
293
294
295
296
297
298
  	if (IS_ERR(newp))
  		return PTR_ERR(newp);
  	spin_lock(&ip6addrlbl_table.lock);
  	ret = __ip6addrlbl_add(newp, replace);
  	spin_unlock(&ip6addrlbl_table.lock);
  	if (ret)
  		ip6addrlbl_free(newp);
  	return ret;
  }
  
  /* remove a label */
3de232554   Benjamin Thery   ipv6 netns: Addre...
299
300
  static int __ip6addrlbl_del(struct net *net,
  			    const struct in6_addr *prefix, int prefixlen,
40fee36e1   YOSHIFUJI Hideaki   [IPV6] ADDRLABEL:...
301
  			    int ifindex)
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
302
303
304
305
  {
  	struct ip6addrlbl_entry *p = NULL;
  	struct hlist_node *pos, *n;
  	int ret = -ESRCH;
5b095d989   Harvey Harrison   net: replace %p6 ...
306
307
  	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)
  ",
0c6ce78ab   Harvey Harrison   net: replace uses...
308
  		  __func__, prefix, prefixlen, ifindex);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
309
310
311
  
  	hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
  		if (p->prefixlen == prefixlen &&
3de232554   Benjamin Thery   ipv6 netns: Addre...
312
  		    net_eq(ip6addrlbl_net(p), net) &&
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
313
314
315
316
  		    p->ifindex == ifindex &&
  		    ipv6_addr_equal(&p->prefix, prefix)) {
  			hlist_del_rcu(&p->list);
  			ip6addrlbl_put(p);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
317
318
319
320
321
322
  			ret = 0;
  			break;
  		}
  	}
  	return ret;
  }
3de232554   Benjamin Thery   ipv6 netns: Addre...
323
324
  static int ip6addrlbl_del(struct net *net,
  			  const struct in6_addr *prefix, int prefixlen,
40fee36e1   YOSHIFUJI Hideaki   [IPV6] ADDRLABEL:...
325
  			  int ifindex)
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
326
327
328
  {
  	struct in6_addr prefix_buf;
  	int ret;
5b095d989   Harvey Harrison   net: replace %p6 ...
329
330
  	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)
  ",
0c6ce78ab   Harvey Harrison   net: replace uses...
331
  		  __func__, prefix, prefixlen, ifindex);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
332
333
334
  
  	ipv6_addr_prefix(&prefix_buf, prefix, prefixlen);
  	spin_lock(&ip6addrlbl_table.lock);
3de232554   Benjamin Thery   ipv6 netns: Addre...
335
  	ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
336
337
338
339
340
  	spin_unlock(&ip6addrlbl_table.lock);
  	return ret;
  }
  
  /* add default label */
3de232554   Benjamin Thery   ipv6 netns: Addre...
341
  static int __net_init ip6addrlbl_net_init(struct net *net)
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
342
343
344
  {
  	int err = 0;
  	int i;
0dc47877a   Harvey Harrison   net: replace rema...
345
346
  	ADDRLABEL(KERN_DEBUG "%s()
  ", __func__);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
347
348
  
  	for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
3de232554   Benjamin Thery   ipv6 netns: Addre...
349
350
  		int ret = ip6addrlbl_add(net,
  					 ip6addrlbl_init_table[i].prefix,
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
351
352
353
354
355
356
357
358
359
  					 ip6addrlbl_init_table[i].prefixlen,
  					 0,
  					 ip6addrlbl_init_table[i].label, 0);
  		/* XXX: should we free all rules when we catch an error? */
  		if (ret && (!err || err != -ENOMEM))
  			err = ret;
  	}
  	return err;
  }
3de232554   Benjamin Thery   ipv6 netns: Addre...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
  static void __net_exit ip6addrlbl_net_exit(struct net *net)
  {
  	struct ip6addrlbl_entry *p = NULL;
  	struct hlist_node *pos, *n;
  
  	/* Remove all labels belonging to the exiting net */
  	spin_lock(&ip6addrlbl_table.lock);
  	hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
  		if (net_eq(ip6addrlbl_net(p), net)) {
  			hlist_del_rcu(&p->list);
  			ip6addrlbl_put(p);
  		}
  	}
  	spin_unlock(&ip6addrlbl_table.lock);
  }
  
  static struct pernet_operations ipv6_addr_label_ops = {
  	.init = ip6addrlbl_net_init,
  	.exit = ip6addrlbl_net_exit,
  };
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
380
381
382
  int __init ipv6_addr_label_init(void)
  {
  	spin_lock_init(&ip6addrlbl_table.lock);
3de232554   Benjamin Thery   ipv6 netns: Addre...
383
  	return register_pernet_subsys(&ipv6_addr_label_ops);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
384
  }
2cc6d2bf3   Neil Horman   ipv6: add a missi...
385
386
387
388
  void ipv6_addr_label_cleanup(void)
  {
  	unregister_pernet_subsys(&ipv6_addr_label_ops);
  }
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
389
390
391
392
393
394
395
396
  static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
  	[IFAL_ADDRESS]		= { .len = sizeof(struct in6_addr), },
  	[IFAL_LABEL]		= { .len = sizeof(u32), },
  };
  
  static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
  			     void *arg)
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
397
  	struct net *net = sock_net(skb->sk);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
  	struct ifaddrlblmsg *ifal;
  	struct nlattr *tb[IFAL_MAX+1];
  	struct in6_addr *pfx;
  	u32 label;
  	int err = 0;
  
  	err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
  	if (err < 0)
  		return err;
  
  	ifal = nlmsg_data(nlh);
  
  	if (ifal->ifal_family != AF_INET6 ||
  	    ifal->ifal_prefixlen > 128)
  		return -EINVAL;
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  	if (!tb[IFAL_ADDRESS])
  		return -EINVAL;
  
  	pfx = nla_data(tb[IFAL_ADDRESS]);
  	if (!pfx)
  		return -EINVAL;
  
  	if (!tb[IFAL_LABEL])
  		return -EINVAL;
  	label = nla_get_u32(tb[IFAL_LABEL]);
  	if (label == IPV6_ADDR_LABEL_DEFAULT)
  		return -EINVAL;
  
  	switch(nlh->nlmsg_type) {
  	case RTM_NEWADDRLABEL:
0771275b2   Florian Westphal   ipv6 addrlabel: p...
428
429
430
  		if (ifal->ifal_index &&
  		    !__dev_get_by_index(net, ifal->ifal_index))
  			return -EINVAL;
3de232554   Benjamin Thery   ipv6 netns: Addre...
431
  		err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
432
433
434
435
  				     ifal->ifal_index, label,
  				     nlh->nlmsg_flags & NLM_F_REPLACE);
  		break;
  	case RTM_DELADDRLABEL:
3de232554   Benjamin Thery   ipv6 netns: Addre...
436
  		err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen,
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
  				     ifal->ifal_index);
  		break;
  	default:
  		err = -EOPNOTSUPP;
  	}
  	return err;
  }
  
  static inline void ip6addrlbl_putmsg(struct nlmsghdr *nlh,
  				     int prefixlen, int ifindex, u32 lseq)
  {
  	struct ifaddrlblmsg *ifal = nlmsg_data(nlh);
  	ifal->ifal_family = AF_INET6;
  	ifal->ifal_prefixlen = prefixlen;
  	ifal->ifal_flags = 0;
  	ifal->ifal_index = ifindex;
  	ifal->ifal_seq = lseq;
  };
  
  static int ip6addrlbl_fill(struct sk_buff *skb,
  			   struct ip6addrlbl_entry *p,
  			   u32 lseq,
  			   u32 pid, u32 seq, int event,
  			   unsigned int flags)
  {
  	struct nlmsghdr *nlh = nlmsg_put(skb, pid, seq, event,
  					 sizeof(struct ifaddrlblmsg), flags);
  	if (!nlh)
  		return -EMSGSIZE;
  
  	ip6addrlbl_putmsg(nlh, p->prefixlen, p->ifindex, lseq);
  
  	if (nla_put(skb, IFAL_ADDRESS, 16, &p->prefix) < 0 ||
  	    nla_put_u32(skb, IFAL_LABEL, p->label) < 0) {
  		nlmsg_cancel(skb, nlh);
  		return -EMSGSIZE;
  	}
  
  	return nlmsg_end(skb, nlh);
  }
  
  static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
480
  	struct net *net = sock_net(skb->sk);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
481
482
483
484
485
486
487
  	struct ip6addrlbl_entry *p;
  	struct hlist_node *pos;
  	int idx = 0, s_idx = cb->args[0];
  	int err;
  
  	rcu_read_lock();
  	hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
3de232554   Benjamin Thery   ipv6 netns: Addre...
488
489
  		if (idx >= s_idx &&
  		    net_eq(ip6addrlbl_net(p), net)) {
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  			if ((err = ip6addrlbl_fill(skb, p,
  						   ip6addrlbl_table.seq,
  						   NETLINK_CB(cb->skb).pid,
  						   cb->nlh->nlmsg_seq,
  						   RTM_NEWADDRLABEL,
  						   NLM_F_MULTI)) <= 0)
  				break;
  		}
  		idx++;
  	}
  	rcu_read_unlock();
  	cb->args[0] = idx;
  	return skb->len;
  }
  
  static inline int ip6addrlbl_msgsize(void)
  {
a02cec215   Eric Dumazet   net: return opera...
507
  	return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
508
  		+ nla_total_size(16)	/* IFAL_ADDRESS */
a02cec215   Eric Dumazet   net: return opera...
509
  		+ nla_total_size(4);	/* IFAL_LABEL */
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
510
511
512
513
514
  }
  
  static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
  			  void *arg)
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
515
  	struct net *net = sock_net(in_skb->sk);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
  	struct ifaddrlblmsg *ifal;
  	struct nlattr *tb[IFAL_MAX+1];
  	struct in6_addr *addr;
  	u32 lseq;
  	int err = 0;
  	struct ip6addrlbl_entry *p;
  	struct sk_buff *skb;
  
  	err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
  	if (err < 0)
  		return err;
  
  	ifal = nlmsg_data(nlh);
  
  	if (ifal->ifal_family != AF_INET6 ||
  	    ifal->ifal_prefixlen != 128)
  		return -EINVAL;
  
  	if (ifal->ifal_index &&
3de232554   Benjamin Thery   ipv6 netns: Addre...
535
  	    !__dev_get_by_index(net, ifal->ifal_index))
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
536
537
538
539
540
541
542
543
544
545
  		return -EINVAL;
  
  	if (!tb[IFAL_ADDRESS])
  		return -EINVAL;
  
  	addr = nla_data(tb[IFAL_ADDRESS]);
  	if (!addr)
  		return -EINVAL;
  
  	rcu_read_lock();
3de232554   Benjamin Thery   ipv6 netns: Addre...
546
  	p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
  	if (p && ip6addrlbl_hold(p))
  		p = NULL;
  	lseq = ip6addrlbl_table.seq;
  	rcu_read_unlock();
  
  	if (!p) {
  		err = -ESRCH;
  		goto out;
  	}
  
  	if (!(skb = nlmsg_new(ip6addrlbl_msgsize(), GFP_KERNEL))) {
  		ip6addrlbl_put(p);
  		return -ENOBUFS;
  	}
  
  	err = ip6addrlbl_fill(skb, p, lseq,
  			      NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
  			      RTM_NEWADDRLABEL, 0);
  
  	ip6addrlbl_put(p);
  
  	if (err < 0) {
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto out;
  	}
3de232554   Benjamin Thery   ipv6 netns: Addre...
573
  	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
574
575
576
577
578
579
  out:
  	return err;
  }
  
  void __init ipv6_addr_label_rtnl_register(void)
  {
c7ac8679b   Greg Rose   rtnetlink: Comput...
580
581
582
583
584
585
  	__rtnl_register(PF_INET6, RTM_NEWADDRLABEL, ip6addrlbl_newdel,
  			NULL, NULL);
  	__rtnl_register(PF_INET6, RTM_DELADDRLABEL, ip6addrlbl_newdel,
  			NULL, NULL);
  	__rtnl_register(PF_INET6, RTM_GETADDRLABEL, ip6addrlbl_get,
  			ip6addrlbl_dump, NULL);
2a8cc6c89   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
586
  }