Blame view

net/core/rtnetlink.c 33.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * INET		An implementation of the TCP/IP protocol suite for the LINUX
   *		operating system.  INET is implemented using the  BSD Socket
   *		interface as the means of communication with the user level.
   *
   *		Routing netlink socket interface: protocol independent part.
   *
   * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   *
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   *
   *	Fixes:
   *	Vitaly E. Lavrov		RTA_OK arithmetics was wrong.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
  #include <linux/errno.h>
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/socket.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
30
31
32
33
34
  #include <linux/timer.h>
  #include <linux/string.h>
  #include <linux/sockios.h>
  #include <linux/net.h>
  #include <linux/fcntl.h>
  #include <linux/mm.h>
  #include <linux/slab.h>
  #include <linux/interrupt.h>
  #include <linux/capability.h>
  #include <linux/skbuff.h>
  #include <linux/init.h>
  #include <linux/security.h>
6756ae4b4   Stephen Hemminger   [NET]: Convert RT...
35
  #include <linux/mutex.h>
1823730fb   Thomas Graf   [IPv4]: Move inte...
36
  #include <linux/if_addr.h>
d8a5ec672   Eric W. Biederman   [NET]: netlink su...
37
  #include <linux/nsproxy.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  
  #include <asm/uaccess.h>
  #include <asm/system.h>
  #include <asm/string.h>
  
  #include <linux/inet.h>
  #include <linux/netdevice.h>
  #include <net/ip.h>
  #include <net/protocol.h>
  #include <net/arp.h>
  #include <net/route.h>
  #include <net/udp.h>
  #include <net/sock.h>
  #include <net/pkt_sched.h>
14c0b97dd   Thomas Graf   [NET]: Protocol I...
52
  #include <net/fib_rules.h>
e28498638   Thomas Graf   [RTNL]: Message h...
53
  #include <net/rtnetlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

e28498638   Thomas Graf   [RTNL]: Message h...
55
56
57
58
59
  struct rtnl_link
  {
  	rtnl_doit_func		doit;
  	rtnl_dumpit_func	dumpit;
  };
