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 static void nc_wait_arp_handler(uchar *pkt, unsigned dest, 49 IPaddr_t sip, unsigned src, 50 unsigned len) 51 { 52 net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */ 53 } 54 55 static void nc_handler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, 56 unsigned len) 57 { 58 if (input_size) 59 net_set_state(NETLOOP_SUCCESS); /* got input - quit net loop */ 60 } 61 62 static void nc_timeout(void) 63 { 64 net_set_state(NETLOOP_SUCCESS); 65 } 66 67 void NcStart(void) 68 { 69 if (!output_packet_len || memcmp(nc_ether, NetEtherNullAddr, 6)) { 70 /* going to check for input packet */ 71 net_set_udp_handler(nc_handler); 72 NetSetTimeout(net_timeout, nc_timeout); 73 } else { 74 /* send arp request */ 75 uchar *pkt; 76 net_set_arp_handler(nc_wait_arp_handler); 77 pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE; 78 memcpy(pkt, output_packet, output_packet_len); 79 NetSendUDPPacket(nc_ether, nc_ip, nc_out_port, nc_in_port, 80 output_packet_len); 81 } 82 } 83 84 int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len) 85 { 86 int end, chunk; 87 88 if (dest != nc_in_port || !len) 89 return 0; /* not for us */ 90 91 debug_cond(DEBUG_DEV_PKT, "input: \"%*.*s\"\n", len, len, pkt); 92 93 if (input_size == sizeof(input_buffer)) 94 return 1; /* no space */ 95 if (len > sizeof(input_buffer) - input_size) 96 len = sizeof(input_buffer) - input_size; 97 98 end = input_offset + input_size; 99 if (end > sizeof(input_buffer)) 100 end -= sizeof(input_buffer); 101 102 chunk = len; 103 if (end + len > sizeof(input_buffer)) { 104 chunk = sizeof(input_buffer) - end; 105 memcpy(input_buffer, pkt + chunk, len - chunk); 106 } 107 memcpy(input_buffer + end, pkt, chunk); 108 109 input_size += len; 110 111 return 1; 112 } 113 114 static void nc_send_packet(const char *buf, int len) 115 { 116 struct eth_device *eth; 117 int inited = 0; 118 uchar *pkt; 119 uchar *ether; 120 IPaddr_t ip; 121 122 debug_cond(DEBUG_DEV_PKT, "output: \"%*.*s\"\n", len, len, buf); 123 124 eth = eth_get_dev(); 125 if (eth == NULL) 126 return; 127 128 if (!memcmp(nc_ether, NetEtherNullAddr, 6)) { 129 if (eth->state == ETH_STATE_ACTIVE) 130 return; /* inside net loop */ 131 output_packet = buf; 132 output_packet_len = len; 133 NetLoop(NETCONS); /* wait for arp reply and send packet */ 134 output_packet_len = 0; 135 return; 136 } 137 138 if (eth->state != ETH_STATE_ACTIVE) { 139 if (eth_init(gd->bd) < 0) 140 return; 141 inited = 1; 142 } 143 pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE; 144 memcpy(pkt, buf, len); 145 ether = nc_ether; 146 ip = nc_ip; 147 NetSendUDPPacket(ether, ip, nc_out_port, nc_in_port, len); 148 149 if (inited) 150 eth_halt(); 151 } 152 153 static int nc_start(void) 154 { 155 int netmask, our_ip; 156 char *p; 157 158 nc_out_port = 6666; /* default port */ 159 nc_in_port = nc_out_port; 160 161 if (getenv("ncip")) { 162 163 nc_ip = getenv_IPaddr("ncip"); 164 if (!nc_ip) 165 return -1; /* ncip is 0.0.0.0 */ 166 p = strchr(getenv("ncip"), ':'); 167 if (p != NULL) { 168 nc_out_port = simple_strtoul(p + 1, NULL, 10); 169 nc_in_port = nc_out_port; 170 } 171 } else 172 nc_ip = ~0; /* ncip is not set, so broadcast */ 173 174 p = getenv("ncoutport"); 175 if (p != NULL) 176 nc_out_port = simple_strtoul(p, NULL, 10); 177 p = getenv("ncinport"); 178 if (p != NULL) 179 nc_in_port = simple_strtoul(p, NULL, 10); 180 181 our_ip = getenv_IPaddr("ipaddr"); 182 netmask = getenv_IPaddr("netmask"); 183 184 if (nc_ip == ~0 || /* 255.255.255.255 */ 185 ((netmask & our_ip) == (netmask & nc_ip) && /* on the same net */ 186 (netmask | nc_ip) == ~0)) /* broadcast to our net */ 187 memset(nc_ether, 0xff, sizeof(nc_ether)); 188 else 189 memset(nc_ether, 0, sizeof(nc_ether)); /* force arp request */ 190 191 /* 192 * Initialize the static IP settings and buffer pointers 193 * incase we call NetSendUDPPacket before NetLoop 194 */ 195 net_init(); 196 197 return 0; 198 } 199 200 static void nc_putc(char c) 201 { 202 if (output_recursion) 203 return; 204 output_recursion = 1; 205 206 nc_send_packet(&c, 1); 207 208 output_recursion = 0; 209 } 210 211 static void nc_puts(const char *s) 212 { 213 int len; 214 215 if (output_recursion) 216 return; 217 output_recursion = 1; 218 219 len = strlen(s); 220 while (len) { 221 int send_len = min(len, sizeof(input_buffer)); 222 nc_send_packet(s, send_len); 223 len -= send_len; 224 s += send_len; 225 } 226 227 output_recursion = 0; 228 } 229 230 static int nc_getc(void) 231 { 232 uchar c; 233 234 input_recursion = 1; 235 236 net_timeout = 0; /* no timeout */ 237 while (!input_size) 238 NetLoop(NETCONS); 239 240 input_recursion = 0; 241 242 c = input_buffer[input_offset++]; 243 244 if (input_offset >= sizeof(input_buffer)) 245 input_offset -= sizeof(input_buffer); 246 input_size--; 247 248 return c; 249 } 250 251 static int nc_tstc(void) 252 { 253 struct eth_device *eth; 254 255 if (input_recursion) 256 return 0; 257 258 if (input_size) 259 return 1; 260 261 eth = eth_get_dev(); 262 if (eth && eth->state == ETH_STATE_ACTIVE) 263 return 0; /* inside net loop */ 264 265 input_recursion = 1; 266 267 net_timeout = 1; 268 NetLoop(NETCONS); /* kind of poll */ 269 270 input_recursion = 0; 271 272 return input_size != 0; 273 } 274 275 int drv_nc_init(void) 276 { 277 struct stdio_dev dev; 278 int rc; 279 280 memset(&dev, 0, sizeof(dev)); 281 282 strcpy(dev.name, "nc"); 283 dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; 284 dev.start = nc_start; 285 dev.putc = nc_putc; 286 dev.puts = nc_puts; 287 dev.getc = nc_getc; 288 dev.tstc = nc_tstc; 289 290 rc = stdio_register(&dev); 291 292 return (rc == 0) ? 1 : rc; 293 } 294