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