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 = getenv_ip("netmask"); 66 our_ip = getenv_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 (getenv("ncip")) { 86 nc_ip = getenv_ip("ncip"); 87 if (!nc_ip.s_addr) 88 return -1; /* ncip is 0.0.0.0 */ 89 p = strchr(getenv("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 = getenv("ncoutport"); 99 if (p != NULL) 100 nc_out_port = simple_strtoul(p, NULL, 10); 101 p = getenv("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 if (end + len > sizeof(input_buffer)) { 161 chunk = sizeof(input_buffer) - end; 162 memcpy(input_buffer, pkt + chunk, len - chunk); 163 } 164 memcpy(input_buffer + end, pkt, chunk); 165 166 input_size += len; 167 168 return 1; 169 } 170 171 static void nc_send_packet(const char *buf, int len) 172 { 173 #ifdef CONFIG_DM_ETH 174 struct udevice *eth; 175 #else 176 struct eth_device *eth; 177 #endif 178 int inited = 0; 179 uchar *pkt; 180 uchar *ether; 181 struct in_addr ip; 182 183 debug_cond(DEBUG_DEV_PKT, "output: \"%*.*s\"\n", len, len, buf); 184 185 eth = eth_get_dev(); 186 if (eth == NULL) 187 return; 188 189 if (!memcmp(nc_ether, net_null_ethaddr, 6)) { 190 if (eth_is_active(eth)) 191 return; /* inside net loop */ 192 output_packet = buf; 193 output_packet_len = len; 194 input_recursion = 1; 195 net_loop(NETCONS); /* wait for arp reply and send packet */ 196 input_recursion = 0; 197 output_packet_len = 0; 198 return; 199 } 200 201 if (!eth_is_active(eth)) { 202 if (eth_is_on_demand_init()) { 203 if (eth_init() < 0) 204 return; 205 eth_set_last_protocol(NETCONS); 206 } else { 207 eth_init_state_only(); 208 } 209 210 inited = 1; 211 } 212 pkt = (uchar *)net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE; 213 memcpy(pkt, buf, len); 214 ether = nc_ether; 215 ip = nc_ip; 216 net_send_udp_packet(ether, ip, nc_out_port, nc_in_port, len); 217 218 if (inited) { 219 if (eth_is_on_demand_init()) 220 eth_halt(); 221 else 222 eth_halt_state_only(); 223 } 224 } 225 226 static int nc_stdio_start(struct stdio_dev *dev) 227 { 228 int retval; 229 230 nc_out_port = 6666; /* default port */ 231 nc_in_port = nc_out_port; 232 233 retval = refresh_settings_from_env(); 234 if (retval != 0) 235 return retval; 236 237 /* 238 * Initialize the static IP settings and buffer pointers 239 * incase we call net_send_udp_packet before net_loop 240 */ 241 net_init(); 242 243 return 0; 244 } 245 246 static void nc_stdio_putc(struct stdio_dev *dev, char c) 247 { 248 if (output_recursion) 249 return; 250 output_recursion = 1; 251 252 nc_send_packet(&c, 1); 253 254 output_recursion = 0; 255 } 256 257 static void nc_stdio_puts(struct stdio_dev *dev, const char *s) 258 { 259 int len; 260 261 if (output_recursion) 262 return; 263 output_recursion = 1; 264 265 len = strlen(s); 266 while (len) { 267 int send_len = min(len, (int)sizeof(input_buffer)); 268 nc_send_packet(s, send_len); 269 len -= send_len; 270 s += send_len; 271 } 272 273 output_recursion = 0; 274 } 275 276 static int nc_stdio_getc(struct stdio_dev *dev) 277 { 278 uchar c; 279 280 input_recursion = 1; 281 282 net_timeout = 0; /* no timeout */ 283 while (!input_size) 284 net_loop(NETCONS); 285 286 input_recursion = 0; 287 288 c = input_buffer[input_offset++]; 289 290 if (input_offset >= sizeof(input_buffer)) 291 input_offset -= sizeof(input_buffer); 292 input_size--; 293 294 return c; 295 } 296 297 static int nc_stdio_tstc(struct stdio_dev *dev) 298 { 299 #ifdef CONFIG_DM_ETH 300 struct udevice *eth; 301 #else 302 struct eth_device *eth; 303 #endif 304 305 if (input_recursion) 306 return 0; 307 308 if (input_size) 309 return 1; 310 311 eth = eth_get_dev(); 312 if (eth_is_active(eth)) 313 return 0; /* inside net loop */ 314 315 input_recursion = 1; 316 317 net_timeout = 1; 318 net_loop(NETCONS); /* kind of poll */ 319 320 input_recursion = 0; 321 322 return input_size != 0; 323 } 324 325 int drv_nc_init(void) 326 { 327 struct stdio_dev dev; 328 int rc; 329 330 memset(&dev, 0, sizeof(dev)); 331 332 strcpy(dev.name, "nc"); 333 dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; 334 dev.start = nc_stdio_start; 335 dev.putc = nc_stdio_putc; 336 dev.puts = nc_stdio_puts; 337 dev.getc = nc_stdio_getc; 338 dev.tstc = nc_stdio_tstc; 339 340 rc = stdio_register(&dev); 341 342 return (rc == 0) ? 1 : rc; 343 } 344