xref: /OK3568_Linux_fs/u-boot/drivers/net/netconsole.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2004
3*4882a593Smuzhiyun  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <command.h>
10*4882a593Smuzhiyun #include <stdio_dev.h>
11*4882a593Smuzhiyun #include <net.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #ifndef CONFIG_NETCONSOLE_BUFFER_SIZE
16*4882a593Smuzhiyun #define CONFIG_NETCONSOLE_BUFFER_SIZE 512
17*4882a593Smuzhiyun #endif
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun static char input_buffer[CONFIG_NETCONSOLE_BUFFER_SIZE];
20*4882a593Smuzhiyun static int input_size; /* char count in input buffer */
21*4882a593Smuzhiyun static int input_offset; /* offset to valid chars in input buffer */
22*4882a593Smuzhiyun static int input_recursion;
23*4882a593Smuzhiyun static int output_recursion;
24*4882a593Smuzhiyun static int net_timeout;
25*4882a593Smuzhiyun static uchar nc_ether[6]; /* server enet address */
26*4882a593Smuzhiyun static struct in_addr nc_ip; /* server ip */
27*4882a593Smuzhiyun static short nc_out_port; /* target output port */
28*4882a593Smuzhiyun static short nc_in_port; /* source input port */
29*4882a593Smuzhiyun static const char *output_packet; /* used by first send udp */
30*4882a593Smuzhiyun static int output_packet_len;
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun  * Start with a default last protocol.
33*4882a593Smuzhiyun  * We are only interested in NETCONS or not.
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun enum proto_t net_loop_last_protocol = BOOTP;
36*4882a593Smuzhiyun 
nc_wait_arp_handler(uchar * pkt,unsigned dest,struct in_addr sip,unsigned src,unsigned len)37*4882a593Smuzhiyun static void nc_wait_arp_handler(uchar *pkt, unsigned dest,
38*4882a593Smuzhiyun 				 struct in_addr sip, unsigned src,
39*4882a593Smuzhiyun 				 unsigned len)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
nc_handler(uchar * pkt,unsigned dest,struct in_addr sip,unsigned src,unsigned len)44*4882a593Smuzhiyun static void nc_handler(uchar *pkt, unsigned dest, struct in_addr sip,
45*4882a593Smuzhiyun 		       unsigned src, unsigned len)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	if (input_size)
48*4882a593Smuzhiyun 		net_set_state(NETLOOP_SUCCESS); /* got input - quit net loop */
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
nc_timeout_handler(void)51*4882a593Smuzhiyun static void nc_timeout_handler(void)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	net_set_state(NETLOOP_SUCCESS);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
is_broadcast(struct in_addr ip)56*4882a593Smuzhiyun static int is_broadcast(struct in_addr ip)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	static struct in_addr netmask;
59*4882a593Smuzhiyun 	static struct in_addr our_ip;
60*4882a593Smuzhiyun 	static int env_changed_id;
61*4882a593Smuzhiyun 	int env_id = get_env_id();
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	/* update only when the environment has changed */
64*4882a593Smuzhiyun 	if (env_changed_id != env_id) {
65*4882a593Smuzhiyun 		netmask = env_get_ip("netmask");
66*4882a593Smuzhiyun 		our_ip = env_get_ip("ipaddr");
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 		env_changed_id = env_id;
69*4882a593Smuzhiyun 	}
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	return (ip.s_addr == ~0 || /* 255.255.255.255 (global bcast) */
72*4882a593Smuzhiyun 		((netmask.s_addr & our_ip.s_addr) ==
73*4882a593Smuzhiyun 		 (netmask.s_addr & ip.s_addr) && /* on the same net and */
74*4882a593Smuzhiyun 		 (netmask.s_addr | ip.s_addr) == ~0)); /* bcast to our net */
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
refresh_settings_from_env(void)77*4882a593Smuzhiyun static int refresh_settings_from_env(void)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	const char *p;
80*4882a593Smuzhiyun 	static int env_changed_id;
81*4882a593Smuzhiyun 	int env_id = get_env_id();
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	/* update only when the environment has changed */
84*4882a593Smuzhiyun 	if (env_changed_id != env_id) {
85*4882a593Smuzhiyun 		if (env_get("ncip")) {
86*4882a593Smuzhiyun 			nc_ip = env_get_ip("ncip");
87*4882a593Smuzhiyun 			if (!nc_ip.s_addr)
88*4882a593Smuzhiyun 				return -1;	/* ncip is 0.0.0.0 */
89*4882a593Smuzhiyun 			p = strchr(env_get("ncip"), ':');
90*4882a593Smuzhiyun 			if (p != NULL) {
91*4882a593Smuzhiyun 				nc_out_port = simple_strtoul(p + 1, NULL, 10);
92*4882a593Smuzhiyun 				nc_in_port = nc_out_port;
93*4882a593Smuzhiyun 			}
94*4882a593Smuzhiyun 		} else {
95*4882a593Smuzhiyun 			nc_ip.s_addr = ~0; /* ncip is not set, so broadcast */
96*4882a593Smuzhiyun 		}
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 		p = env_get("ncoutport");
99*4882a593Smuzhiyun 		if (p != NULL)
100*4882a593Smuzhiyun 			nc_out_port = simple_strtoul(p, NULL, 10);
101*4882a593Smuzhiyun 		p = env_get("ncinport");
102*4882a593Smuzhiyun 		if (p != NULL)
103*4882a593Smuzhiyun 			nc_in_port = simple_strtoul(p, NULL, 10);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 		if (is_broadcast(nc_ip))
106*4882a593Smuzhiyun 			/* broadcast MAC address */
107*4882a593Smuzhiyun 			memset(nc_ether, 0xff, sizeof(nc_ether));
108*4882a593Smuzhiyun 		else
109*4882a593Smuzhiyun 			/* force arp request */
110*4882a593Smuzhiyun 			memset(nc_ether, 0, sizeof(nc_ether));
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun 	return 0;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun /**
116*4882a593Smuzhiyun  * Called from net_loop in net/net.c before each packet
117*4882a593Smuzhiyun  */
nc_start(void)118*4882a593Smuzhiyun void nc_start(void)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	refresh_settings_from_env();
121*4882a593Smuzhiyun 	if (!output_packet_len || memcmp(nc_ether, net_null_ethaddr, 6)) {
122*4882a593Smuzhiyun 		/* going to check for input packet */
123*4882a593Smuzhiyun 		net_set_udp_handler(nc_handler);
124*4882a593Smuzhiyun 		net_set_timeout_handler(net_timeout, nc_timeout_handler);
125*4882a593Smuzhiyun 	} else {
126*4882a593Smuzhiyun 		/* send arp request */
127*4882a593Smuzhiyun 		uchar *pkt;
128*4882a593Smuzhiyun 		net_set_arp_handler(nc_wait_arp_handler);
129*4882a593Smuzhiyun 		pkt = (uchar *)net_tx_packet + net_eth_hdr_size() +
130*4882a593Smuzhiyun 			IP_UDP_HDR_SIZE;
131*4882a593Smuzhiyun 		memcpy(pkt, output_packet, output_packet_len);
132*4882a593Smuzhiyun 		net_send_udp_packet(nc_ether, nc_ip, nc_out_port, nc_in_port,
133*4882a593Smuzhiyun 				    output_packet_len);
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
nc_input_packet(uchar * pkt,struct in_addr src_ip,unsigned dest_port,unsigned src_port,unsigned len)137*4882a593Smuzhiyun int nc_input_packet(uchar *pkt, struct in_addr src_ip, unsigned dest_port,
138*4882a593Smuzhiyun 	unsigned src_port, unsigned len)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	int end, chunk;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	if (dest_port != nc_in_port || !len)
143*4882a593Smuzhiyun 		return 0; /* not for us */
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	if (src_ip.s_addr != nc_ip.s_addr && !is_broadcast(nc_ip))
146*4882a593Smuzhiyun 		return 0; /* not from our client */
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	debug_cond(DEBUG_DEV_PKT, "input: \"%*.*s\"\n", len, len, pkt);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	if (input_size == sizeof(input_buffer))
151*4882a593Smuzhiyun 		return 1; /* no space */
152*4882a593Smuzhiyun 	if (len > sizeof(input_buffer) - input_size)
153*4882a593Smuzhiyun 		len = sizeof(input_buffer) - input_size;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	end = input_offset + input_size;
156*4882a593Smuzhiyun 	if (end > sizeof(input_buffer))
157*4882a593Smuzhiyun 		end -= sizeof(input_buffer);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	chunk = len;
160*4882a593Smuzhiyun 	if (end + len > sizeof(input_buffer)) {
161*4882a593Smuzhiyun 		chunk = sizeof(input_buffer) - end;
162*4882a593Smuzhiyun 		memcpy(input_buffer, pkt + chunk, len - chunk);
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 	memcpy(input_buffer + end, pkt, chunk);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	input_size += len;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	return 1;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
nc_send_packet(const char * buf,int len)171*4882a593Smuzhiyun static void nc_send_packet(const char *buf, int len)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun #ifdef CONFIG_DM_ETH
174*4882a593Smuzhiyun 	struct udevice *eth;
175*4882a593Smuzhiyun #else
176*4882a593Smuzhiyun 	struct eth_device *eth;
177*4882a593Smuzhiyun #endif
178*4882a593Smuzhiyun 	int inited = 0;
179*4882a593Smuzhiyun 	uchar *pkt;
180*4882a593Smuzhiyun 	uchar *ether;
181*4882a593Smuzhiyun 	struct in_addr ip;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	debug_cond(DEBUG_DEV_PKT, "output: \"%*.*s\"\n", len, len, buf);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	eth = eth_get_dev();
186*4882a593Smuzhiyun 	if (eth == NULL)
187*4882a593Smuzhiyun 		return;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	if (!memcmp(nc_ether, net_null_ethaddr, 6)) {
190*4882a593Smuzhiyun 		if (eth_is_active(eth))
191*4882a593Smuzhiyun 			return;	/* inside net loop */
192*4882a593Smuzhiyun 		output_packet = buf;
193*4882a593Smuzhiyun 		output_packet_len = len;
194*4882a593Smuzhiyun 		input_recursion = 1;
195*4882a593Smuzhiyun 		net_loop(NETCONS); /* wait for arp reply and send packet */
196*4882a593Smuzhiyun 		input_recursion = 0;
197*4882a593Smuzhiyun 		output_packet_len = 0;
198*4882a593Smuzhiyun 		return;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	if (!eth_is_active(eth)) {
202*4882a593Smuzhiyun 		if (eth_is_on_demand_init()) {
203*4882a593Smuzhiyun 			if (eth_init() < 0)
204*4882a593Smuzhiyun 				return;
205*4882a593Smuzhiyun 			eth_set_last_protocol(NETCONS);
206*4882a593Smuzhiyun 		} else {
207*4882a593Smuzhiyun 			eth_init_state_only();
208*4882a593Smuzhiyun 		}
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 		inited = 1;
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 	pkt = (uchar *)net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
213*4882a593Smuzhiyun 	memcpy(pkt, buf, len);
214*4882a593Smuzhiyun 	ether = nc_ether;
215*4882a593Smuzhiyun 	ip = nc_ip;
216*4882a593Smuzhiyun 	net_send_udp_packet(ether, ip, nc_out_port, nc_in_port, len);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	if (inited) {
219*4882a593Smuzhiyun 		if (eth_is_on_demand_init())
220*4882a593Smuzhiyun 			eth_halt();
221*4882a593Smuzhiyun 		else
222*4882a593Smuzhiyun 			eth_halt_state_only();
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
nc_stdio_start(struct stdio_dev * dev)226*4882a593Smuzhiyun static int nc_stdio_start(struct stdio_dev *dev)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun 	int retval;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	nc_out_port = 6666; /* default port */
231*4882a593Smuzhiyun 	nc_in_port = nc_out_port;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	retval = refresh_settings_from_env();
234*4882a593Smuzhiyun 	if (retval != 0)
235*4882a593Smuzhiyun 		return retval;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	/*
238*4882a593Smuzhiyun 	 * Initialize the static IP settings and buffer pointers
239*4882a593Smuzhiyun 	 * incase we call net_send_udp_packet before net_loop
240*4882a593Smuzhiyun 	 */
241*4882a593Smuzhiyun 	net_init();
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	return 0;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
nc_stdio_putc(struct stdio_dev * dev,char c)246*4882a593Smuzhiyun static void nc_stdio_putc(struct stdio_dev *dev, char c)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	if (output_recursion)
249*4882a593Smuzhiyun 		return;
250*4882a593Smuzhiyun 	output_recursion = 1;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	nc_send_packet(&c, 1);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	output_recursion = 0;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun 
nc_stdio_puts(struct stdio_dev * dev,const char * s)257*4882a593Smuzhiyun static void nc_stdio_puts(struct stdio_dev *dev, const char *s)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	int len;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	if (output_recursion)
262*4882a593Smuzhiyun 		return;
263*4882a593Smuzhiyun 	output_recursion = 1;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	len = strlen(s);
266*4882a593Smuzhiyun 	while (len) {
267*4882a593Smuzhiyun 		int send_len = min(len, (int)sizeof(input_buffer));
268*4882a593Smuzhiyun 		nc_send_packet(s, send_len);
269*4882a593Smuzhiyun 		len -= send_len;
270*4882a593Smuzhiyun 		s += send_len;
271*4882a593Smuzhiyun 	}
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	output_recursion = 0;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun 
nc_stdio_getc(struct stdio_dev * dev)276*4882a593Smuzhiyun static int nc_stdio_getc(struct stdio_dev *dev)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	uchar c;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	input_recursion = 1;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	net_timeout = 0;	/* no timeout */
283*4882a593Smuzhiyun 	while (!input_size)
284*4882a593Smuzhiyun 		net_loop(NETCONS);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	input_recursion = 0;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	c = input_buffer[input_offset++];
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	if (input_offset >= sizeof(input_buffer))
291*4882a593Smuzhiyun 		input_offset -= sizeof(input_buffer);
292*4882a593Smuzhiyun 	input_size--;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	return c;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
nc_stdio_tstc(struct stdio_dev * dev)297*4882a593Smuzhiyun static int nc_stdio_tstc(struct stdio_dev *dev)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun #ifdef CONFIG_DM_ETH
300*4882a593Smuzhiyun 	struct udevice *eth;
301*4882a593Smuzhiyun #else
302*4882a593Smuzhiyun 	struct eth_device *eth;
303*4882a593Smuzhiyun #endif
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	if (input_recursion)
306*4882a593Smuzhiyun 		return 0;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (input_size)
309*4882a593Smuzhiyun 		return 1;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	eth = eth_get_dev();
312*4882a593Smuzhiyun 	if (eth_is_active(eth))
313*4882a593Smuzhiyun 		return 0;	/* inside net loop */
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	input_recursion = 1;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	net_timeout = 1;
318*4882a593Smuzhiyun 	net_loop(NETCONS);	/* kind of poll */
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	input_recursion = 0;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	return input_size != 0;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
drv_nc_init(void)325*4882a593Smuzhiyun int drv_nc_init(void)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	struct stdio_dev dev;
328*4882a593Smuzhiyun 	int rc;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	memset(&dev, 0, sizeof(dev));
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	strcpy(dev.name, "nc");
333*4882a593Smuzhiyun 	dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
334*4882a593Smuzhiyun 	dev.start = nc_stdio_start;
335*4882a593Smuzhiyun 	dev.putc = nc_stdio_putc;
336*4882a593Smuzhiyun 	dev.puts = nc_stdio_puts;
337*4882a593Smuzhiyun 	dev.getc = nc_stdio_getc;
338*4882a593Smuzhiyun 	dev.tstc = nc_stdio_tstc;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	rc = stdio_register(&dev);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	return (rc == 0) ? 1 : rc;
343*4882a593Smuzhiyun }
344