6756ae4b4   Stephen Hemminger   [NET]: Convert RT...
60
  static DEFINE_MUTEX(rtnl_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
  
  void rtnl_lock(void)
  {
6756ae4b4   Stephen Hemminger   [NET]: Convert RT...
64
  	mutex_lock(&rtnl_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  }
6756ae4b4   Stephen Hemminger   [NET]: Convert RT...
66
  void __rtnl_unlock(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  {
6756ae4b4   Stephen Hemminger   [NET]: Convert RT...
68
  	mutex_unlock(&rtnl_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  }
6756ae4b4   Stephen Hemminger   [NET]: Convert RT...
70

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
  void rtnl_unlock(void)
  {
58ec3b4db   Herbert Xu   net: Fix netdev_r...
73
  	/* This fellow will unlock it for us. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
  	netdev_run_todo();
  }
6756ae4b4   Stephen Hemminger   [NET]: Convert RT...
76
77
78
79
  int rtnl_trylock(void)
  {
  	return mutex_trylock(&rtnl_mutex);
  }
c9c1014b2   Patrick McHardy   [RTNETLINK]: Fix ...
80
81
82
83
  int rtnl_is_locked(void)
  {
  	return mutex_is_locked(&rtnl_mutex);
  }
42bad1da5   Adrian Bunk   [NETLINK]: Possib...
84
  static struct rtnl_link *rtnl_msg_handlers[NPROTO];
e28498638   Thomas Graf   [RTNL]: Message h...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  
  static inline int rtm_msgindex(int msgtype)
  {
  	int msgindex = msgtype - RTM_BASE;
  
  	/*
  	 * msgindex < 0 implies someone tried to register a netlink
  	 * control code. msgindex >= RTM_NR_MSGTYPES may indicate that
  	 * the message type has not been added to linux/rtnetlink.h
  	 */
  	BUG_ON(msgindex < 0 || msgindex >= RTM_NR_MSGTYPES);
  
  	return msgindex;
  }
  
  static rtnl_doit_func rtnl_get_doit(int protocol, int msgindex)
  {
  	struct rtnl_link *tab;
  
  	tab = rtnl_msg_handlers[protocol];
51057f2fe   Thomas Graf   [RTNL]: Properly ...
105
  	if (tab == NULL || tab[msgindex].doit == NULL)
e28498638   Thomas Graf   [RTNL]: Message h...
106
  		tab = rtnl_msg_handlers[PF_UNSPEC];
51057f2fe   Thomas Graf   [RTNL]: Properly ...
107
  	return tab ? tab[msgindex].doit : NULL;
e28498638   Thomas Graf   [RTNL]: Message h...
108
109
110
111
112
113
114
  }
  
  static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex)
  {
  	struct rtnl_link *tab;
  
  	tab = rtnl_msg_handlers[protocol];
51057f2fe   Thomas Graf   [RTNL]: Properly ...
115
  	if (tab == NULL || tab[msgindex].dumpit == NULL)
e28498638   Thomas Graf   [RTNL]: Message h...
116
  		tab = rtnl_msg_handlers[PF_UNSPEC];
51057f2fe   Thomas Graf   [RTNL]: Properly ...
117
  	return tab ? tab[msgindex].dumpit : NULL;
e28498638   Thomas Graf   [RTNL]: Message h...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
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
226
227
  }
  
  /**
   * __rtnl_register - Register a rtnetlink message type
   * @protocol: Protocol family or PF_UNSPEC
   * @msgtype: rtnetlink message type
   * @doit: Function pointer called for each request message
   * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
   *
   * Registers the specified function pointers (at least one of them has
   * to be non-NULL) to be called whenever a request message for the
   * specified protocol family and message type is received.
   *
   * The special protocol family PF_UNSPEC may be used to define fallback
   * function pointers for the case when no entry for the specific protocol
   * family exists.
   *
   * Returns 0 on success or a negative error code.
   */
  int __rtnl_register(int protocol, int msgtype,
  		    rtnl_doit_func doit, rtnl_dumpit_func dumpit)
  {
  	struct rtnl_link *tab;
  	int msgindex;
  
  	BUG_ON(protocol < 0 || protocol >= NPROTO);
  	msgindex = rtm_msgindex(msgtype);
  
  	tab = rtnl_msg_handlers[protocol];
  	if (tab == NULL) {
  		tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL);
  		if (tab == NULL)
  			return -ENOBUFS;
  
  		rtnl_msg_handlers[protocol] = tab;
  	}
  
  	if (doit)
  		tab[msgindex].doit = doit;
  
  	if (dumpit)
  		tab[msgindex].dumpit = dumpit;
  
  	return 0;
  }
  
  EXPORT_SYMBOL_GPL(__rtnl_register);
  
  /**
   * rtnl_register - Register a rtnetlink message type
   *
   * Identical to __rtnl_register() but panics on failure. This is useful
   * as failure of this function is very unlikely, it can only happen due
   * to lack of memory when allocating the chain to store all message
   * handlers for a protocol. Meant for use in init functions where lack
   * of memory implies no sense in continueing.
   */
  void rtnl_register(int protocol, int msgtype,
  		   rtnl_doit_func doit, rtnl_dumpit_func dumpit)
  {
  	if (__rtnl_register(protocol, msgtype, doit, dumpit) < 0)
  		panic("Unable to register rtnetlink message handler, "
  		      "protocol = %d, message type = %d
  ",
  		      protocol, msgtype);
  }
  
  EXPORT_SYMBOL_GPL(rtnl_register);
  
  /**
   * rtnl_unregister - Unregister a rtnetlink message type
   * @protocol: Protocol family or PF_UNSPEC
   * @msgtype: rtnetlink message type
   *
   * Returns 0 on success or a negative error code.
   */
  int rtnl_unregister(int protocol, int msgtype)
  {
  	int msgindex;
  
  	BUG_ON(protocol < 0 || protocol >= NPROTO);
  	msgindex = rtm_msgindex(msgtype);
  
  	if (rtnl_msg_handlers[protocol] == NULL)
  		return -ENOENT;
  
  	rtnl_msg_handlers[protocol][msgindex].doit = NULL;
  	rtnl_msg_handlers[protocol][msgindex].dumpit = NULL;
  
  	return 0;
  }
  
  EXPORT_SYMBOL_GPL(rtnl_unregister);
  
  /**
   * rtnl_unregister_all - Unregister all rtnetlink message type of a protocol
   * @protocol : Protocol family or PF_UNSPEC
   *
   * Identical to calling rtnl_unregster() for all registered message types
   * of a certain protocol family.
   */
  void rtnl_unregister_all(int protocol)
  {
  	BUG_ON(protocol < 0 || protocol >= NPROTO);
  
  	kfree(rtnl_msg_handlers[protocol]);
  	rtnl_msg_handlers[protocol] = NULL;
  }
  
  EXPORT_SYMBOL_GPL(rtnl_unregister_all);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228

38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  static LIST_HEAD(link_ops);
  
  /**
   * __rtnl_link_register - Register rtnl_link_ops with rtnetlink.
   * @ops: struct rtnl_link_ops * to register
   *
   * The caller must hold the rtnl_mutex. This function should be used
   * by drivers that create devices during module initialization. It
   * must be called before registering the devices.
   *
   * Returns 0 on success or a negative error code.
   */
  int __rtnl_link_register(struct rtnl_link_ops *ops)
  {
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
243
244
  	if (!ops->dellink)
  		ops->dellink = unregister_netdevice;
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  	list_add_tail(&ops->list, &link_ops);
  	return 0;
  }
  
  EXPORT_SYMBOL_GPL(__rtnl_link_register);
  
  /**
   * rtnl_link_register - Register rtnl_link_ops with rtnetlink.
   * @ops: struct rtnl_link_ops * to register
   *
   * Returns 0 on success or a negative error code.
   */
  int rtnl_link_register(struct rtnl_link_ops *ops)
  {
  	int err;
  
  	rtnl_lock();
  	err = __rtnl_link_register(ops);
  	rtnl_unlock();
  	return err;
  }
  
  EXPORT_SYMBOL_GPL(rtnl_link_register);
669f87baa   Pavel Emelyanov   [RTNL]: Introduce...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops)
  {
  	struct net_device *dev;
  restart:
  	for_each_netdev(net, dev) {
  		if (dev->rtnl_link_ops == ops) {
  			ops->dellink(dev);
  			goto restart;
  		}
  	}
  }
  
  void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops)
  {
  	rtnl_lock();
  	__rtnl_kill_links(net, ops);
  	rtnl_unlock();
  }
  EXPORT_SYMBOL_GPL(rtnl_kill_links);
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
287
288
289
290
  /**
   * __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink.
   * @ops: struct rtnl_link_ops * to unregister
   *
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
291
   * The caller must hold the rtnl_mutex.
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
292
293
294
   */
  void __rtnl_link_unregister(struct rtnl_link_ops *ops)
  {
881d966b4   Eric W. Biederman   [NET]: Make the d...
295
  	struct net *net;
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
296

881d966b4   Eric W. Biederman   [NET]: Make the d...
297
  	for_each_net(net) {
669f87baa   Pavel Emelyanov   [RTNL]: Introduce...
298
  		__rtnl_kill_links(net, ops);
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
299
  	}
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  	list_del(&ops->list);
  }
  
  EXPORT_SYMBOL_GPL(__rtnl_link_unregister);
  
  /**
   * rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink.
   * @ops: struct rtnl_link_ops * to unregister
   */
  void rtnl_link_unregister(struct rtnl_link_ops *ops)
  {
  	rtnl_lock();
  	__rtnl_link_unregister(ops);
  	rtnl_unlock();
  }
  
  EXPORT_SYMBOL_GPL(rtnl_link_unregister);
  
  static const struct rtnl_link_ops *rtnl_link_ops_get(const char *kind)
  {
  	const struct rtnl_link_ops *ops;
  
  	list_for_each_entry(ops, &link_ops, list) {
  		if (!strcmp(ops->kind, kind))
  			return ops;
  	}
  	return NULL;
  }
  
  static size_t rtnl_link_get_size(const struct net_device *dev)
  {
  	const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
  	size_t size;
  
  	if (!ops)
  		return 0;
  
  	size = nlmsg_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */
  	       nlmsg_total_size(strlen(ops->kind) + 1);	 /* IFLA_INFO_KIND */
  
  	if (ops->get_size)
  		/* IFLA_INFO_DATA + nested data */
  		size += nlmsg_total_size(sizeof(struct nlattr)) +
  			ops->get_size(dev);
  
  	if (ops->get_xstats_size)
  		size += ops->get_xstats_size(dev);	/* IFLA_INFO_XSTATS */
  
  	return size;
  }
  
  static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev)
  {
  	const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
  	struct nlattr *linkinfo, *data;
  	int err = -EMSGSIZE;
  
  	linkinfo = nla_nest_start(skb, IFLA_LINKINFO);
  	if (linkinfo == NULL)
  		goto out;
  
  	if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0)
  		goto err_cancel_link;
  	if (ops->fill_xstats) {
  		err = ops->fill_xstats(skb, dev);
  		if (err < 0)
  			goto err_cancel_link;
  	}
  	if (ops->fill_info) {
  		data = nla_nest_start(skb, IFLA_INFO_DATA);
  		if (data == NULL)
  			goto err_cancel_link;
  		err = ops->fill_info(skb, dev);
  		if (err < 0)
  			goto err_cancel_data;
  		nla_nest_end(skb, data);
  	}
  
  	nla_nest_end(skb, linkinfo);
  	return 0;
  
  err_cancel_data:
  	nla_nest_cancel(skb, data);
  err_cancel_link:
  	nla_nest_cancel(skb, linkinfo);
  out:
  	return err;
  }
db46edc6d   Thomas Graf   [RTNETLINK] Clean...
388
  static const int rtm_min[RTM_NR_FAMILIES] =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  {
f90a0a74b   Thomas Graf   [RTNETLINK] Fix &...
390
391
392
  	[RTM_FAM(RTM_NEWLINK)]      = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
  	[RTM_FAM(RTM_NEWADDR)]      = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
  	[RTM_FAM(RTM_NEWROUTE)]     = NLMSG_LENGTH(sizeof(struct rtmsg)),
14c0b97dd   Thomas Graf   [NET]: Protocol I...
393
  	[RTM_FAM(RTM_NEWRULE)]      = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
f90a0a74b   Thomas Graf   [RTNETLINK] Fix &...
394
395
396
397
  	[RTM_FAM(RTM_NEWQDISC)]     = NLMSG_LENGTH(sizeof(struct tcmsg)),
  	[RTM_FAM(RTM_NEWTCLASS)]    = NLMSG_LENGTH(sizeof(struct tcmsg)),
  	[RTM_FAM(RTM_NEWTFILTER)]   = NLMSG_LENGTH(sizeof(struct tcmsg)),
  	[RTM_FAM(RTM_NEWACTION)]    = NLMSG_LENGTH(sizeof(struct tcamsg)),
f90a0a74b   Thomas Graf   [RTNETLINK] Fix &...
398
399
  	[RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
  	[RTM_FAM(RTM_GETANYCAST)]   = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  };
db46edc6d   Thomas Graf   [RTNETLINK] Clean...
401
  static const int rta_max[RTM_NR_FAMILIES] =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  {
f90a0a74b   Thomas Graf   [RTNETLINK] Fix &...
403
404
405
  	[RTM_FAM(RTM_NEWLINK)]      = IFLA_MAX,
  	[RTM_FAM(RTM_NEWADDR)]      = IFA_MAX,
  	[RTM_FAM(RTM_NEWROUTE)]     = RTA_MAX,
14c0b97dd   Thomas Graf   [NET]: Protocol I...
406
  	[RTM_FAM(RTM_NEWRULE)]      = FRA_MAX,
f90a0a74b   Thomas Graf   [RTNETLINK] Fix &...
407
408
409
410
  	[RTM_FAM(RTM_NEWQDISC)]     = TCA_MAX,
  	[RTM_FAM(RTM_NEWTCLASS)]    = TCA_MAX,
  	[RTM_FAM(RTM_NEWTFILTER)]   = TCA_MAX,
  	[RTM_FAM(RTM_NEWACTION)]    = TCAA_MAX,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
417
418
419
420
421
  };
  
  void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
  {
  	struct rtattr *rta;
  	int size = RTA_LENGTH(attrlen);
  
  	rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size));
  	rta->rta_type = attrtype;
  	rta->rta_len = size;
  	memcpy(RTA_DATA(rta), data, attrlen);
