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