root/ar5315_microredboot/microredboot/ecos/packages/redboot/current/src/net/udp.c

Revision 12368, 7.1 kB (checked in by BrainSlayer, 5 months ago)

tftp server added, supports wiligear, ubiquiti and dd-wrt webflash format

Line 
1 //==========================================================================
2 //
3 //      net/udp.c
4 //
5 //      Stand-alone UDP networking support for RedBoot
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
12 // Copyright (C) 2002, 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 // Date:         2000-07-14
47 // Purpose:     
48 // Description: 
49 //             
50 // This code is part of RedBoot (tm).
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #include <redboot.h>
57 #include <net/net.h>
58
59 #ifdef UDP_STATS
60 static int udp_rx_total;
61 static int udp_rx_handled;
62 static int udp_rx_cksum;
63 static int udp_rx_dropped;
64 #endif
65
66 #define MAX_UDP_DATA (ETH_MAX_PKTLEN - (ETH_HDR_SIZE + \
67                                         sizeof(ip_header_t)  + \
68                                         sizeof(udp_header_t)))
69
70 /*
71  * A major assumption is that only a very small number of sockets will
72  * active, so a simple linear search of those sockets is acceptible.
73  */
74 static udp_socket_t *udp_list;
75
76 /*
77  * Install a handler for incoming udp packets.
78  * Caller provides the udp_socket_t structure.
79  * Returns zero if successful, -1 if socket is already used.
80  */
81 int __udp_install_listener(udp_socket_t * s, word port, udp_handler_t handler)
82 {
83         udp_socket_t *p;
84
85         /*
86          * Make sure we only have one handler per port.
87          */
88         for (p = udp_list; p; p = p->next)
89                 if (p->our_port == port)
90                         return -1;
91
92         s->our_port = htons(port);
93         s->handler = handler;
94         s->next = udp_list;
95         udp_list = s;
96
97         return 0;
98 }
99
100 /*
101  * Remove the handler for the given socket.
102  */
103 void __udp_remove_listener(word port)
104 {
105         udp_socket_t *prev, *s;
106
107         for (prev = NULL, s = udp_list; s; prev = s, s = s->next)
108                 if (s->our_port == htons(port)) {
109                         if (prev)
110                                 prev->next = s->next;
111                         else
112                                 udp_list = s->next;
113                 }
114 }
115
116 /*
117  * Handle incoming UDP packets.
118  */
119 void __udp_handler(pktbuf_t * pkt, ip_route_t * r)
120 {
121         udp_header_t *udp = pkt->udp_hdr;
122         ip_header_t *ip = pkt->ip_hdr;
123         udp_socket_t *s;
124
125         if (udp->checksum == 0xffff)
126                 udp->checksum = 0;
127
128         /* copy length for pseudo sum calculation */
129         ip->length = udp->length;
130
131         if (__sum((word *) udp, ntohs(udp->length), __pseudo_sum(ip)) == 0) {
132                 for (s = udp_list; s; s = s->next) {
133                         if (s->our_port == udp->dest_port) {
134                                 (*s->handler) (s,
135                                                ((char *)udp) +
136                                                sizeof(udp_header_t),
137                                                ntohs(udp->length) -
138                                                sizeof(udp_header_t), r,
139                                                ntohs(udp->src_port));
140                                 __pktbuf_free(pkt);
141                                 return;
142                         }
143                 }
144         }
145         __pktbuf_free(pkt);
146 }
147
148 /*
149  * Send a UDP packet.
150  */
151 int
152 __udp_send(char *buf, int len, ip_route_t * dest_ip,
153            word dest_port, word src_port)
154 {
155         pktbuf_t *pkt;
156         udp_header_t *udp;
157         ip_header_t *ip;
158         unsigned short cksum;
159         int ret;
160
161         /* dumb */
162         if (len > MAX_UDP_DATA)
163                 return -1;
164
165         /* just drop it if can't get a buffer */
166         if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL)
167                 return -1;
168
169         udp = pkt->udp_hdr;
170         ip = pkt->ip_hdr;
171
172         pkt->pkt_bytes = len + sizeof(udp_header_t);
173
174         udp->src_port = htons(src_port);
175         udp->dest_port = htons(dest_port);
176         udp->length = htons(pkt->pkt_bytes);
177         udp->checksum = 0;
178
179         memcpy(((char *)udp) + sizeof(udp_header_t), buf, len);
180
181         /* fill in some pseudo-header fields */
182         memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
183         memcpy(ip->destination, dest_ip->ip_addr, sizeof(ip_addr_t));
184         ip->protocol = IP_PROTO_UDP;
185         ip->length = udp->length;
186
187         cksum = __sum((word *) udp, pkt->pkt_bytes, __pseudo_sum(ip));
188         udp->checksum = htons(cksum);
189
190         ret = __ip_send(pkt, IP_PROTO_UDP, dest_ip);
191         __pktbuf_free(pkt);
192         return ret;
193 }
194
195 int
196 __udp_sendto(char *data, int len, struct sockaddr_in *server,
197              struct sockaddr_in *local)
198 {
199         ip_route_t rt;
200
201         if (__arp_lookup((ip_addr_t *) & server->sin_addr, &rt) < 0) {
202                 diag_printf("%s: Can't find address of server\n", __FUNCTION__);
203                 return -1;
204         } else {
205                 __udp_send(data, len, &rt, ntohs(server->sin_port),
206                            ntohs(local->sin_port));
207                 return 0;
208         }
209 }
210
211 static char *recvfrom_buf;
212 static int recvfrom_len;
213 static struct sockaddr_in *recvfrom_server;
214
215 static void
216 __udp_recvfrom_handler(udp_socket_t * skt, char *buf, int len,
217                        ip_route_t * src_route, word src_port)
218 {
219         if (recvfrom_server == NULL || recvfrom_buf == NULL)
220                 return;
221
222         if (recvfrom_server->sin_port
223             && recvfrom_server->sin_port != htons(src_port))
224                 return;
225
226         // Move data to waiting buffer
227         recvfrom_len = len;
228         memcpy(recvfrom_buf, buf, len);
229         if (recvfrom_server) {
230                 recvfrom_server->sin_port = htons(src_port);
231                 memcpy(&recvfrom_server->sin_addr, &src_route->ip_addr,
232                        sizeof(src_route->ip_addr));
233                 recvfrom_buf = (char *)0;       // Tell reader we got a packet
234         } else {
235                 diag_printf("udp_recvfrom - dropped packet of %d bytes\n", len);
236         }
237 }
238
239 int
240 __udp_recvfrom(char *data, int len, struct sockaddr_in *server,
241                struct sockaddr_in *local, struct timeval *timo)
242 {
243         int res, my_port, total_ms;
244         udp_socket_t skt;
245         unsigned long start;
246
247         my_port = ntohs(local->sin_port);
248         if (__udp_install_listener(&skt, my_port, __udp_recvfrom_handler) < 0) {
249                 return -1;
250         }
251         recvfrom_buf = data;
252         recvfrom_len = len;
253         recvfrom_server = server;
254         total_ms = (timo->tv_sec * 1000) + (timo->tv_usec / 1000);
255         start = MS_TICKS();
256         res = -1;
257         do {
258                 __enet_poll();  // Handle the hardware
259                 if (!recvfrom_buf) {
260                         // Data have arrived
261                         res = recvfrom_len;
262                         break;
263                 }
264         } while ((MS_TICKS_DELAY() - start) < total_ms);
265         __udp_remove_listener(my_port);
266         return res;
267 }
Note: See TracBrowser for help on using the browser.