b3563c4fb   Patrick McHardy   [NETLINK]: Clear ...
422
  	memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  }
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
424
  int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
  {
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
426
  	struct sock *rtnl = net->rtnl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
  	int err = 0;
ac6d439d2   Patrick McHardy   [NETLINK]: Conver...
428
  	NETLINK_CB(skb).dst_group = group;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
433
434
435
  	if (echo)
  		atomic_inc(&skb->users);
  	netlink_broadcast(rtnl, skb, pid, group, GFP_KERNEL);
  	if (echo)
  		err = netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
  	return err;
  }
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
436
  int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid)
2942e9005   Thomas Graf   [RTNETLINK]: Use ...
437
  {
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
438
  	struct sock *rtnl = net->rtnl;
2942e9005   Thomas Graf   [RTNETLINK]: Use ...
439
440
  	return nlmsg_unicast(rtnl, skb, pid);
  }
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
441
442
  void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
  		 struct nlmsghdr *nlh, gfp_t flags)
97676b6b5   Thomas Graf   [RTNETLINK]: Add ...
443
  {
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
444
  	struct sock *rtnl = net->rtnl;
97676b6b5   Thomas Graf   [RTNETLINK]: Add ...
445
446
447
448
  	int report = 0;
  
  	if (nlh)
  		report = nlmsg_report(nlh);
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
449
  	nlmsg_notify(rtnl, skb, pid, group, report, flags);
97676b6b5   Thomas Graf   [RTNETLINK]: Add ...
450
  }
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
451
  void rtnl_set_sk_err(struct net *net, u32 group, int error)
