Blame view

drivers/net/netconsole.c 24.1 KB
de6cc6515   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   *  linux/drivers/net/netconsole.c
   *
   *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
   *
   *  This file contains the implementation of an IRQ-safe, crash-safe
   *  kernel console implementation that outputs kernel messages to the
   *  network.
   *
   * Modification history:
   *
   * 2001-09-17    started by Ingo Molnar.
   * 2003-08-11    2.6 port by Matt Mackall
   *               simplified options
   *               generic card hooks
   *               works non-modular
   * 2003-09-07    rewritten with netpoll api
   */
  
  /****************************************************************
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
   *
   ****************************************************************/
22ded5772   Joe Perches   netconsole: Conve...
24
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
  #include <linux/init.h>
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
28
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include <linux/console.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #include <linux/moduleparam.h>
4cd5773a2   Andy Shevchenko   net: core: move m...
31
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #include <linux/netpoll.h>
0bcc18161   Satyam Sharma   [NET] netconsole:...
34
35
  #include <linux/inet.h>
  #include <linux/configfs.h>
1667c942e   Joe Perches   netconsole: Use e...
36
  #include <linux/etherdevice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
  
  MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
  MODULE_DESCRIPTION("Console driver for network interfaces");
  MODULE_LICENSE("GPL");
d39badf05   Satyam Sharma   [NET] netconsole:...
41
42
43
44
45
  #define MAX_PARAM_LENGTH	256
  #define MAX_PRINT_CHUNK		1000
  
  static char config[MAX_PARAM_LENGTH];
  module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
61a2d07d3   Niels de Vos   Remove newline fr...
46
  MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

c1a608519   Amerigo Wang   netconsole: add o...
48
49
50
  static bool oops_only = false;
  module_param(oops_only, bool, 0600);
  MODULE_PARM_DESC(oops_only, "Only log oops messages");
d2b60881e   Satyam Sharma   [NET] netconsole:...
51
52
53
54
55
56
57
58
  #ifndef	MODULE
  static int __init option_setup(char *opt)
  {
  	strlcpy(config, opt, MAX_PARAM_LENGTH);
  	return 1;
  }
  __setup("netconsole=", option_setup);
  #endif	/* MODULE */
b5427c271   Satyam Sharma   [NET] netconsole:...
59
60
61
62
63
  /* Linked list of all configured targets */
  static LIST_HEAD(target_list);
  
  /* This needs to be a spinlock because write_msg() cannot sleep */
  static DEFINE_SPINLOCK(target_list_lock);
e2f15f9a7   Tejun Heo   netconsole: imple...
64
65
66
67
68
  /*
   * Console driver for extended netconsoles.  Registered on the first use to
   * avoid unnecessarily enabling ext message formatting.
   */
  static struct console netconsole_ext;
df180e369   Satyam Sharma   [NET] netconsole:...
69
70
  /**
   * struct netconsole_target - Represents a configured netconsole target.
b5427c271   Satyam Sharma   [NET] netconsole:...
71
   * @list:	Links this target into the target_list.
0bcc18161   Satyam Sharma   [NET] netconsole:...
72
73
74
75
76
77
78
   * @item:	Links us into the configfs subsystem hierarchy.
   * @enabled:	On / off knob to enable / disable target.
   *		Visible from userspace (read-write).
   *		We maintain a strict 1:1 correspondence between this and
   *		whether the corresponding netpoll is active or inactive.
   *		Also, other parameters of a target may be modified at
   *		runtime only when it is disabled (enabled == 0).
df180e369   Satyam Sharma   [NET] netconsole:...
79
   * @np:		The netpoll structure for this target.
0bcc18161   Satyam Sharma   [NET] netconsole:...
80
81
82
83
84
85
86
87
   *		Contains the other userspace visible parameters:
   *		dev_name	(read-write)
   *		local_port	(read-write)
   *		remote_port	(read-write)
   *		local_ip	(read-write)
   *		remote_ip	(read-write)
   *		local_mac	(read-only)
   *		remote_mac	(read-write)
df180e369   Satyam Sharma   [NET] netconsole:...
88
89
   */
  struct netconsole_target {
b5427c271   Satyam Sharma   [NET] netconsole:...
90
  	struct list_head	list;
0bcc18161   Satyam Sharma   [NET] netconsole:...
91
92
93
  #ifdef	CONFIG_NETCONSOLE_DYNAMIC
  	struct config_item	item;
  #endif
698cf1c61   Tejun Heo   netconsole: make ...
94
  	bool			enabled;
e2f15f9a7   Tejun Heo   netconsole: imple...
95
  	bool			extended;
df180e369   Satyam Sharma   [NET] netconsole:...
96
97
  	struct netpoll		np;
  };
0bcc18161   Satyam Sharma   [NET] netconsole:...
98
99
100
  #ifdef	CONFIG_NETCONSOLE_DYNAMIC
  
  static struct configfs_subsystem netconsole_subsys;
