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