97676b6b5   Thomas Graf   [RTNETLINK]: Add ...
452
  {
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
453
  	struct sock *rtnl = net->rtnl;
97676b6b5   Thomas Graf   [RTNETLINK]: Add ...
454
455
  	netlink_set_err(rtnl, 0, group, error);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
  int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics)
  {
2d7202bfd   Thomas Graf   [IPv6] route: Con...
458
459
460
461
462
463
464
465
466
467
468
469
  	struct nlattr *mx;
  	int i, valid = 0;
  
  	mx = nla_nest_start(skb, RTA_METRICS);
  	if (mx == NULL)
  		return -ENOBUFS;
  
  	for (i = 0; i < RTAX_MAX; i++) {
  		if (metrics[i]) {
  			valid++;
  			NLA_PUT_U32(skb, i+1, metrics[i]);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471

a57d27fc7   David S. Miller   [RTNETLINK]: Don'...
472
473
474
475
  	if (!valid) {
  		nla_nest_cancel(skb, mx);
  		return 0;
  	}
2d7202bfd   Thomas Graf   [IPv6] route: Con...
476
477
478
479
  
  	return nla_nest_end(skb, mx);
  
  nla_put_failure:
bc3ed28ca   Thomas Graf   netlink: Improve ...
480
481
  	nla_nest_cancel(skb, mx);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  }
e3703b3de   Thomas Graf   [RTNETLINK]: Add ...
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
  int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id,
  		       u32 ts, u32 tsage, long expires, u32 error)
  {
  	struct rta_cacheinfo ci = {
  		.rta_lastuse = jiffies_to_clock_t(jiffies - dst->lastuse),
  		.rta_used = dst->__use,
  		.rta_clntref = atomic_read(&(dst->__refcnt)),
  		.rta_error = error,
  		.rta_id =  id,
  		.rta_ts = ts,
  		.rta_tsage = tsage,
  	};
  
  	if (expires)
  		ci.rta_expires = jiffies_to_clock_t(expires);
  
  	return nla_put(skb, RTA_CACHEINFO, sizeof(ci), &ci);
  }
  
  EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503

93b2d4a20   David S. Miller   Revert "[RTNETLIN...
504
  static void set_operstate(struct net_device *dev, unsigned char transition)
b00055aac   Stefan Rompf   [NET] core: add R...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
  {
  	unsigned char operstate = dev->operstate;
  
  	switch(transition) {
  	case IF_OPER_UP:
  		if ((operstate == IF_OPER_DORMANT ||
  		     operstate == IF_OPER_UNKNOWN) &&
  		    !netif_dormant(dev))
  			operstate = IF_OPER_UP;
  		break;
  
  	case IF_OPER_DORMANT:
  		if (operstate == IF_OPER_UP ||
  		    operstate == IF_OPER_UNKNOWN)
  			operstate = IF_OPER_DORMANT;
  		break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
521
  	}
b00055aac   Stefan Rompf   [NET] core: add R...
522
523
524
525
526
  
  	if (dev->operstate != operstate) {
  		write_lock_bh(&dev_base_lock);
  		dev->operstate = operstate;
  		write_unlock_bh(&dev_base_lock);
93b2d4a20   David S. Miller   Revert "[RTNETLIN...
527
528
  		netdev_state_change(dev);
  	}
b00055aac   Stefan Rompf   [NET] core: add R...
529
  }
b60c5115f   Thomas Graf   [NET]: Convert li...
530
  static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
eeda3fd64   Stephen Hemminger   netdev: introduce...
531
  				 const struct net_device_stats *b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  {
b60c5115f   Thomas Graf   [NET]: Convert li...
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
  	a->rx_packets = b->rx_packets;
  	a->tx_packets = b->tx_packets;
  	a->rx_bytes = b->rx_bytes;
  	a->tx_bytes = b->tx_bytes;
  	a->rx_errors = b->rx_errors;
  	a->tx_errors = b->tx_errors;
  	a->rx_dropped = b->rx_dropped;
  	a->tx_dropped = b->tx_dropped;
  
  	a->multicast = b->multicast;
  	a->collisions = b->collisions;
  
  	a->rx_length_errors = b->rx_length_errors;
  	a->rx_over_errors = b->rx_over_errors;
  	a->rx_crc_errors = b->rx_crc_errors;
  	a->rx_frame_errors = b->rx_frame_errors;
  	a->rx_fifo_errors = b->rx_fifo_errors;
  	a->rx_missed_errors = b->rx_missed_errors;
  
  	a->tx_aborted_errors = b->tx_aborted_errors;
  	a->tx_carrier_errors = b->tx_carrier_errors;
  	a->tx_fifo_errors = b->tx_fifo_errors;
  	a->tx_heartbeat_errors = b->tx_heartbeat_errors;
  	a->tx_window_errors = b->tx_window_errors;
  
  	a->rx_compressed = b->rx_compressed;
  	a->tx_compressed = b->tx_compressed;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561

38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
562
  static inline size_t if_nlmsg_size(const struct net_device *dev)
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
563
564
565
  {
  	return NLMSG_ALIGN(sizeof(struct ifinfomsg))
  	       + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
0b815a1a6   Stephen Hemminger   net: network devi...
566
  	       + nla_total_size(IFALIASZ) /* IFLA_IFALIAS */
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
567
568
569
570
571
572
573
574
575
576
577
  	       + nla_total_size(IFNAMSIZ) /* IFLA_QDISC */
  	       + nla_total_size(sizeof(struct rtnl_link_ifmap))
  	       + nla_total_size(sizeof(struct rtnl_link_stats))
  	       + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
  	       + nla_total_size(MAX_ADDR_LEN) /* IFLA_BROADCAST */
  	       + nla_total_size(4) /* IFLA_TXQLEN */
  	       + nla_total_size(4) /* IFLA_WEIGHT */
  	       + nla_total_size(4) /* IFLA_MTU */
  	       + nla_total_size(4) /* IFLA_LINK */
  	       + nla_total_size(4) /* IFLA_MASTER */
  	       + nla_total_size(1) /* IFLA_OPERSTATE */
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
578
579
  	       + nla_total_size(1) /* IFLA_LINKMODE */
  	       + rtnl_link_get_size(dev); /* IFLA_LINKINFO */
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
580
  }
b60c5115f   Thomas Graf   [NET]: Convert li...
581
  static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
575c3e2a0   Patrick McHardy   [RTNETLINK]: Remo...
582
583
  			    int type, u32 pid, u32 seq, u32 change,
  			    unsigned int flags)
b60c5115f   Thomas Graf   [NET]: Convert li...
584
  {
b0e1e6462   David S. Miller   netdev: Move rest...
585
  	struct netdev_queue *txq;
b60c5115f   Thomas Graf   [NET]: Convert li...
586
587
  	struct ifinfomsg *ifm;
  	struct nlmsghdr *nlh;
eeda3fd64   Stephen Hemminger   netdev: introduce...
588
  	const struct net_device_stats *stats;
96e74088f   Pavel Emelyanov   net: The dev->get...
589
  	struct nlattr *attr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590

b60c5115f   Thomas Graf   [NET]: Convert li...
591
592
  	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
  	if (nlh == NULL)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
593
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594

b60c5115f   Thomas Graf   [NET]: Convert li...
595
596
597
598
599
600
601
602
603
604
  	ifm = nlmsg_data(nlh);
  	ifm->ifi_family = AF_UNSPEC;
  	ifm->__ifi_pad = 0;
  	ifm->ifi_type = dev->type;
  	ifm->ifi_index = dev->ifindex;
  	ifm->ifi_flags = dev_get_flags(dev);
  	ifm->ifi_change = change;
  
  	NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
  	NLA_PUT_U32(skb, IFLA_TXQLEN, dev->tx_queue_len);
b60c5115f   Thomas Graf   [NET]: Convert li...
605
606
607
608
609
610
611
612
613
614
  	NLA_PUT_U8(skb, IFLA_OPERSTATE,
  		   netif_running(dev) ? dev->operstate : IF_OPER_DOWN);
  	NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode);
  	NLA_PUT_U32(skb, IFLA_MTU, dev->mtu);
  
  	if (dev->ifindex != dev->iflink)
  		NLA_PUT_U32(skb, IFLA_LINK, dev->iflink);
  
  	if (dev->master)
  		NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615

e8a0464cc   David S. Miller   netdev: Allocate ...
616
  	txq = netdev_get_tx_queue(dev, 0);
b0e1e6462   David S. Miller   netdev: Move rest...
617
618
  	if (txq->qdisc_sleeping)
  		NLA_PUT_STRING(skb, IFLA_QDISC, txq->qdisc_sleeping->ops->id);
b00055aac   Stefan Rompf   [NET] core: add R...
619

0b815a1a6   Stephen Hemminger   net: network devi...
620
621
  	if (dev->ifalias)
  		NLA_PUT_STRING(skb, IFLA_IFALIAS, dev->ifalias);
b00055aac   Stefan Rompf   [NET] core: add R...
622
  	if (1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
625
626
627
628
629
630
  		struct rtnl_link_ifmap map = {
  			.mem_start   = dev->mem_start,
  			.mem_end     = dev->mem_end,
  			.base_addr   = dev->base_addr,
  			.irq         = dev->irq,
  			.dma         = dev->dma,
  			.port        = dev->if_port,
  		};
b60c5115f   Thomas Graf   [NET]: Convert li...
631
  		NLA_PUT(skb, IFLA_MAP, sizeof(map), &map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
  	}
  
  	if (dev->addr_len) {
b60c5115f   Thomas Graf   [NET]: Convert li...
635
636
  		NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
  		NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
  	}
96e74088f   Pavel Emelyanov   net: The dev->get...
638
639
640
641
  	attr = nla_reserve(skb, IFLA_STATS,
  			sizeof(struct rtnl_link_stats));
  	if (attr == NULL)
  		goto nla_put_failure;
b60c5115f   Thomas Graf   [NET]: Convert li...
642

eeda3fd64   Stephen Hemminger   netdev: introduce...
643
  	stats = dev_get_stats(dev);
96e74088f   Pavel Emelyanov   net: The dev->get...
644
  	copy_rtnl_link_stats(nla_data(attr), stats);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645

38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
646
647
648
649
  	if (dev->rtnl_link_ops) {
  		if (rtnl_link_fill(skb, dev) < 0)
  			goto nla_put_failure;
  	}
b60c5115f   Thomas Graf   [NET]: Convert li...
650
651
652
  	return nlmsg_end(skb, nlh);
  
  nla_put_failure:
26932566a   Patrick McHardy   [NETLINK]: Don't ...
653
654
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
  }
b60c5115f   Thomas Graf   [NET]: Convert li...
656
  static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
658
  	struct net *net = sock_net(skb->sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
  	int idx;
  	int s_idx = cb->args[0];
  	struct net_device *dev;
7562f876c   Pavel Emelianov   [NET]: Rework dev...
662
  	idx = 0;
881d966b4   Eric W. Biederman   [NET]: Make the d...
663
  	for_each_netdev(net, dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  		if (idx < s_idx)
7562f876c   Pavel Emelianov   [NET]: Rework dev...
665
  			goto cont;
575c3e2a0   Patrick McHardy   [RTNETLINK]: Remo...
666
  		if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
b60c5115f   Thomas Graf   [NET]: Convert li...
667
668
  				     NETLINK_CB(cb->skb).pid,
  				     cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  			break;
7562f876c   Pavel Emelianov   [NET]: Rework dev...
670
671
  cont:
  		idx++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
675
676
  	cb->args[0] = idx;
  
  	return skb->len;
  }
e71992889   Pavel Emelianov   [RTNETLINK]: Intr...
677
  const struct nla_policy ifla_policy[IFLA_MAX+1] = {
5176f91ea   Thomas Graf   [NETLINK]: Make u...
678
  	[IFLA_IFNAME]		= { .type = NLA_STRING, .len = IFNAMSIZ-1 },
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
679
680
  	[IFLA_ADDRESS]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
  	[IFLA_BROADCAST]	= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
5176f91ea   Thomas Graf   [NETLINK]: Make u...
681
  	[IFLA_MAP]		= { .len = sizeof(struct rtnl_link_ifmap) },
da5e0494c   Thomas Graf   [NET]: Convert li...
682
  	[IFLA_MTU]		= { .type = NLA_U32 },
76e87306c   Thomas Graf   [RTNL]: Add missi...
683
  	[IFLA_LINK]		= { .type = NLA_U32 },
da5e0494c   Thomas Graf   [NET]: Convert li...
684
685
686
687
  	[IFLA_TXQLEN]		= { .type = NLA_U32 },
  	[IFLA_WEIGHT]		= { .type = NLA_U32 },
  	[IFLA_OPERSTATE]	= { .type = NLA_U8 },
  	[IFLA_LINKMODE]		= { .type = NLA_U8 },
76e87306c   Thomas Graf   [RTNL]: Add missi...
688
  	[IFLA_LINKINFO]		= { .type = NLA_NESTED },
d8a5ec672   Eric W. Biederman   [NET]: netlink su...
689
  	[IFLA_NET_NS_PID]	= { .type = NLA_U32 },
0b815a1a6   Stephen Hemminger   net: network devi...
690
  	[IFLA_IFALIAS]	        = { .type = NLA_STRING, .len = IFALIASZ-1 },
da5e0494c   Thomas Graf   [NET]: Convert li...
691
  };
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
692
693
694
695
  static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
  	[IFLA_INFO_KIND]	= { .type = NLA_STRING },
  	[IFLA_INFO_DATA]	= { .type = NLA_NESTED },
  };
d8a5ec672   Eric W. Biederman   [NET]: netlink su...
696
697
698
699
700
701
702
703
  static struct net *get_net_ns_by_pid(pid_t pid)
  {
  	struct task_struct *tsk;
  	struct net *net;
  
  	/* Lookup the network namespace */
  	net = ERR_PTR(-ESRCH);
  	rcu_read_lock();
ceaa79c43   Eric W. Biederman   [NETNS]: Fix get_...
704
  	tsk = find_task_by_vpid(pid);
d8a5ec672   Eric W. Biederman   [NET]: netlink su...
705
  	if (tsk) {
cf7b708c8   Pavel Emelyanov   Make access to ta...
706
707
708
709
  		struct nsproxy *nsproxy;
  		nsproxy = task_nsproxy(tsk);
  		if (nsproxy)
  			net = get_net(nsproxy->net_ns);
d8a5ec672   Eric W. Biederman   [NET]: netlink su...
710
711
712
713
  	}
  	rcu_read_unlock();
  	return net;
  }
1840bb13c   Thomas Graf   [RTNL]: Validate ...
714
715
716
717
718
719
720
721
722
723
724
725
726
727
  static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
  {
  	if (dev) {
  		if (tb[IFLA_ADDRESS] &&
  		    nla_len(tb[IFLA_ADDRESS]) < dev->addr_len)
  			return -EINVAL;
  
  		if (tb[IFLA_BROADCAST] &&
  		    nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
  			return -EINVAL;
  	}
  
  	return 0;
  }
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
728
  static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
729
  		      struct nlattr **tb, char *ifname, int modified)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  {
d314774cf   Stephen Hemminger   netdev: network d...
731
  	const struct net_device_ops *ops = dev->netdev_ops;
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
732
  	int send_addr_notify = 0;
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
733
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734

d8a5ec672   Eric W. Biederman   [NET]: netlink su...
735
736
737
738
739
740
741
742
743
744
745
746
747
  	if (tb[IFLA_NET_NS_PID]) {
  		struct net *net;
  		net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID]));
  		if (IS_ERR(net)) {
  			err = PTR_ERR(net);
  			goto errout;
  		}
  		err = dev_change_net_namespace(dev, net, ifname);
  		put_net(net);
  		if (err)
  			goto errout;
  		modified = 1;
  	}
