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(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 p = getenv("ncoutport"); 98 if (p != NULL) 99 nc_out_port = simple_strtoul(p, NULL, 10); 100 p = getenv("ncinport"); 101 if (p != NULL) 102 nc_in_port = simple_strtoul(p, NULL, 10); 103 104 if (is_broadcast(nc_ip)) 105 /* broadcast MAC address */ 106 memset(nc_ether, 0xff, sizeof(nc_ether)); 107 else 108 /* force arp request */ 109 memset(nc_ether, 0, sizeof(nc_ether)); 110 } 111 return 0; 112 } 113 114 /** 115 * Called from NetLoop in net/net.c before each packet 116 */ 117 void NcStart(void) 118 { 119 refresh_settings_from_env(); 120 if (!output_packet_len || memcmp(nc_ether, net_null_ethaddr, 6)) { 121 /* going to check for input packet */ 122 net_set_udp_handler(nc_handler); 123 NetSetTimeout(net_timeout, nc_timeout); 124 } else { 125 /* send arp request */ 126 uchar *pkt; 127 net_set_arp_handler(nc_wait_arp_handler); 128 pkt = (uchar *)net_tx_packet + net_eth_hdr_size() + 129 IP_UDP_HDR_SIZE; 130 memcpy(pkt, output_packet, output_packet_len); 131 net_send_udp_packet(nc_ether, nc_ip, nc_out_port, nc_in_port, 132 output_packet_len); 133 } 134 } 135 136 int nc_input_packet(uchar *pkt, struct in_addr src_ip, unsigned dest_port, 137 unsigned src_port, unsigned len) 138 { 139 int end, chunk; 140 141 if (dest_port != nc_in_port || !len) 142 return 0; /* not for us */ 143 144 if (src_ip.s_addr != nc_ip.s_addr && !is_broadcast(nc_ip)) 145 return 0; /* not from our client */ 146 147 debug_cond(DEBUG_DEV_PKT, "input: \"%*.*s\"\n", len, len, pkt); 148 149 if (input_size == sizeof(input_buffer)) 150 return 1; /* no space */ 151 if (len > sizeof(input_buffer) - input_size) 152 len = sizeof(input_buffer) - input_size; 153 154 end = input_offset + input_size; 155 if (end > sizeof(input_buffer)) 156 end -= sizeof(input_buffer); 157 158 chunk = len; 159 if (end + len > sizeof(input_buffer)) { 160 chunk = sizeof(input_buffer) - end; 161 memcpy(input_buffer, pkt + chunk, len - chunk); 162 } 163 memcpy(input_buffer + end, pkt, chunk); 164 165 input_size += len; 166 167 return 1; 168 } 169 170 static void nc_send_packet(const char *buf, int len) 171 { 172 struct eth_device *eth; 173 int inited = 0; 174 uchar *pkt; 175 uchar *ether; 176 struct in_addr ip; 177 178 debug_cond(DEBUG_DEV_PKT, "output: \"%*.*s\"\n", len, len, buf); 179 180 eth = eth_get_dev(); 181 if (eth == NULL) 182 return; 183 184 if (!memcmp(nc_ether, net_null_ethaddr, 6)) { 185 if (eth->state == ETH_STATE_ACTIVE) 186 return; /* inside net loop */ 187 output_packet = buf; 188 output_packet_len = len; 189 input_recursion = 1; 190 NetLoop(NETCONS); /* wait for arp reply and send packet */ 191 input_recursion = 0; 192 output_packet_len = 0; 193 return; 194 } 195 196 if (eth->state != ETH_STATE_ACTIVE) { 197 if (eth_is_on_demand_init()) { 198 if (eth_init() < 0) 199 return; 200 eth_set_last_protocol(NETCONS); 201 } else 202 eth_init_state_only(); 203 204 inited = 1; 205 } 206 pkt = (uchar *)net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE; 207 memcpy(pkt, buf, len); 208 ether = nc_ether; 209 ip = nc_ip; 210 net_send_udp_packet(ether, ip, nc_out_port, nc_in_port, len); 211 212 if (inited) { 213 if (eth_is_on_demand_init()) 214 eth_halt(); 215 else 216 eth_halt_state_only(); 217 } 218 } 219 220 static int nc_start(struct stdio_dev *dev) 221 { 222 int retval; 223 224 nc_out_port = 6666; /* default port */ 225 nc_in_port = nc_out_port; 226 227 retval = refresh_settings_from_env(); 228 if (retval != 0) 229 return retval; 230 231 /* 232 * Initialize the static IP settings and buffer pointers 233 * incase we call net_send_udp_packet before NetLoop 234 */ 235 net_init(); 236 237 return 0; 238 } 239 240 static void nc_putc(struct stdio_dev *dev, char c) 241 { 242 if (output_recursion) 243 return; 244 output_recursion = 1; 245 246 nc_send_packet(&c, 1); 247 248 output_recursion = 0; 249 } 250 251 static void nc_puts(struct stdio_dev *dev, const char *s) 252 { 253 int len; 254 255 if (output_recursion) 256 return; 257 output_recursion = 1; 258 259 len = strlen(s); 260 while (len) { 261 int send_len = min(len, (int)sizeof(input_buffer)); 262 nc_send_packet(s, send_len); 263 len -= send_len; 264 s += send_len; 265 } 266 267 output_recursion = 0; 268 } 269 270 static int nc_getc(struct stdio_dev *dev) 271 { 272 uchar c; 273 274 input_recursion = 1; 275 276 net_timeout = 0; /* no timeout */ 277 while (!input_size) 278 NetLoop(NETCONS); 279 280 input_recursion = 0; 281 282 c = input_buffer[input_offset++]; 283 284 if (input_offset >= sizeof(input_buffer)) 285 input_offset -= sizeof(input_buffer); 286 input_size--; 287 288 return c; 289 } 290 291 static int nc_tstc(struct stdio_dev *dev) 292 { 293 struct eth_device *eth; 294 295 if (input_recursion) 296 return 0; 297 298 if (input_size) 299 return 1; 300 301 eth = eth_get_dev(); 302 if (eth && eth->state == ETH_STATE_ACTIVE) 303 return 0; /* inside net loop */ 304 305 input_recursion = 1; 306 307 net_timeout = 1; 308 NetLoop(NETCONS); /* kind of poll */ 309 310 input_recursion = 0; 311 312 return input_size != 0; 313 } 314 315 int drv_nc_init(void) 316 { 317 struct stdio_dev dev; 318 int rc; 319 320 memset(&dev, 0, sizeof(dev)); 321 322 strcpy(dev.name, "nc"); 323 dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; 324 dev.start = nc_start; 325 dev.putc = nc_putc; 326 dev.puts = nc_puts; 327 dev.getc = nc_getc; 328 dev.tstc = nc_tstc; 329 330 rc = stdio_register(&dev); 331 332 return (rc == 0) ? 1 : rc; 333 } 334