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