da5e0494c   Thomas Graf   [NET]: Convert li...
748
  	if (tb[IFLA_MAP]) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
  		struct rtnl_link_ifmap *u_map;
  		struct ifmap k_map;
d314774cf   Stephen Hemminger   netdev: network d...
751
  		if (!ops->ndo_set_config) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
  			err = -EOPNOTSUPP;
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
753
  			goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
756
757
  		}
  
  		if (!netif_device_present(dev)) {
  			err = -ENODEV;
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
758
  			goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760

da5e0494c   Thomas Graf   [NET]: Convert li...
761
  		u_map = nla_data(tb[IFLA_MAP]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
764
765
766
767
  		k_map.mem_start = (unsigned long) u_map->mem_start;
  		k_map.mem_end = (unsigned long) u_map->mem_end;
  		k_map.base_addr = (unsigned short) u_map->base_addr;
  		k_map.irq = (unsigned char) u_map->irq;
  		k_map.dma = (unsigned char) u_map->dma;
  		k_map.port = (unsigned char) u_map->port;
d314774cf   Stephen Hemminger   netdev: network d...
768
  		err = ops->ndo_set_config(dev, &k_map);
da5e0494c   Thomas Graf   [NET]: Convert li...
769
  		if (err < 0)
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
770
  			goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771

da5e0494c   Thomas Graf   [NET]: Convert li...
772
  		modified = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  	}
da5e0494c   Thomas Graf   [NET]: Convert li...
774
  	if (tb[IFLA_ADDRESS]) {
70f8e78e1   David S. Miller   [RTNETLINK]: Fix ...
775
776
  		struct sockaddr *sa;
  		int len;
d314774cf   Stephen Hemminger   netdev: network d...
777
  		if (!ops->ndo_set_mac_address) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
  			err = -EOPNOTSUPP;
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
779
  			goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  		}
da5e0494c   Thomas Graf   [NET]: Convert li...
781

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
783
  		if (!netif_device_present(dev)) {
  			err = -ENODEV;
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
784
  			goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786

70f8e78e1   David S. Miller   [RTNETLINK]: Fix ...
787
788
789
790
  		len = sizeof(sa_family_t) + dev->addr_len;
  		sa = kmalloc(len, GFP_KERNEL);
  		if (!sa) {
  			err = -ENOMEM;
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
791
  			goto errout;
70f8e78e1   David S. Miller   [RTNETLINK]: Fix ...
792
793
  		}
  		sa->sa_family = dev->type;
da5e0494c   Thomas Graf   [NET]: Convert li...
794
  		memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
70f8e78e1   David S. Miller   [RTNETLINK]: Fix ...
795
  		       dev->addr_len);
d314774cf   Stephen Hemminger   netdev: network d...
796
  		err = ops->ndo_set_mac_address(dev, sa);
70f8e78e1   David S. Miller   [RTNETLINK]: Fix ...
797
  		kfree(sa);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  		if (err)
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
799
  			goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  		send_addr_notify = 1;
da5e0494c   Thomas Graf   [NET]: Convert li...
801
  		modified = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  	}
da5e0494c   Thomas Graf   [NET]: Convert li...
803
804
805
  	if (tb[IFLA_MTU]) {
  		err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
  		if (err < 0)
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
806
  			goto errout;
da5e0494c   Thomas Graf   [NET]: Convert li...
807
  		modified = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  	}
da5e0494c   Thomas Graf   [NET]: Convert li...
809
810
811
812
813
  	/*
  	 * Interface selected by interface index but interface
  	 * name provided implies that a name change has been
  	 * requested.
  	 */
51055be81   Patrick McHardy   [RTNETLINK]: ifin...
814
  	if (ifm->ifi_index > 0 && ifname[0]) {
da5e0494c   Thomas Graf   [NET]: Convert li...
815
816
  		err = dev_change_name(dev, ifname);
  		if (err < 0)
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
817
  			goto errout;
da5e0494c   Thomas Graf   [NET]: Convert li...
818
  		modified = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
  	}
0b815a1a6   Stephen Hemminger   net: network devi...
820
821
822
823
824
825
826
  	if (tb[IFLA_IFALIAS]) {
  		err = dev_set_alias(dev, nla_data(tb[IFLA_IFALIAS]),
  				    nla_len(tb[IFLA_IFALIAS]));
  		if (err < 0)
  			goto errout;
  		modified = 1;
  	}
da5e0494c   Thomas Graf   [NET]: Convert li...
827
828
829
  	if (tb[IFLA_BROADCAST]) {
  		nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len);
  		send_addr_notify = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
  	}