369e5a888   Tejun Heo   netconsole: make ...
101
  static DEFINE_MUTEX(dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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
  
  static int __init dynamic_netconsole_init(void)
  {
  	config_group_init(&netconsole_subsys.su_group);
  	mutex_init(&netconsole_subsys.su_mutex);
  	return configfs_register_subsystem(&netconsole_subsys);
  }
  
  static void __exit dynamic_netconsole_exit(void)
  {
  	configfs_unregister_subsystem(&netconsole_subsys);
  }
  
  /*
   * Targets that were created by parsing the boot/module option string
   * do not exist in the configfs hierarchy (and have NULL names) and will
   * never go away, so make these a no-op for them.
   */
  static void netconsole_target_get(struct netconsole_target *nt)
  {
  	if (config_item_name(&nt->item))
  		config_item_get(&nt->item);
  }
  
  static void netconsole_target_put(struct netconsole_target *nt)
  {
  	if (config_item_name(&nt->item))
  		config_item_put(&nt->item);
  }
  
  #else	/* !CONFIG_NETCONSOLE_DYNAMIC */
  
  static int __init dynamic_netconsole_init(void)
  {
  	return 0;
  }
  
  static void __exit dynamic_netconsole_exit(void)
  {
  }
  
  /*
   * No danger of targets going away from under us when dynamic
   * reconfigurability is off.
   */
  static void netconsole_target_get(struct netconsole_target *nt)
  {
  }
  
  static void netconsole_target_put(struct netconsole_target *nt)
  {
  }
  
  #endif	/* CONFIG_NETCONSOLE_DYNAMIC */
  
  /* Allocate new target (from boot/module param) and setup netpoll for it */
  static struct netconsole_target *alloc_param_target(char *target_config)
b5427c271   Satyam Sharma   [NET] netconsole:...
159
160
161
  {
  	int err = -ENOMEM;
  	struct netconsole_target *nt;
0bcc18161   Satyam Sharma   [NET] netconsole:...
162
163
164
165
  	/*
  	 * Allocate and initialize with defaults.
  	 * Note that these targets get their config_item fields zeroed-out.
  	 */
b5427c271   Satyam Sharma   [NET] netconsole:...
166
  	nt = kzalloc(sizeof(*nt), GFP_KERNEL);
e404decb0   Joe Perches   drivers/net: Remo...
167
  	if (!nt)
b5427c271   Satyam Sharma   [NET] netconsole:...
168
  		goto fail;
b5427c271   Satyam Sharma   [NET] netconsole:...
169
170
171
172
173
  
  	nt->np.name = "netconsole";
  	strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
  	nt->np.local_port = 6665;
  	nt->np.remote_port = 6666;
1667c942e   Joe Perches   netconsole: Use e...
174
  	eth_broadcast_addr(nt->np.remote_mac);
b5427c271   Satyam Sharma   [NET] netconsole:...
175

e2f15f9a7   Tejun Heo   netconsole: imple...
176
177
178
179
  	if (*target_config == '+') {
  		nt->extended = true;
  		target_config++;
  	}
b5427c271   Satyam Sharma   [NET] netconsole:...
180
181
182
183
184
185
186
187
  	/* Parse parameters and setup netpoll */
  	err = netpoll_parse_options(&nt->np, target_config);
  	if (err)
  		goto fail;
  
  	err = netpoll_setup(&nt->np);
  	if (err)
  		goto fail;
698cf1c61   Tejun Heo   netconsole: make ...
188
  	nt->enabled = true;
0bcc18161   Satyam Sharma   [NET] netconsole:...
189

b5427c271   Satyam Sharma   [NET] netconsole:...
190
191
192
193
194
195
  	return nt;
  
  fail:
  	kfree(nt);
  	return ERR_PTR(err);
  }
0bcc18161   Satyam Sharma   [NET] netconsole:...
196
197
  /* Cleanup netpoll for given target (from boot/module param) and free it */
  static void free_param_target(struct netconsole_target *nt)
b5427c271   Satyam Sharma   [NET] netconsole:...
198
199
200
201
  {
  	netpoll_cleanup(&nt->np);
  	kfree(nt);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202

0bcc18161   Satyam Sharma   [NET] netconsole:...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  #ifdef	CONFIG_NETCONSOLE_DYNAMIC
  
  /*
   * Our subsystem hierarchy is:
   *
   * /sys/kernel/config/netconsole/
   *				|
   *				<target>/
   *				|	enabled
   *				|	dev_name
   *				|	local_port
   *				|	remote_port
   *				|	local_ip
   *				|	remote_ip
   *				|	local_mac
   *				|	remote_mac
   *				|
   *				<target>/...
   */
0bcc18161   Satyam Sharma   [NET] netconsole:...
222
223
224
225
226
227
228
229
  static struct netconsole_target *to_target(struct config_item *item)
  {
  	return item ?
  		container_of(item, struct netconsole_target, item) :
  		NULL;
  }
  
  /*
0bcc18161   Satyam Sharma   [NET] netconsole:...
230
231
   * Attribute operations for netconsole_target.
   */
ea9ed9cff   Christoph Hellwig   netconsole: use p...
232
  static ssize_t enabled_show(struct config_item *item, char *buf)
0bcc18161   Satyam Sharma   [NET] netconsole:...
233
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
234
235
  	return snprintf(buf, PAGE_SIZE, "%d
  ", to_target(item)->enabled);
0bcc18161   Satyam Sharma   [NET] netconsole:...
236
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
237
  static ssize_t extended_show(struct config_item *item, char *buf)
e2f15f9a7   Tejun Heo   netconsole: imple...
238
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
239
240
  	return snprintf(buf, PAGE_SIZE, "%d
  ", to_target(item)->extended);
e2f15f9a7   Tejun Heo   netconsole: imple...
241
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
242
  static ssize_t dev_name_show(struct config_item *item, char *buf)
0bcc18161   Satyam Sharma   [NET] netconsole:...
243
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
244
245
  	return snprintf(buf, PAGE_SIZE, "%s
  ", to_target(item)->np.dev_name);
0bcc18161   Satyam Sharma   [NET] netconsole:...
246
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
247
  static ssize_t local_port_show(struct config_item *item, char *buf)
0bcc18161   Satyam Sharma   [NET] netconsole:...
248
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
249
250
  	return snprintf(buf, PAGE_SIZE, "%d
  ", to_target(item)->np.local_port);
0bcc18161   Satyam Sharma   [NET] netconsole:...
251
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
252
  static ssize_t remote_port_show(struct config_item *item, char *buf)
0bcc18161   Satyam Sharma   [NET] netconsole:...
253
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
254
255
  	return snprintf(buf, PAGE_SIZE, "%d
  ", to_target(item)->np.remote_port);
0bcc18161   Satyam Sharma   [NET] netconsole:...
256
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
257
  static ssize_t local_ip_show(struct config_item *item, char *buf)
0bcc18161   Satyam Sharma   [NET] netconsole:...
258
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
259
  	struct netconsole_target *nt = to_target(item);
b3d936f3e   Cong Wang   netpoll: add IPv6...
260
261
262
263
  	if (nt->np.ipv6)
  		return snprintf(buf, PAGE_SIZE, "%pI6c
  ", &nt->np.local_ip.in6);
  	else
b7394d242   Cong Wang   netpoll: prepare ...
264
265
  		return snprintf(buf, PAGE_SIZE, "%pI4
  ", &nt->np.local_ip);
0bcc18161   Satyam Sharma   [NET] netconsole:...
266
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
267
  static ssize_t remote_ip_show(struct config_item *item, char *buf)
0bcc18161   Satyam Sharma   [NET] netconsole:...
268
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
269
  	struct netconsole_target *nt = to_target(item);
b3d936f3e   Cong Wang   netpoll: add IPv6...
270
271
272
273
  	if (nt->np.ipv6)
  		return snprintf(buf, PAGE_SIZE, "%pI6c
  ", &nt->np.remote_ip.in6);
  	else
b7394d242   Cong Wang   netpoll: prepare ...
274
275
  		return snprintf(buf, PAGE_SIZE, "%pI4
  ", &nt->np.remote_ip);
0bcc18161   Satyam Sharma   [NET] netconsole:...
276
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
277
  static ssize_t local_mac_show(struct config_item *item, char *buf)
0bcc18161   Satyam Sharma   [NET] netconsole:...
278
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
279
  	struct net_device *dev = to_target(item)->np.dev;
e174961ca   Johannes Berg   net: convert prin...
280
  	static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
095386416   Stephen Hemminger   [NETPOLL]: no nee...
281

e174961ca   Johannes Berg   net: convert prin...
282
283
  	return snprintf(buf, PAGE_SIZE, "%pM
  ", dev ? dev->dev_addr : bcast);
0bcc18161   Satyam Sharma   [NET] netconsole:...
284
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
285
  static ssize_t remote_mac_show(struct config_item *item, char *buf)
0bcc18161   Satyam Sharma   [NET] netconsole:...
286
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
287
288
  	return snprintf(buf, PAGE_SIZE, "%pM
  ", to_target(item)->np.remote_mac);
0bcc18161   Satyam Sharma   [NET] netconsole:...
289
290
291
292
293
294
295
296
297
  }
  
  /*
   * This one is special -- targets created through the configfs interface
   * are not enabled (and the corresponding netpoll activated) by default.
   * The user is expected to set the desired parameters first (which
   * would enable him to dynamically add new netpoll targets for new
   * network interfaces as and when they come up).
   */
ea9ed9cff   Christoph Hellwig   netconsole: use p...
298
299
  static ssize_t enabled_store(struct config_item *item,
  		const char *buf, size_t count)
0bcc18161   Satyam Sharma   [NET] netconsole:...
300
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
301
  	struct netconsole_target *nt = to_target(item);
45e526e80   Nikolay Aleksandrov   netconsole: fix N...
302
  	unsigned long flags;
99f823f98   Alexey Dobriyan   netconsole: switc...
303
  	int enabled;
0bcc18161   Satyam Sharma   [NET] netconsole:...
304
  	int err;
0bcc18161   Satyam Sharma   [NET] netconsole:...
305

ea9ed9cff   Christoph Hellwig   netconsole: use p...
306
  	mutex_lock(&dynamic_netconsole_mutex);
99f823f98   Alexey Dobriyan   netconsole: switc...
307
308
  	err = kstrtoint(buf, 10, &enabled);
  	if (err < 0)
ea9ed9cff   Christoph Hellwig   netconsole: use p...
309
310
311
  		goto out_unlock;
  
  	err = -EINVAL;
99f823f98   Alexey Dobriyan   netconsole: switc...
312
  	if (enabled < 0 || enabled > 1)
ea9ed9cff   Christoph Hellwig   netconsole: use p...
313
  		goto out_unlock;
698cf1c61   Tejun Heo   netconsole: make ...
314
  	if ((bool)enabled == nt->enabled) {
22ded5772   Joe Perches   netconsole: Conve...
315
316
317
  		pr_info("network logging has already %s
  ",
  			nt->enabled ? "started" : "stopped");
ea9ed9cff   Christoph Hellwig   netconsole: use p...
318
  		goto out_unlock;
d5123480b   Gao feng   netconsole: enabl...
319
  	}
0bcc18161   Satyam Sharma   [NET] netconsole:...
320

698cf1c61   Tejun Heo   netconsole: make ...
321
  	if (enabled) {	/* true */
e2f15f9a7   Tejun Heo   netconsole: imple...
322
323
324
325
  		if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) {
  			netconsole_ext.flags |= CON_ENABLED;
  			register_console(&netconsole_ext);
  		}
0bcc18161   Satyam Sharma   [NET] netconsole:...
326
327
328
329
330
331
332
  		/*
  		 * Skip netpoll_parse_options() -- all the attributes are
  		 * already configured via configfs. Just print them out.
  		 */
  		netpoll_print_options(&nt->np);
  
  		err = netpoll_setup(&nt->np);
c7c6effde   Nikolay Aleksandrov   netconsole: fix m...
333
  		if (err)
ea9ed9cff   Christoph Hellwig   netconsole: use p...
334
  			goto out_unlock;
0bcc18161   Satyam Sharma   [NET] netconsole:...
335

4a6a97e26   Joe Perches   netconsole: Remov...
336
337
  		pr_info("network logging started
  ");
698cf1c61   Tejun Heo   netconsole: make ...
338
  	} else {	/* false */
45e526e80   Nikolay Aleksandrov   netconsole: fix N...
339
340
  		/* We need to disable the netconsole before cleaning it up
  		 * otherwise we might end up in write_msg() with
698cf1c61   Tejun Heo   netconsole: make ...
341
  		 * nt->np.dev == NULL and nt->enabled == true
45e526e80   Nikolay Aleksandrov   netconsole: fix N...
342
343
  		 */
  		spin_lock_irqsave(&target_list_lock, flags);
698cf1c61   Tejun Heo   netconsole: make ...
344
  		nt->enabled = false;
45e526e80   Nikolay Aleksandrov   netconsole: fix N...
345
  		spin_unlock_irqrestore(&target_list_lock, flags);
0bcc18161   Satyam Sharma   [NET] netconsole:...
346
347
348
349
  		netpoll_cleanup(&nt->np);
  	}
  
  	nt->enabled = enabled;
ea9ed9cff   Christoph Hellwig   netconsole: use p...
350
  	mutex_unlock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
351
  	return strnlen(buf, count);
ea9ed9cff   Christoph Hellwig   netconsole: use p...
352
353
354
  out_unlock:
  	mutex_unlock(&dynamic_netconsole_mutex);
  	return err;
0bcc18161   Satyam Sharma   [NET] netconsole:...
355
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
356
357
  static ssize_t extended_store(struct config_item *item, const char *buf,
  		size_t count)
e2f15f9a7   Tejun Heo   netconsole: imple...
358
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
359
  	struct netconsole_target *nt = to_target(item);
e2f15f9a7   Tejun Heo   netconsole: imple...
360
361
  	int extended;
  	int err;
ea9ed9cff   Christoph Hellwig   netconsole: use p...
362
  	mutex_lock(&dynamic_netconsole_mutex);
e2f15f9a7   Tejun Heo   netconsole: imple...
363
364
365
366
  	if (nt->enabled) {
  		pr_err("target (%s) is enabled, disable to update parameters
  ",
  		       config_item_name(&nt->item));
ea9ed9cff   Christoph Hellwig   netconsole: use p...
367
368
  		err = -EINVAL;
  		goto out_unlock;
e2f15f9a7   Tejun Heo   netconsole: imple...
369
370
371
372
  	}
  
  	err = kstrtoint(buf, 10, &extended);
  	if (err < 0)
ea9ed9cff   Christoph Hellwig   netconsole: use p...
373
374
375
376
377
  		goto out_unlock;
  	if (extended < 0 || extended > 1) {
  		err = -EINVAL;
  		goto out_unlock;
  	}
e2f15f9a7   Tejun Heo   netconsole: imple...
378
379
  
  	nt->extended = extended;
ea9ed9cff   Christoph Hellwig   netconsole: use p...
380
  	mutex_unlock(&dynamic_netconsole_mutex);
e2f15f9a7   Tejun Heo   netconsole: imple...
381
  	return strnlen(buf, count);
ea9ed9cff   Christoph Hellwig   netconsole: use p...
382
383
384
  out_unlock:
  	mutex_unlock(&dynamic_netconsole_mutex);
  	return err;
e2f15f9a7   Tejun Heo   netconsole: imple...
385
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
386
387
  static ssize_t dev_name_store(struct config_item *item, const char *buf,
  		size_t count)
0bcc18161   Satyam Sharma   [NET] netconsole:...
388
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
389
  	struct netconsole_target *nt = to_target(item);
0bcc18161   Satyam Sharma   [NET] netconsole:...
390
  	size_t len;
ea9ed9cff   Christoph Hellwig   netconsole: use p...
391
  	mutex_lock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
392
  	if (nt->enabled) {
22ded5772   Joe Perches   netconsole: Conve...
393
394
395
  		pr_err("target (%s) is enabled, disable to update parameters
  ",
  		       config_item_name(&nt->item));
ea9ed9cff   Christoph Hellwig   netconsole: use p...
396
  		mutex_unlock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
397
398
399
400
401
402
403
404
405
406
  		return -EINVAL;
  	}
  
  	strlcpy(nt->np.dev_name, buf, IFNAMSIZ);
  
  	/* Get rid of possible trailing newline from echo(1) */
  	len = strnlen(nt->np.dev_name, IFNAMSIZ);
  	if (nt->np.dev_name[len - 1] == '
  ')
  		nt->np.dev_name[len - 1] = '\0';
ea9ed9cff   Christoph Hellwig   netconsole: use p...
407
  	mutex_unlock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
408
409
  	return strnlen(buf, count);
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
410
411
  static ssize_t local_port_store(struct config_item *item, const char *buf,
  		size_t count)
0bcc18161   Satyam Sharma   [NET] netconsole:...
412
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
413
414
  	struct netconsole_target *nt = to_target(item);
  	int rv = -EINVAL;
0bcc18161   Satyam Sharma   [NET] netconsole:...
415

ea9ed9cff   Christoph Hellwig   netconsole: use p...
416
  	mutex_lock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
417
  	if (nt->enabled) {
22ded5772   Joe Perches   netconsole: Conve...
418
419
420
  		pr_err("target (%s) is enabled, disable to update parameters
  ",
  		       config_item_name(&nt->item));
ea9ed9cff   Christoph Hellwig   netconsole: use p...
421
  		goto out_unlock;
0bcc18161   Satyam Sharma   [NET] netconsole:...
422
  	}
99f823f98   Alexey Dobriyan   netconsole: switc...
423
424
  	rv = kstrtou16(buf, 10, &nt->np.local_port);
  	if (rv < 0)
ea9ed9cff   Christoph Hellwig   netconsole: use p...
425
426
  		goto out_unlock;
  	mutex_unlock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
427
  	return strnlen(buf, count);
ea9ed9cff   Christoph Hellwig   netconsole: use p...
428
429
430
  out_unlock:
  	mutex_unlock(&dynamic_netconsole_mutex);
  	return rv;
0bcc18161   Satyam Sharma   [NET] netconsole:...
431
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
432
433
  static ssize_t remote_port_store(struct config_item *item,
  		const char *buf, size_t count)
0bcc18161   Satyam Sharma   [NET] netconsole:...
434
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
435
436
  	struct netconsole_target *nt = to_target(item);
  	int rv = -EINVAL;
0bcc18161   Satyam Sharma   [NET] netconsole:...
437

ea9ed9cff   Christoph Hellwig   netconsole: use p...
438
  	mutex_lock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
439
  	if (nt->enabled) {
22ded5772   Joe Perches   netconsole: Conve...
440
441
442
  		pr_err("target (%s) is enabled, disable to update parameters
  ",
  		       config_item_name(&nt->item));
ea9ed9cff   Christoph Hellwig   netconsole: use p...
443
  		goto out_unlock;
0bcc18161   Satyam Sharma   [NET] netconsole:...
444
  	}
99f823f98   Alexey Dobriyan   netconsole: switc...
445
446
  	rv = kstrtou16(buf, 10, &nt->np.remote_port);
  	if (rv < 0)
ea9ed9cff   Christoph Hellwig   netconsole: use p...
447
448
  		goto out_unlock;
  	mutex_unlock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
449
  	return strnlen(buf, count);
ea9ed9cff   Christoph Hellwig   netconsole: use p...
450
451
452
  out_unlock:
  	mutex_unlock(&dynamic_netconsole_mutex);
  	return rv;
0bcc18161   Satyam Sharma   [NET] netconsole:...
453
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
454
455
  static ssize_t local_ip_store(struct config_item *item, const char *buf,
  		size_t count)
0bcc18161   Satyam Sharma   [NET] netconsole:...
456
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
457
458
459
  	struct netconsole_target *nt = to_target(item);
  
  	mutex_lock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
460
  	if (nt->enabled) {
22ded5772   Joe Perches   netconsole: Conve...
461
462
463
  		pr_err("target (%s) is enabled, disable to update parameters
  ",
  		       config_item_name(&nt->item));
ea9ed9cff   Christoph Hellwig   netconsole: use p...
464
  		goto out_unlock;
0bcc18161   Satyam Sharma   [NET] netconsole:...
465
  	}
b3d936f3e   Cong Wang   netpoll: add IPv6...
466
467
468
469
470
  	if (strnchr(buf, count, ':')) {
  		const char *end;
  		if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
  			if (*end && *end != '
  ') {
22ded5772   Joe Perches   netconsole: Conve...
471
472
  				pr_err("invalid IPv6 address at: <%c>
  ", *end);
ea9ed9cff   Christoph Hellwig   netconsole: use p...
473
  				goto out_unlock;
b3d936f3e   Cong Wang   netpoll: add IPv6...
474
475
476
  			}
  			nt->np.ipv6 = true;
  		} else
ea9ed9cff   Christoph Hellwig   netconsole: use p...
477
  			goto out_unlock;
b3d936f3e   Cong Wang   netpoll: add IPv6...
478
479
480
481
  	} else {
  		if (!nt->np.ipv6) {
  			nt->np.local_ip.ip = in_aton(buf);
  		} else
ea9ed9cff   Christoph Hellwig   netconsole: use p...
482
  			goto out_unlock;
b3d936f3e   Cong Wang   netpoll: add IPv6...
483
  	}
0bcc18161   Satyam Sharma   [NET] netconsole:...
484

ea9ed9cff   Christoph Hellwig   netconsole: use p...
485
  	mutex_unlock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
486
  	return strnlen(buf, count);
ea9ed9cff   Christoph Hellwig   netconsole: use p...
487
488
489
  out_unlock:
  	mutex_unlock(&dynamic_netconsole_mutex);
  	return -EINVAL;
0bcc18161   Satyam Sharma   [NET] netconsole:...
490
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
491
492
  static ssize_t remote_ip_store(struct config_item *item, const char *buf,
  	       size_t count)
0bcc18161   Satyam Sharma   [NET] netconsole:...
493
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
494
495
496
  	struct netconsole_target *nt = to_target(item);
  
  	mutex_lock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
497
  	if (nt->enabled) {
22ded5772   Joe Perches   netconsole: Conve...
498
499
500
  		pr_err("target (%s) is enabled, disable to update parameters
  ",
  		       config_item_name(&nt->item));
ea9ed9cff   Christoph Hellwig   netconsole: use p...
501
  		goto out_unlock;
0bcc18161   Satyam Sharma   [NET] netconsole:...
502
  	}
b3d936f3e   Cong Wang   netpoll: add IPv6...
503
504
505
506
507
  	if (strnchr(buf, count, ':')) {
  		const char *end;
  		if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
  			if (*end && *end != '
  ') {
22ded5772   Joe Perches   netconsole: Conve...
508
509
  				pr_err("invalid IPv6 address at: <%c>
  ", *end);
ea9ed9cff   Christoph Hellwig   netconsole: use p...
510
  				goto out_unlock;
b3d936f3e   Cong Wang   netpoll: add IPv6...
511
512
513
  			}
  			nt->np.ipv6 = true;
  		} else
ea9ed9cff   Christoph Hellwig   netconsole: use p...
514
  			goto out_unlock;
b3d936f3e   Cong Wang   netpoll: add IPv6...
515
516
517
518
  	} else {
  		if (!nt->np.ipv6) {
  			nt->np.remote_ip.ip = in_aton(buf);
  		} else
ea9ed9cff   Christoph Hellwig   netconsole: use p...
519
  			goto out_unlock;
b3d936f3e   Cong Wang   netpoll: add IPv6...
520
  	}
0bcc18161   Satyam Sharma   [NET] netconsole:...
521

ea9ed9cff   Christoph Hellwig   netconsole: use p...
522
  	mutex_unlock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
523
  	return strnlen(buf, count);
ea9ed9cff   Christoph Hellwig   netconsole: use p...
524
525
526
  out_unlock:
  	mutex_unlock(&dynamic_netconsole_mutex);
  	return -EINVAL;
0bcc18161   Satyam Sharma   [NET] netconsole:...
527
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
528
529
  static ssize_t remote_mac_store(struct config_item *item, const char *buf,
  		size_t count)
0bcc18161   Satyam Sharma   [NET] netconsole:...
530
  {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
531
  	struct netconsole_target *nt = to_target(item);
0bcc18161   Satyam Sharma   [NET] netconsole:...
532
  	u8 remote_mac[ETH_ALEN];
0bcc18161   Satyam Sharma   [NET] netconsole:...
533

ea9ed9cff   Christoph Hellwig   netconsole: use p...
534
  	mutex_lock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
535
  	if (nt->enabled) {
22ded5772   Joe Perches   netconsole: Conve...
536
537
538
  		pr_err("target (%s) is enabled, disable to update parameters
  ",
  		       config_item_name(&nt->item));
ea9ed9cff   Christoph Hellwig   netconsole: use p...
539
  		goto out_unlock;
0bcc18161   Satyam Sharma   [NET] netconsole:...
540
  	}
4940fc889   Alexey Dobriyan   net: add mac_pton...
541
  	if (!mac_pton(buf, remote_mac))
ea9ed9cff   Christoph Hellwig   netconsole: use p...
542
  		goto out_unlock;
4940fc889   Alexey Dobriyan   net: add mac_pton...
543
544
  	if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '
  ')
ea9ed9cff   Christoph Hellwig   netconsole: use p...
545
  		goto out_unlock;
0bcc18161   Satyam Sharma   [NET] netconsole:...
546
  	memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
ea9ed9cff   Christoph Hellwig   netconsole: use p...
547
  	mutex_unlock(&dynamic_netconsole_mutex);
0bcc18161   Satyam Sharma   [NET] netconsole:...
548
  	return strnlen(buf, count);
ea9ed9cff   Christoph Hellwig   netconsole: use p...
549
550
551
  out_unlock:
  	mutex_unlock(&dynamic_netconsole_mutex);
  	return -EINVAL;
0bcc18161   Satyam Sharma   [NET] netconsole:...
552
  }
ea9ed9cff   Christoph Hellwig   netconsole: use p...
553
554
555
556
557
558
559
560
561
  CONFIGFS_ATTR(, enabled);
  CONFIGFS_ATTR(, extended);
  CONFIGFS_ATTR(, dev_name);
  CONFIGFS_ATTR(, local_port);
  CONFIGFS_ATTR(, remote_port);
  CONFIGFS_ATTR(, local_ip);
  CONFIGFS_ATTR(, remote_ip);
  CONFIGFS_ATTR_RO(, local_mac);
  CONFIGFS_ATTR(, remote_mac);
0bcc18161   Satyam Sharma   [NET] netconsole:...
562
563
  
  static struct configfs_attribute *netconsole_target_attrs[] = {
ea9ed9cff   Christoph Hellwig   netconsole: use p...
564
565
566
567
568
569
570
571
572
  	&attr_enabled,
  	&attr_extended,
  	&attr_dev_name,
  	&attr_local_port,
  	&attr_remote_port,
  	&attr_local_ip,
  	&attr_remote_ip,
  	&attr_local_mac,
  	&attr_remote_mac,
0bcc18161   Satyam Sharma   [NET] netconsole:...
573
574
575
576
577
578
579
580
581
582
583
  	NULL,
  };
  
  /*
   * Item operations and type for netconsole_target.
   */
  
  static void netconsole_target_release(struct config_item *item)
  {
  	kfree(to_target(item));
  }
0bcc18161   Satyam Sharma   [NET] netconsole:...
584
585
  static struct configfs_item_operations netconsole_target_item_ops = {
  	.release		= netconsole_target_release,
0bcc18161   Satyam Sharma   [NET] netconsole:...
586
  };
0d4a4406c   Bhumika Goyal   netconsole: make ...
587
  static const struct config_item_type netconsole_target_type = {
0bcc18161   Satyam Sharma   [NET] netconsole:...
588
589
590
591
592
593
594
595
  	.ct_attrs		= netconsole_target_attrs,
  	.ct_item_ops		= &netconsole_target_item_ops,
  	.ct_owner		= THIS_MODULE,
  };
  
  /*
   * Group operations and type for netconsole_subsys.
   */
f89ab8619   Joel Becker   Revert "configfs:...
596
597
  static struct config_item *make_netconsole_target(struct config_group *group,
  						  const char *name)
0bcc18161   Satyam Sharma   [NET] netconsole:...
598
599
600
601
602
603
  {
  	unsigned long flags;
  	struct netconsole_target *nt;
  
  	/*
  	 * Allocate and initialize with defaults.
698cf1c61   Tejun Heo   netconsole: make ...
604
  	 * Target is disabled at creation (!enabled).
0bcc18161   Satyam Sharma   [NET] netconsole:...
605
606
  	 */
  	nt = kzalloc(sizeof(*nt), GFP_KERNEL);
e404decb0   Joe Perches   drivers/net: Remo...
607
  	if (!nt)
a6795e9eb   Joel Becker   configfs: Allow -...
608
  		return ERR_PTR(-ENOMEM);
0bcc18161   Satyam Sharma   [NET] netconsole:...
609
610
611
612
613
  
  	nt->np.name = "netconsole";
  	strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
  	nt->np.local_port = 6665;
  	nt->np.remote_port = 6666;
1667c942e   Joe Perches   netconsole: Use e...
614
  	eth_broadcast_addr(nt->np.remote_mac);
0bcc18161   Satyam Sharma   [NET] netconsole:...
615
616
617
618
619
620
621
622
  
  	/* Initialize the config_item member */
  	config_item_init_type_name(&nt->item, name, &netconsole_target_type);
  
  	/* Adding, but it is disabled */
  	spin_lock_irqsave(&target_list_lock, flags);
  	list_add(&nt->list, &target_list);
  	spin_unlock_irqrestore(&target_list_lock, flags);
f89ab8619   Joel Becker   Revert "configfs:...
623
  	return &nt->item;
0bcc18161   Satyam Sharma   [NET] netconsole:...
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
  }
  
  static void drop_netconsole_target(struct config_group *group,
  				   struct config_item *item)
  {
  	unsigned long flags;
  	struct netconsole_target *nt = to_target(item);
  
  	spin_lock_irqsave(&target_list_lock, flags);
  	list_del(&nt->list);
  	spin_unlock_irqrestore(&target_list_lock, flags);
  
  	/*
  	 * The target may have never been enabled, or was manually disabled
  	 * before being removed so netpoll may have already been cleaned up.
  	 */
  	if (nt->enabled)
  		netpoll_cleanup(&nt->np);
  
  	config_item_put(&nt->item);
  }
  
  static struct configfs_group_operations netconsole_subsys_group_ops = {
  	.make_item	= make_netconsole_target,
  	.drop_item	= drop_netconsole_target,
  };
0d4a4406c   Bhumika Goyal   netconsole: make ...
650
  static const struct config_item_type netconsole_subsys_type = {
0bcc18161   Satyam Sharma   [NET] netconsole:...
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
  	.ct_group_ops	= &netconsole_subsys_group_ops,
  	.ct_owner	= THIS_MODULE,
  };
  
  /* The netconsole configfs subsystem */
  static struct configfs_subsystem netconsole_subsys = {
  	.su_group	= {
  		.cg_item	= {
  			.ci_namebuf	= "netconsole",
  			.ci_type	= &netconsole_subsys_type,
  		},
  	},
  };
  
  #endif	/* CONFIG_NETCONSOLE_DYNAMIC */
17951f34b   Satyam Sharma   [NET] netconsole:...
666
667
  /* Handle network interface device notifications */
  static int netconsole_netdev_event(struct notifier_block *this,
351638e7d   Jiri Pirko   net: pass info st...
668
  				   unsigned long event, void *ptr)
17951f34b   Satyam Sharma   [NET] netconsole:...
669
  {
b5427c271   Satyam Sharma   [NET] netconsole:...
670
671
  	unsigned long flags;
  	struct netconsole_target *nt;
351638e7d   Jiri Pirko   net: pass info st...
672
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
141dfba34   Ferenc Wagner   netconsole: don't...
673
  	bool stopped = false;
17951f34b   Satyam Sharma   [NET] netconsole:...
674

0e34e9317   WANG Cong   netpoll: add gene...
675
  	if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
daf9209bb   Amerigo Wang   net: rename NETDE...
676
  	      event == NETDEV_RELEASE || event == NETDEV_JOIN))
b5427c271   Satyam Sharma   [NET] netconsole:...
677
678
679
  		goto done;
  
  	spin_lock_irqsave(&target_list_lock, flags);
3f315bef2   Veaceslav Falico   netconsole: don't...
680
  restart:
b5427c271   Satyam Sharma   [NET] netconsole:...
681
  	list_for_each_entry(nt, &target_list, list) {
0bcc18161   Satyam Sharma   [NET] netconsole:...
682
  		netconsole_target_get(nt);
b5427c271   Satyam Sharma   [NET] netconsole:...
683
684
  		if (nt->np.dev == dev) {
  			switch (event) {
b5427c271   Satyam Sharma   [NET] netconsole:...
685
686
687
  			case NETDEV_CHANGENAME:
  				strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
  				break;
daf9209bb   Amerigo Wang   net: rename NETDE...
688
  			case NETDEV_RELEASE:
8d8fc29d0   Amerigo Wang   netpoll: disable ...
689
  			case NETDEV_JOIN:
2382b15bc   Bruno Prémont   netconsole: take ...
690
  			case NETDEV_UNREGISTER:
c71380ff0   Nikolay Aleksandrov   netconsole: fix a...
691
  				/* rtnl_lock already held
3f315bef2   Veaceslav Falico   netconsole: don't...
692
  				 * we might sleep in __netpoll_cleanup()
3b410a310   Neil Horman   bonding: Fix netc...
693
  				 */
3f315bef2   Veaceslav Falico   netconsole: don't...
694
  				spin_unlock_irqrestore(&target_list_lock, flags);
7a163bfb7   Dan Aloni   netconsole: avoid...
695

3f315bef2   Veaceslav Falico   netconsole: don't...
696
  				__netpoll_cleanup(&nt->np);
7a163bfb7   Dan Aloni   netconsole: avoid...
697

3f315bef2   Veaceslav Falico   netconsole: don't...
698
699
700
  				spin_lock_irqsave(&target_list_lock, flags);
  				dev_put(nt->np.dev);
  				nt->np.dev = NULL;
698cf1c61   Tejun Heo   netconsole: make ...
701
  				nt->enabled = false;
141dfba34   Ferenc Wagner   netconsole: don't...
702
  				stopped = true;
3f315bef2   Veaceslav Falico   netconsole: don't...
703
704
  				netconsole_target_put(nt);
  				goto restart;
b5427c271   Satyam Sharma   [NET] netconsole:...
705
  			}
17951f34b   Satyam Sharma   [NET] netconsole:...
706
  		}
0bcc18161   Satyam Sharma   [NET] netconsole:...
707
  		netconsole_target_put(nt);
17951f34b   Satyam Sharma   [NET] netconsole:...
708
  	}
b5427c271   Satyam Sharma   [NET] netconsole:...
709
  	spin_unlock_irqrestore(&target_list_lock, flags);
8d8fc29d0   Amerigo Wang   netpoll: disable ...
710
  	if (stopped) {
22ded5772   Joe Perches   netconsole: Conve...
711
  		const char *msg = "had an event";
8d8fc29d0   Amerigo Wang   netpoll: disable ...
712
713
  		switch (event) {
  		case NETDEV_UNREGISTER:
22ded5772   Joe Perches   netconsole: Conve...
714
  			msg = "unregistered";
8d8fc29d0   Amerigo Wang   netpoll: disable ...
715
  			break;
daf9209bb   Amerigo Wang   net: rename NETDE...
716
  		case NETDEV_RELEASE:
22ded5772   Joe Perches   netconsole: Conve...
717
  			msg = "released slaves";
8d8fc29d0   Amerigo Wang   netpoll: disable ...
718
719
  			break;
  		case NETDEV_JOIN:
22ded5772   Joe Perches   netconsole: Conve...
720
  			msg = "is joining a master device";
8d8fc29d0   Amerigo Wang   netpoll: disable ...
721
722
  			break;
  		}
22ded5772   Joe Perches   netconsole: Conve...
723
724
725
  		pr_info("network logging stopped on interface %s as it %s
  ",
  			dev->name, msg);
8d8fc29d0   Amerigo Wang   netpoll: disable ...
726
  	}
17951f34b   Satyam Sharma   [NET] netconsole:...
727

b5427c271   Satyam Sharma   [NET] netconsole:...
728
  done:
17951f34b   Satyam Sharma   [NET] netconsole:...
729
730
731
732
733
734
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block netconsole_netdev_notifier = {
  	.notifier_call  = netconsole_netdev_event,
  };
e2f15f9a7   Tejun Heo   netconsole: imple...
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
  /**
   * send_ext_msg_udp - send extended log message to target
   * @nt: target to send message to
   * @msg: extended log message to send
   * @msg_len: length of message
   *
   * Transfer extended log @msg to @nt.  If @msg is longer than
   * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with
   * ncfrag header field added to identify them.
   */
  static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg,
  			     int msg_len)
  {
  	static char buf[MAX_PRINT_CHUNK]; /* protected by target_list_lock */
  	const char *header, *body;
  	int offset = 0;
  	int header_len, body_len;
  
  	if (msg_len <= MAX_PRINT_CHUNK) {
  		netpoll_send_udp(&nt->np, msg, msg_len);
  		return;
  	}
  
  	/* need to insert extra header fields, detect header and body */
  	header = msg;
  	body = memchr(msg, ';', msg_len);
  	if (WARN_ON_ONCE(!body))
  		return;
  
  	header_len = body - header;
  	body_len = msg_len - header_len - 1;
  	body++;
  
  	/*
  	 * Transfer multiple chunks with the following extra header.
  	 * "ncfrag=<byte-offset>/<total-bytes>"
  	 */
  	memcpy(buf, header, header_len);
  
  	while (offset < body_len) {
  		int this_header = header_len;
  		int this_chunk;
  
  		this_header += scnprintf(buf + this_header,
  					 sizeof(buf) - this_header,
  					 ",ncfrag=%d/%d;", offset, body_len);
  
  		this_chunk = min(body_len - offset,
  				 MAX_PRINT_CHUNK - this_header);
  		if (WARN_ON_ONCE(this_chunk <= 0))
  			return;
  
  		memcpy(buf + this_header, body + offset, this_chunk);
  
  		netpoll_send_udp(&nt->np, buf, this_header + this_chunk);
  
  		offset += this_chunk;
  	}
  }
  
  static void write_ext_msg(struct console *con, const char *msg,
  			  unsigned int len)
  {
  	struct netconsole_target *nt;
  	unsigned long flags;
  
  	if ((oops_only && !oops_in_progress) || list_empty(&target_list))
  		return;
  
  	spin_lock_irqsave(&target_list_lock, flags);
  	list_for_each_entry(nt, &target_list, list)
  		if (nt->extended && nt->enabled && netif_running(nt->np.dev))
  			send_ext_msg_udp(nt, msg, len);
  	spin_unlock_irqrestore(&target_list_lock, flags);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
812
813
  static void write_msg(struct console *con, const char *msg, unsigned int len)
  {
  	int frag, left;
  	unsigned long flags;
b5427c271   Satyam Sharma   [NET] netconsole:...
814
815
  	struct netconsole_target *nt;
  	const char *tmp;
c1a608519   Amerigo Wang   netconsole: add o...
816
817
  	if (oops_only && !oops_in_progress)
  		return;
b5427c271   Satyam Sharma   [NET] netconsole:...
818
819
820
821
822
823
  	/* Avoid taking lock and disabling interrupts unnecessarily */
  	if (list_empty(&target_list))
  		return;
  
  	spin_lock_irqsave(&target_list_lock, flags);
  	list_for_each_entry(nt, &target_list, list) {
e2f15f9a7   Tejun Heo   netconsole: imple...
824
  		if (!nt->extended && nt->enabled && netif_running(nt->np.dev)) {
b5427c271   Satyam Sharma   [NET] netconsole:...
825
826
827
828
829
830
831
832
833
834
835
836
837
  			/*
  			 * We nest this inside the for-each-target loop above
  			 * so that we're able to get as much logging out to
  			 * at least one target if we die inside here, instead
  			 * of unnecessarily keeping all targets in lock-step.
  			 */
  			tmp = msg;
  			for (left = len; left;) {
  				frag = min(left, MAX_PRINT_CHUNK);
  				netpoll_send_udp(&nt->np, tmp, frag);
  				tmp += frag;
  				left -= frag;
  			}
0cc120bea   Satyam Sharma   [NET] netconsole:...
838
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  	}
b5427c271   Satyam Sharma   [NET] netconsole:...
840
  	spin_unlock_irqrestore(&target_list_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  }
e2f15f9a7   Tejun Heo   netconsole: imple...
842
843
844
845
846
  static struct console netconsole_ext = {
  	.name	= "netcon_ext",
  	.flags	= CON_EXTENDED,	/* starts disabled, registered on first use */
  	.write	= write_ext_msg,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
  static struct console netconsole = {
d39badf05   Satyam Sharma   [NET] netconsole:...
848
  	.name	= "netcon",
0517deed7   Michael Ellerman   netconsole: only ...
849
  	.flags	= CON_ENABLED,
d39badf05   Satyam Sharma   [NET] netconsole:...
850
  	.write	= write_msg,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
  };
d39badf05   Satyam Sharma   [NET] netconsole:...
852
  static int __init init_netconsole(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
  {
0bcc18161   Satyam Sharma   [NET] netconsole:...
854
  	int err;
b5427c271   Satyam Sharma   [NET] netconsole:...
855
856
857
858
  	struct netconsole_target *nt, *tmp;
  	unsigned long flags;
  	char *target_config;
  	char *input = config;
b41848b61   Stephen Hemminger   netpoll setup err...
859

0bcc18161   Satyam Sharma   [NET] netconsole:...
860
861
862
863
864
865
866
  	if (strnlen(input, MAX_PARAM_LENGTH)) {
  		while ((target_config = strsep(&input, ";"))) {
  			nt = alloc_param_target(target_config);
  			if (IS_ERR(nt)) {
  				err = PTR_ERR(nt);
  				goto fail;
  			}
0517deed7   Michael Ellerman   netconsole: only ...
867
  			/* Dump existing printks when we register */
e2f15f9a7   Tejun Heo   netconsole: imple...
868
869
870
871
872
  			if (nt->extended)
  				netconsole_ext.flags |= CON_PRINTBUFFER |
  							CON_ENABLED;
  			else
  				netconsole.flags |= CON_PRINTBUFFER;
0517deed7   Michael Ellerman   netconsole: only ...
873

0bcc18161   Satyam Sharma   [NET] netconsole:...
874
875
876
  			spin_lock_irqsave(&target_list_lock, flags);
  			list_add(&nt->list, &target_list);
  			spin_unlock_irqrestore(&target_list_lock, flags);
b5427c271   Satyam Sharma   [NET] netconsole:...
877
  		}
b5427c271   Satyam Sharma   [NET] netconsole:...
878
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879

17951f34b   Satyam Sharma   [NET] netconsole:...
880
881
  	err = register_netdevice_notifier(&netconsole_netdev_notifier);
  	if (err)
b5427c271   Satyam Sharma   [NET] netconsole:...
882
  		goto fail;
17951f34b   Satyam Sharma   [NET] netconsole:...
883

0bcc18161   Satyam Sharma   [NET] netconsole:...
884
885
886
  	err = dynamic_netconsole_init();
  	if (err)
  		goto undonotifier;
e2f15f9a7   Tejun Heo   netconsole: imple...
887
888
  	if (netconsole_ext.flags & CON_ENABLED)
  		register_console(&netconsole_ext);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
  	register_console(&netconsole);
22ded5772   Joe Perches   netconsole: Conve...
890
891
  	pr_info("network logging started
  ");
d39badf05   Satyam Sharma   [NET] netconsole:...
892

d39badf05   Satyam Sharma   [NET] netconsole:...
893
  	return err;
b5427c271   Satyam Sharma   [NET] netconsole:...
894

0bcc18161   Satyam Sharma   [NET] netconsole:...
895
896
  undonotifier:
  	unregister_netdevice_notifier(&netconsole_netdev_notifier);
b5427c271   Satyam Sharma   [NET] netconsole:...
897
  fail:
22ded5772   Joe Perches   netconsole: Conve...
898
899
  	pr_err("cleaning up
  ");
b5427c271   Satyam Sharma   [NET] netconsole:...
900
901
  
  	/*
0bcc18161   Satyam Sharma   [NET] netconsole:...
902
903
  	 * Remove all targets and destroy them (only targets created
  	 * from the boot/module option exist here). Skipping the list
b5427c271   Satyam Sharma   [NET] netconsole:...
904
905
906
907
  	 * lock is safe here, and netpoll_cleanup() will sleep.
  	 */
  	list_for_each_entry_safe(nt, tmp, &target_list, list) {
  		list_del(&nt->list);
0bcc18161   Satyam Sharma   [NET] netconsole:...
908
  		free_param_target(nt);
b5427c271   Satyam Sharma   [NET] netconsole:...
909
910
911
  	}
  
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  }
d39badf05   Satyam Sharma   [NET] netconsole:...
913
  static void __exit cleanup_netconsole(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
  {
b5427c271   Satyam Sharma   [NET] netconsole:...
915
  	struct netconsole_target *nt, *tmp;
df180e369   Satyam Sharma   [NET] netconsole:...
916

e2f15f9a7   Tejun Heo   netconsole: imple...
917
  	unregister_console(&netconsole_ext);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
  	unregister_console(&netconsole);
0bcc18161   Satyam Sharma   [NET] netconsole:...
919
  	dynamic_netconsole_exit();
17951f34b   Satyam Sharma   [NET] netconsole:...
920
  	unregister_netdevice_notifier(&netconsole_netdev_notifier);
b5427c271   Satyam Sharma   [NET] netconsole:...
921
922
  
  	/*
0bcc18161   Satyam Sharma   [NET] netconsole:...
923
924
925
926
927
928
  	 * Targets created via configfs pin references on our module
  	 * and would first be rmdir(2)'ed from userspace. We reach
  	 * here only when they are already destroyed, and only those
  	 * created from the boot/module option are left, so remove and
  	 * destroy them. Skipping the list lock is safe here, and
  	 * netpoll_cleanup() will sleep.
b5427c271   Satyam Sharma   [NET] netconsole:...
929
930
931
  	 */
  	list_for_each_entry_safe(nt, tmp, &target_list, list) {
  		list_del(&nt->list);
0bcc18161   Satyam Sharma   [NET] netconsole:...
932
  		free_param_target(nt);
b5427c271   Satyam Sharma   [NET] netconsole:...
933
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
  }
97c7de055   Lin Ming   netconsole: switc...
935
936
937
938
939
940
941
  /*
   * Use late_initcall to ensure netconsole is
   * initialized after network device driver if built-in.
   *
   * late_initcall() and module_init() are identical if built as module.
   */
  late_initcall(init_netconsole);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
  module_exit(cleanup_netconsole);