1 /* 2 * (C) Copyright 2004 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 #include <common.h> 25 #include <command.h> 26 #include <stdio_dev.h> 27 #include <net.h> 28 29 DECLARE_GLOBAL_DATA_PTR; 30 31 #ifndef CONFIG_NETCONSOLE_BUFFER_SIZE 32 #define CONFIG_NETCONSOLE_BUFFER_SIZE 512 33 #endif 34 35 static char input_buffer[CONFIG_NETCONSOLE_BUFFER_SIZE]; 36 static int input_size; /* char count in input buffer */ 37 static int input_offset; /* offset to valid chars in input buffer */ 38 static int input_recursion; 39 static int output_recursion; 40 static int net_timeout; 41 static uchar nc_ether[6]; /* server enet address */ 42 static IPaddr_t nc_ip; /* server ip */ 43 static short nc_out_port; /* target output port */ 44 static short nc_in_port; /* source input port */ 45 static const char *output_packet; /* used by first send udp */ 46 static int output_packet_len; 47 /* 48 * Start with a default last protocol. 49 * We are only interested in NETCONS or not. 50 */ 51 enum proto_t net_loop_last_protocol = BOOTP; 52 53 static void nc_wait_arp_handler(uchar *pkt, unsigned dest, 54 IPaddr_t sip, unsigned src, 55 unsigned len) 56 { 57 net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */ 58 } 59 60 static void nc_handler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, 61 unsigned len) 62 { 63 if (input_size) 64 net_set_state(NETLOOP_SUCCESS); /* got input - quit net loop */ 65 } 66 67 static void nc_timeout(void) 68 { 69 net_set_state(NETLOOP_SUCCESS); 70 } 71 72 void NcStart(void) 73 { 74 if (!output_packet_len || memcmp(nc_ether, NetEtherNullAddr, 6)) { 75 /* going to check for input packet */ 76 net_set_udp_handler(nc_handler); 77 NetSetTimeout(net_timeout, nc_timeout); 78 } else { 79 /* send arp request */ 80 uchar *pkt; 81 net_set_arp_handler(nc_wait_arp_handler); 82 pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE; 83 memcpy(pkt, output_packet, output_packet_len); 84 NetSendUDPPacket(nc_ether, nc_ip, nc_out_port, nc_in_port, 85 output_packet_len); 86 } 87 } 88 89 int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len) 90 { 91 int end, chunk; 92 93 if (dest != nc_in_port || !len) 94 return 0; /* not for us */ 95 96 debug_cond(DEBUG_DEV_PKT, "input: \"%*.*s\"\n", len, len, pkt); 97 98 if (input_size == sizeof(input_buffer)) 99 return 1; /* no space */ 100 if (len > sizeof(input_buffer) - input_size) 101 len = sizeof(input_buffer) - input_size; 102 103 end = input_offset + input_size; 104 if (end > sizeof(input_buffer)) 105 end -= sizeof(input_buffer); 106 107 chunk = len; 108 if (end + len > sizeof(input_buffer)) { 109 chunk = sizeof(input_buffer) - end; 110 memcpy(input_buffer, pkt + chunk, len - chunk); 111 } 112 memcpy(input_buffer + end, pkt, chunk); 113 114 input_size += len; 115 116 return 1; 117 } 118 119 static void nc_send_packet(const char *buf, int len) 120 { 121 struct eth_device *eth; 122 int inited = 0; 123 uchar *pkt; 124 uchar *ether; 125 IPaddr_t ip; 126 127 debug_cond(DEBUG_DEV_PKT, "output: \"%*.*s\"\n", len, len, buf); 128 129 eth = eth_get_dev(); 130 if (eth == NULL) 131 return; 132 133 if (!memcmp(nc_ether, NetEtherNullAddr, 6)) { 134 if (eth->state == ETH_STATE_ACTIVE) 135 return; /* inside net loop */ 136 output_packet = buf; 137 output_packet_len = len; 138 NetLoop(NETCONS); /* wait for arp reply and send packet */ 139 output_packet_len = 0; 140 return; 141 } 142 143 if (eth->state != ETH_STATE_ACTIVE) { 144 if (eth_is_on_demand_init()) { 145 if (eth_init(gd->bd) < 0) 146 return; 147 eth_set_last_protocol(NETCONS); 148 } else 149 eth_init_state_only(gd->bd); 150 151 inited = 1; 152 } 153 pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE; 154 memcpy(pkt, buf, len); 155 ether = nc_ether; 156 ip = nc_ip; 157 NetSendUDPPacket(ether, ip, nc_out_port, nc_in_port, len); 158 159 if (inited) { 160 if (eth_is_on_demand_init()) 161 eth_halt(); 162 else 163 eth_halt_state_only(); 164 } 165 } 166 167 static int nc_start(void) 168 { 169 int netmask, our_ip; 170 char *p; 171 172 nc_out_port = 6666; /* default port */ 173 nc_in_port = nc_out_port; 174 175 if (getenv("ncip")) { 176 177 nc_ip = getenv_IPaddr("ncip"); 178 if (!nc_ip) 179 return -1; /* ncip is 0.0.0.0 */ 180 p = strchr(getenv("ncip"), ':'); 181 if (p != NULL) { 182 nc_out_port = simple_strtoul(p + 1, NULL, 10); 183 nc_in_port = nc_out_port; 184 } 185 } else 186 nc_ip = ~0; /* ncip is not set, so broadcast */ 187 188 p = getenv("ncoutport"); 189 if (p != NULL) 190 nc_out_port = simple_strtoul(p, NULL, 10); 191 p = getenv("ncinport"); 192 if (p != NULL) 193 nc_in_port = simple_strtoul(p, NULL, 10); 194 195 our_ip = getenv_IPaddr("ipaddr"); 196 netmask = getenv_IPaddr("netmask"); 197 198 if (nc_ip == ~0 || /* 255.255.255.255 */ 199 ((netmask & our_ip) == (netmask & nc_ip) && /* on the same net */ 200 (netmask | nc_ip) == ~0)) /* broadcast to our net */ 201 memset(nc_ether, 0xff, sizeof(nc_ether)); 202 else 203 memset(nc_ether, 0, sizeof(nc_ether)); /* force arp request */ 204 205 /* 206 * Initialize the static IP settings and buffer pointers 207 * incase we call NetSendUDPPacket before NetLoop 208 */ 209 net_init(); 210 211 return 0; 212 } 213 214 static void nc_putc(char c) 215 { 216 if (output_recursion) 217 return; 218 output_recursion = 1; 219 220 nc_send_packet(&c, 1); 221 222 output_recursion = 0; 223 } 224 225 static void nc_puts(const char *s) 226 { 227 int len; 228 229 if (output_recursion) 230 return; 231 output_recursion = 1; 232 233 len = strlen(s); 234 while (len) { 235 int send_len = min(len, sizeof(input_buffer)); 236 nc_send_packet(s, send_len); 237 len -= send_len; 238 s += send_len; 239 } 240 241 output_recursion = 0; 242 } 243 244 static int nc_getc(void) 245 { 246 uchar c; 247 248 input_recursion = 1; 249 250 net_timeout = 0; /* no timeout */ 251 while (!input_size) 252 NetLoop(NETCONS); 253 254 input_recursion = 0; 255 256 c = input_buffer[input_offset++]; 257 258 if (input_offset >= sizeof(input_buffer)) 259 input_offset -= sizeof(input_buffer); 260 input_size--; 261 262 return c; 263 } 264 265 static int nc_tstc(void) 266 { 267 struct eth_device *eth; 268 269 if (input_recursion) 270 return 0; 271 272 if (input_size) 273 return 1; 274 275 eth = eth_get_dev(); 276 if (eth && eth->state == ETH_STATE_ACTIVE) 277 return 0; /* inside net loop */ 278 279 input_recursion = 1; 280 281 net_timeout = 1; 282 NetLoop(NETCONS); /* kind of poll */ 283 284 input_recursion = 0; 285 286 return input_size != 0; 287 } 288 289 int drv_nc_init(void) 290 { 291 struct stdio_dev dev; 292 int rc; 293 294 memset(&dev, 0, sizeof(dev)); 295 296 strcpy(dev.name, "nc"); 297 dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; 298 dev.start = nc_start; 299 dev.putc = nc_putc; 300 dev.puts = nc_puts; 301 dev.getc = nc_getc; 302 dev.tstc = nc_tstc; 303 304 rc = stdio_register(&dev); 305 306 return (rc == 0) ? 1 : rc; 307 } 308