83b496e92   Patrick McHardy   [RTNETLINK]: Allo...
831
832
833
834
835
836
837
  	if (ifm->ifi_flags || ifm->ifi_change) {
  		unsigned int flags = ifm->ifi_flags;
  
  		/* bugwards compatibility: ifi_change == 0 is treated as ~0 */
  		if (ifm->ifi_change)
  			flags = (flags & ifm->ifi_change) |
  				(dev->flags & ~ifm->ifi_change);
5f9021cfd   Johannes Berg   rtnetlink: propag...
838
839
840
  		err = dev_change_flags(dev, flags);
  		if (err < 0)
  			goto errout;
83b496e92   Patrick McHardy   [RTNETLINK]: Allo...
841
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842

93b2d4a20   David S. Miller   Revert "[RTNETLIN...
843
844
  	if (tb[IFLA_TXQLEN])
  		dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
b00055aac   Stefan Rompf   [NET] core: add R...
845

da5e0494c   Thomas Graf   [NET]: Convert li...
846
  	if (tb[IFLA_OPERSTATE])
93b2d4a20   David S. Miller   Revert "[RTNETLIN...
847
  		set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
b00055aac   Stefan Rompf   [NET] core: add R...
848

da5e0494c   Thomas Graf   [NET]: Convert li...
849
  	if (tb[IFLA_LINKMODE]) {
93b2d4a20   David S. Miller   Revert "[RTNETLIN...
850
851
852
  		write_lock_bh(&dev_base_lock);
  		dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
  		write_unlock_bh(&dev_base_lock);
b00055aac   Stefan Rompf   [NET] core: add R...
853
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
  	err = 0;
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
855
  errout:
da5e0494c   Thomas Graf   [NET]: Convert li...
856
857
858
859
860
861
  	if (err < 0 && modified && net_ratelimit())
  		printk(KERN_WARNING "A link change request failed with "
  		       "some changes comitted already. Interface %s may "
  		       "have been left with an inconsistent configuration, "
  		       "please check.
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
863
  	if (send_addr_notify)
  		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
864
865
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866

0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
867
868
  static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
869
  	struct net *net = sock_net(skb->sk);
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
  	struct ifinfomsg *ifm;
  	struct net_device *dev;
  	int err;
  	struct nlattr *tb[IFLA_MAX+1];
  	char ifname[IFNAMSIZ];
  
  	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
  	if (err < 0)
  		goto errout;
  
  	if (tb[IFLA_IFNAME])
  		nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
  	else
  		ifname[0] = '\0';
  
  	err = -EINVAL;
  	ifm = nlmsg_data(nlh);
  	if (ifm->ifi_index > 0)
881d966b4   Eric W. Biederman   [NET]: Make the d...
888
  		dev = dev_get_by_index(net, ifm->ifi_index);
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
889
  	else if (tb[IFLA_IFNAME])
881d966b4   Eric W. Biederman   [NET]: Make the d...
890
  		dev = dev_get_by_name(net, ifname);
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
891
892
893
894
895
896
897
  	else
  		goto errout;
  
  	if (dev == NULL) {
  		err = -ENODEV;
  		goto errout;
  	}
1840bb13c   Thomas Graf   [RTNL]: Validate ...
898
  	if ((err = validate_linkmsg(dev, tb)) < 0)
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
899
  		goto errout_dev;
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
900
  	err = do_setlink(dev, ifm, tb, ifname, 0);
0157f60c0   Patrick McHardy   [RTNETLINK]: Spli...
901
  errout_dev:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
  	dev_put(dev);
da5e0494c   Thomas Graf   [NET]: Convert li...
903
  errout:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
905
  	return err;
  }
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
906
907
  static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
908
  	struct net *net = sock_net(skb->sk);
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
  	const struct rtnl_link_ops *ops;
  	struct net_device *dev;
  	struct ifinfomsg *ifm;
  	char ifname[IFNAMSIZ];
  	struct nlattr *tb[IFLA_MAX+1];
  	int err;
  
  	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
  	if (err < 0)
  		return err;
  
  	if (tb[IFLA_IFNAME])
  		nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
  
  	ifm = nlmsg_data(nlh);
  	if (ifm->ifi_index > 0)
881d966b4   Eric W. Biederman   [NET]: Make the d...
925
  		dev = __dev_get_by_index(net, ifm->ifi_index);
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
926
  	else if (tb[IFLA_IFNAME])
881d966b4   Eric W. Biederman   [NET]: Make the d...
927
  		dev = __dev_get_by_name(net, ifname);
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
928
929
930
931
932
933
934
935
936
937
938
939
940
  	else
  		return -EINVAL;
  
  	if (!dev)
  		return -ENODEV;
  
  	ops = dev->rtnl_link_ops;
  	if (!ops)
  		return -EOPNOTSUPP;
  
  	ops->dellink(dev);
  	return 0;
  }
881d966b4   Eric W. Biederman   [NET]: Make the d...
941
  struct net_device *rtnl_create_link(struct net *net, char *ifname,
e71992889   Pavel Emelianov   [RTNETLINK]: Intr...
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
  		const struct rtnl_link_ops *ops, struct nlattr *tb[])
  {
  	int err;
  	struct net_device *dev;
  
  	err = -ENOMEM;
  	dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
  	if (!dev)
  		goto err;
  
  	if (strchr(dev->name, '%')) {
  		err = dev_alloc_name(dev, dev->name);
  		if (err < 0)
  			goto err_free;
  	}
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
957
  	dev_net_set(dev, net);
e71992889   Pavel Emelianov   [RTNETLINK]: Intr...
958
959
960
961
962
963
964
965
966
967
968
969
970
  	dev->rtnl_link_ops = ops;
  
  	if (tb[IFLA_MTU])
  		dev->mtu = nla_get_u32(tb[IFLA_MTU]);
  	if (tb[IFLA_ADDRESS])
  		memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
  				nla_len(tb[IFLA_ADDRESS]));
  	if (tb[IFLA_BROADCAST])
  		memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
  				nla_len(tb[IFLA_BROADCAST]));
  	if (tb[IFLA_TXQLEN])
  		dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
  	if (tb[IFLA_OPERSTATE])
93b2d4a20   David S. Miller   Revert "[RTNETLIN...
971
  		set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
e71992889   Pavel Emelianov   [RTNETLINK]: Intr...
972
973
974
975
976
977
978
979
980
981
  	if (tb[IFLA_LINKMODE])
  		dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
  
  	return dev;
  
  err_free:
  	free_netdev(dev);
  err:
  	return ERR_PTR(err);
  }
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
982
983
  static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
984
  	struct net *net = sock_net(skb->sk);
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
985
986
987
988
989
990
991
992
  	const struct rtnl_link_ops *ops;
  	struct net_device *dev;
  	struct ifinfomsg *ifm;
  	char kind[MODULE_NAME_LEN];
  	char ifname[IFNAMSIZ];
  	struct nlattr *tb[IFLA_MAX+1];
  	struct nlattr *linkinfo[IFLA_INFO_MAX+1];
  	int err;
95a5afca4   Johannes Berg   net: Remove CONFI...
993
  #ifdef CONFIG_MODULES
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
994
  replay:
8072f085d   Thomas Graf   [RTNETLINK]: Fix ...
995
  #endif
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
  	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
  	if (err < 0)
  		return err;
  
  	if (tb[IFLA_IFNAME])
  		nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
  	else
  		ifname[0] = '\0';
  
  	ifm = nlmsg_data(nlh);
  	if (ifm->ifi_index > 0)
881d966b4   Eric W. Biederman   [NET]: Make the d...
1007
  		dev = __dev_get_by_index(net, ifm->ifi_index);
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
1008
  	else if (ifname[0])
881d966b4   Eric W. Biederman   [NET]: Make the d...
1009
  		dev = __dev_get_by_name(net, ifname);
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
1010
1011
  	else
  		dev = NULL;
