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