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