1840bb13c   Thomas Graf   [RTNL]: Validate ...
1012
1013
  	if ((err = validate_linkmsg(dev, tb)) < 0)
  		return err;
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
  	if (tb[IFLA_LINKINFO]) {
  		err = nla_parse_nested(linkinfo, IFLA_INFO_MAX,
  				       tb[IFLA_LINKINFO], ifla_info_policy);
  		if (err < 0)
  			return err;
  	} else
  		memset(linkinfo, 0, sizeof(linkinfo));
  
  	if (linkinfo[IFLA_INFO_KIND]) {
  		nla_strlcpy(kind, linkinfo[IFLA_INFO_KIND], sizeof(kind));
  		ops = rtnl_link_ops_get(kind);
  	} else {
  		kind[0] = '\0';
  		ops = NULL;
  	}
  
  	if (1) {
  		struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL;
  
  		if (ops) {
  			if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
  				err = nla_parse_nested(attr, ops->maxtype,
  						       linkinfo[IFLA_INFO_DATA],
  						       ops->policy);
  				if (err < 0)
  					return err;
  				data = attr;
  			}
  			if (ops->validate) {
  				err = ops->validate(tb, data);
  				if (err < 0)
  					return err;
  			}
  		}
  
  		if (dev) {
  			int modified = 0;
  
  			if (nlh->nlmsg_flags & NLM_F_EXCL)
  				return -EEXIST;
  			if (nlh->nlmsg_flags & NLM_F_REPLACE)
  				return -EOPNOTSUPP;
  
  			if (linkinfo[IFLA_INFO_DATA]) {
  				if (!ops || ops != dev->rtnl_link_ops ||
  				    !ops->changelink)
  					return -EOPNOTSUPP;
  
  				err = ops->changelink(dev, tb, data);
  				if (err < 0)
  					return err;
  				modified = 1;
  			}
  
  			return do_setlink(dev, ifm, tb, ifname, modified);
  		}
  
  		if (!(nlh->nlmsg_flags & NLM_F_CREATE))
  			return -ENODEV;
  
  		if (ifm->ifi_index || ifm->ifi_flags || ifm->ifi_change)
  			return -EOPNOTSUPP;
0e06877c6   Patrick McHardy   [RTNETLINK]: rtnl...
1076
  		if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO])
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
1077
1078
1079
  			return -EOPNOTSUPP;
  
  		if (!ops) {
95a5afca4   Johannes Berg   net: Remove CONFI...
1080
  #ifdef CONFIG_MODULES
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
  			if (kind[0]) {
  				__rtnl_unlock();
  				request_module("rtnl-link-%s", kind);
  				rtnl_lock();
  				ops = rtnl_link_ops_get(kind);
  				if (ops)
  					goto replay;
  			}
  #endif
  			return -EOPNOTSUPP;
  		}
  
  		if (!ifname[0])
  			snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
e71992889   Pavel Emelianov   [RTNETLINK]: Intr...
1095

881d966b4   Eric W. Biederman   [NET]: Make the d...
1096
  		dev = rtnl_create_link(net, ifname, ops, tb);
e71992889   Pavel Emelianov   [RTNETLINK]: Intr...
1097
1098
1099
1100
  
  		if (IS_ERR(dev))
  			err = PTR_ERR(dev);
  		else if (ops->newlink)
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
1101
1102
1103
  			err = ops->newlink(dev, tb, data);
  		else
  			err = register_netdevice(dev);
e71992889   Pavel Emelianov   [RTNETLINK]: Intr...
1104
1105
  
  		if (err < 0 && !IS_ERR(dev))
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
1106
1107
1108
1109
  			free_netdev(dev);
  		return err;
  	}
  }
b60c5115f   Thomas Graf   [NET]: Convert li...
1110
  static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
711e2c33a   Jean Tourrilhes   [PATCH] WE-20 for...
1111
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1112
  	struct net *net = sock_net(skb->sk);
b60c5115f   Thomas Graf   [NET]: Convert li...
1113
1114
1115
1116
  	struct ifinfomsg *ifm;
  	struct nlattr *tb[IFLA_MAX+1];
  	struct net_device *dev = NULL;
  	struct sk_buff *nskb;
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
1117
  	int err;
711e2c33a   Jean Tourrilhes   [PATCH] WE-20 for...
1118

b60c5115f   Thomas Graf   [NET]: Convert li...
1119
1120
  	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
  	if (err < 0)
9918f2309   Eric Sesterhenn   [RTNETLINK]: Poss...
1121
  		return err;
b60c5115f   Thomas Graf   [NET]: Convert li...
1122
1123
  
  	ifm = nlmsg_data(nlh);
51055be81   Patrick McHardy   [RTNETLINK]: ifin...
1124
  	if (ifm->ifi_index > 0) {
881d966b4   Eric W. Biederman   [NET]: Make the d...
1125
  		dev = dev_get_by_index(net, ifm->ifi_index);
b60c5115f   Thomas Graf   [NET]: Convert li...
1126
1127
1128
  		if (dev == NULL)
  			return -ENODEV;
  	} else
711e2c33a   Jean Tourrilhes   [PATCH] WE-20 for...
1129
  		return -EINVAL;
711e2c33a   Jean Tourrilhes   [PATCH] WE-20 for...
1130

38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
1131
  	nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
b60c5115f   Thomas Graf   [NET]: Convert li...
1132
1133
1134
1135
  	if (nskb == NULL) {
  		err = -ENOBUFS;
  		goto errout;
  	}
575c3e2a0   Patrick McHardy   [RTNETLINK]: Remo...
1136
1137
  	err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid,
  			       nlh->nlmsg_seq, 0, 0);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1138
1139
1140
1141
1142
1143
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in if_nlmsg_size */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(nskb);
  		goto errout;
  	}
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
1144
  	err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid);
b60c5115f   Thomas Graf   [NET]: Convert li...
1145
  errout:
711e2c33a   Jean Tourrilhes   [PATCH] WE-20 for...
1146
  	dev_put(dev);
711e2c33a   Jean Tourrilhes   [PATCH] WE-20 for...
1147

b60c5115f   Thomas Graf   [NET]: Convert li...
1148
  	return err;
711e2c33a   Jean Tourrilhes   [PATCH] WE-20 for...
1149
  }
711e2c33a   Jean Tourrilhes   [PATCH] WE-20 for...
1150

42bad1da5   Adrian Bunk   [NETLINK]: Possib...
1151
  static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
  {
  	int idx;
  	int s_idx = cb->family;
  
  	if (s_idx == 0)
  		s_idx = 1;
  	for (idx=1; idx<NPROTO; idx++) {
  		int type = cb->nlh->nlmsg_type-RTM_BASE;
  		if (idx < s_idx || idx == PF_PACKET)
  			continue;
e28498638   Thomas Graf   [RTNL]: Message h...
1162
1163
  		if (rtnl_msg_handlers[idx] == NULL ||
  		    rtnl_msg_handlers[idx][type].dumpit == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
1166
  			continue;
  		if (idx > s_idx)
  			memset(&cb->args[0], 0, sizeof(cb->args));
e28498638   Thomas Graf   [RTNL]: Message h...
1167
  		if (rtnl_msg_handlers[idx][type].dumpit(skb, cb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
1169
1170
1171
1172
1173
1174
1175
1176
  			break;
  	}
  	cb->family = idx;
  
  	return skb->len;
  }
  
  void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
  {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1177
  	struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
  	struct sk_buff *skb;
0ec6d3f46   Thomas Graf   [NET] link: Conve...
1179
  	int err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180

38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
1181
  	skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
0ec6d3f46   Thomas Graf   [NET] link: Conve...
1182
1183
  	if (skb == NULL)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184

575c3e2a0   Patrick McHardy   [RTNETLINK]: Remo...
1185
  	err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1186
1187
1188
1189
1190
1191
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in if_nlmsg_size() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
1192
1193
  	rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
  	return;
0ec6d3f46   Thomas Graf   [NET] link: Conve...
1194
1195
  errout:
  	if (err < 0)
4b3da706b   Eric W. Biederman   [NET]: Make the n...
1196
  		rtnl_set_sk_err(net, RTNLGRP_LINK, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
1199
1200
1201
1202
  /* Protected by RTNL sempahore.  */
  static struct rtattr **rta_buf;
  static int rtattr_max;
  
  /* Process one rtnetlink message. */
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
1203
  static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1205
  	struct net *net = sock_net(skb->sk);
e28498638   Thomas Graf   [RTNL]: Message h...
1206
  	rtnl_doit_func doit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
1208
1209
1210
  	int sz_idx, kind;
  	int min_len;
  	int family;
  	int type;
1c2d670f3   Patrick McHardy   [RTNETLINK]: Hold...
1211
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
  	type = nlh->nlmsg_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
  	if (type > RTM_MAX)
038890fed   Thomas Graf   [RTNL]: Improve e...
1215
  		return -EOPNOTSUPP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
1217
1218
1219
1220
1221
1222
1223
  
  	type -= RTM_BASE;
  
  	/* All the messages must have at least 1 byte length */
  	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg)))
  		return 0;
  
  	family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family;
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
1224
1225
  	if (family >= NPROTO)
  		return -EAFNOSUPPORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
1228
  	sz_idx = type>>2;
  	kind = type&3;
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
1229
1230
  	if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN))
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
1232
  
  	if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
1233
  		struct sock *rtnl;
e28498638   Thomas Graf   [RTNL]: Message h...
1234
  		rtnl_dumpit_func dumpit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235

e28498638   Thomas Graf   [RTNL]: Message h...
1236
1237
  		dumpit = rtnl_get_dumpit(family, type);
  		if (dumpit == NULL)
038890fed   Thomas Graf   [RTNL]: Improve e...
1238
  			return -EOPNOTSUPP;
9ac4a1698   Thomas Graf   [RTNETLINK]: Use ...
1239

1c2d670f3   Patrick McHardy   [RTNETLINK]: Hold...
1240
  		__rtnl_unlock();
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
1241
  		rtnl = net->rtnl;
1c2d670f3   Patrick McHardy   [RTNETLINK]: Hold...
1242
1243
1244
  		err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
  		rtnl_lock();
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1245
1246
1247
1248
1249
1250
  	}
  
  	memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
  
  	min_len = rtm_min[sz_idx];
  	if (nlh->nlmsg_len < min_len)
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
1251
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1252
1253
1254
1255
1256
1257
1258
1259
1260
  
  	if (nlh->nlmsg_len > min_len) {
  		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
  		struct rtattr *attr = (void*)nlh + NLMSG_ALIGN(min_len);
  
  		while (RTA_OK(attr, attrlen)) {
  			unsigned flavor = attr->rta_type;
  			if (flavor) {
  				if (flavor > rta_max[sz_idx])
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
1261
  					return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262
1263
1264
1265
1266
  				rta_buf[flavor-1] = attr;
  			}
  			attr = RTA_NEXT(attr, attrlen);
  		}
  	}
e28498638   Thomas Graf   [RTNL]: Message h...
1267
1268
  	doit = rtnl_get_doit(family, type);
  	if (doit == NULL)
038890fed   Thomas Graf   [RTNL]: Improve e...
1269
  		return -EOPNOTSUPP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1270

1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
1271
  	return doit(skb, nlh, (void *)&rta_buf[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
  }
cd40b7d39   Denis V. Lunev   [NET]: make netli...
1273
  static void rtnetlink_rcv(struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
  {
cd40b7d39   Denis V. Lunev   [NET]: make netli...
1275
1276
1277
  	rtnl_lock();
  	netlink_rcv_skb(skb, &rtnetlink_rcv_msg);
  	rtnl_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1279
1280
1281
  static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr)
  {
  	struct net_device *dev = ptr;
e9dc86534   Eric W. Biederman   [NET]: Make devic...
1282

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
  	switch (event) {
  	case NETDEV_UNREGISTER:
  		rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
  		break;
  	case NETDEV_REGISTER:
  		rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
  		break;
  	case NETDEV_UP:
  	case NETDEV_DOWN:
  		rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING);
  		break;
  	case NETDEV_CHANGE:
  	case NETDEV_GOING_DOWN:
  		break;
  	default:
  		rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
  		break;
  	}
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block rtnetlink_dev_notifier = {
  	.notifier_call	= rtnetlink_event,
  };
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
1307
1308
1309
1310
1311
1312
1313
1314
  
  static int rtnetlink_net_init(struct net *net)
  {
  	struct sock *sk;
  	sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
  				   rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
  	if (!sk)
  		return -ENOMEM;
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
1315
1316
1317
1318
1319
1320
  	net->rtnl = sk;
  	return 0;
  }
  
  static void rtnetlink_net_exit(struct net *net)
  {
775516bfa   Denis V. Lunev   [NETNS]: Namespac...
1321
1322
  	netlink_kernel_release(net->rtnl);
  	net->rtnl = NULL;
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
1323
1324
1325
1326
1327
1328
  }
  
  static struct pernet_operations rtnetlink_net_ops = {
  	.init = rtnetlink_net_init,
  	.exit = rtnetlink_net_exit,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
  void __init rtnetlink_init(void)
  {
  	int i;
  
  	rtattr_max = 0;
  	for (i = 0; i < ARRAY_SIZE(rta_max); i++)
  		if (rta_max[i] > rtattr_max)
  			rtattr_max = rta_max[i];
  	rta_buf = kmalloc(rtattr_max * sizeof(struct rtattr *), GFP_KERNEL);
  	if (!rta_buf)
  		panic("rtnetlink_init: cannot allocate rta_buf
  ");
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
1341
  	if (register_pernet_subsys(&rtnetlink_net_ops))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
1343
  		panic("rtnetlink_init: cannot initialize rtnetlink
  ");
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
1344

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
1346
  	netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
  	register_netdevice_notifier(&rtnetlink_dev_notifier);
340d17fc9   Thomas Graf   [NET] link: Use r...
1347
1348
1349
  
  	rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo);
  	rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL);
38f7b870d   Patrick McHardy   [RTNETLINK]: Link...
1350
1351
  	rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL);
  	rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL);
687ad8cc6   Thomas Graf   [RTNL]: Use rtnl ...
1352
1353
1354
  
  	rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all);
  	rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
1356
1357
  }
  
  EXPORT_SYMBOL(__rta_fill);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
  EXPORT_SYMBOL(rtnetlink_put_metrics);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1359
  EXPORT_SYMBOL(rtnl_lock);
6756ae4b4   Stephen Hemminger   [NET]: Convert RT...
1360
  EXPORT_SYMBOL(rtnl_trylock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
  EXPORT_SYMBOL(rtnl_unlock);
c9c1014b2   Patrick McHardy   [RTNETLINK]: Fix ...
1362
  EXPORT_SYMBOL(rtnl_is_locked);
2942e9005   Thomas Graf   [RTNETLINK]: Use ...
1363
  EXPORT_SYMBOL(rtnl_unicast);
97676b6b5   Thomas Graf   [RTNETLINK]: Add ...
1364
1365
  EXPORT_SYMBOL(rtnl_notify);
  EXPORT_SYMBOL(rtnl_set_sk_err);
e71992889   Pavel Emelianov   [RTNETLINK]: Intr...
1366
1367
  EXPORT_SYMBOL(rtnl_create_link);
  EXPORT_SYMBOL(ifla_policy);