1 /**
2 * @file udp.c
3 *
4 * @brief
5 * The file implements the NET Module UDP functionality.
6 *
7 * \par
8 * NOTE:
9 * (C) Copyright 2008, Texas Instruments, Inc.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the
21 * distribution.
22 *
23 * Neither the name of Texas Instruments Incorporated nor the names of
24 * its contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *
39 * \par
40 */
41 #include "types.h"
42 #include "iblloc.h"
43 #include "net.h"
44 #include "netif.h"
45 #include "iblcfg.h"
46 #include <string.h>
49 /**********************************************************************
50 *************************** GLOBAL Variables *************************
51 **********************************************************************/
53 /**
54 * @brief This is the global master control block for the UDP
55 * Socket Module and contains information about all the UDP sockets
56 * which are open.
57 */
58 SOCKET udp_socket[MAX_UDP_SOCKET];
60 /**********************************************************************
61 **************************** UDP Functions ***************************
62 **********************************************************************/
64 /**
65 * @b Description
66 * @n
67 * The function computes the UDP checksum and populates the UDP
68 * Checksum field.
69 *
70 * @param[in] ptr_udphdr
71 * This is the pointer to the UDP header.
72 * @param[in] ptr_pseudo
73 * This is the UDP Pseudo header used for checksum calculations.
74 *
75 * @retval
76 * Not Applicable.
77 */
78 static void udp_checksum (UDPHDR *ptr_udphdr, PSEUDOHDR* ptr_pseudo)
79 {
80 Int32 tmp1;
81 Uint16* pw;
82 Uint32 TSum;
84 /* Get header size in bytes */
85 tmp1 = ntohs(ptr_pseudo->Length);
87 /* Checksum field is NULL in checksum calculations */
88 ptr_udphdr->UDPChecksum = 0;
90 /* Checksum the header */
91 pw = (Uint16 *)ptr_udphdr;
92 TSum = 0;
93 for( ; tmp1 > 1; tmp1 -= 2 )
94 TSum += (Uint32)*pw++;
95 #ifdef BIGENDIAN
96 if( tmp1 )
97 TSum += (Uint32)(*pw & 0xFF00);
98 #else
99 if( tmp1 )
100 TSum += (Uint32)(*pw & 0x00FF);
101 #endif
103 /* Checksum the pseudo header */
104 pw = (Uint16 *)ptr_pseudo;
105 for( tmp1=0; tmp1 < 6; tmp1++ )
106 TSum += (Uint32)*pw++;
108 TSum = (TSum&0xFFFF) + (TSum>>16);
109 TSum = (TSum&0xFFFF) + (TSum>>16);
111 /* Special case the 0xFFFF checksum - don't use a checksum
112 * value of 0x0000 */
113 if( TSum != 0xFFFF )
114 TSum = ~TSum;
116 /* Note checksum is Net/Host byte order independent */
117 ptr_udphdr->UDPChecksum = (Uint16)TSum;
118 return;
119 }
121 /**
122 * @b Description
123 * @n
124 * The function handles the processing of UDP packets.
125 *
126 * @param[in] ptr_iphdr
127 * This is the pointer to the IP header.
128 *
129 * @retval
130 * Success - 0
131 * @retval
132 * Error - <0
133 */
134 Int32 udp_receive (IPHDR* ptr_iphdr)
135 {
136 UDPHDR* ptr_udphdr;
137 Uint16 l4_pkt_size;
138 PSEUDOHDR pseudo;
139 Uint16 checksum;
140 Int32 index;
142 /* Get the pointer to the ICMP header. */
143 ptr_udphdr = (UDPHDR *) ((Uint8 *)ptr_iphdr + IPHDR_SIZE);
145 /* Compute the l4 packet size. */
146 l4_pkt_size = ntohs(ptr_iphdr->TotalLen) - IPHDR_SIZE;
148 /* Make sure we have minimum size to proceed. */
149 if (l4_pkt_size < UDPHDR_SIZE)
150 return -1;
152 /* Validate the UDP Checksum if one has been provided. */
153 if (ptr_udphdr->UDPChecksum)
154 {
155 /* Create the Pseudo header. */
156 pseudo.IPSrc = ptr_iphdr->IPSrc;
157 pseudo.IPDst = ptr_iphdr->IPDst;
158 pseudo.Null = 0;
159 pseudo.Protocol = 17;
160 pseudo.Length = ptr_udphdr->Length;
162 /* Compute the checksum and compare with the one received. */
163 checksum = ptr_udphdr->UDPChecksum;
164 udp_checksum (ptr_udphdr, &pseudo);
165 if (checksum != ptr_udphdr->UDPChecksum)
166 return -1;
167 }
169 /* Cycle through the UDP sockets and pass it to the application. */
170 for (index = 0; index < MAX_UDP_SOCKET; index++)
171 {
172 /* Check if there is a match of the destination port of the received
173 * packet with a local port on the socket. */
174 if (udp_socket[index].local_port == ntohs(ptr_udphdr->DstPort))
175 {
176 /* Found the socket! Pass the packet to the application receive handler. */
177 udp_socket[index].app_fn (index, (Uint8 *)((Uint8*)ptr_udphdr + sizeof(UDPHDR)),
178 (ntohs(ptr_udphdr->Length) - sizeof(UDPHDR)));
180 /* Packet has been successfully passed to the application. */
181 return 0;
182 }
183 }
185 /* Control comes here implies that there was no application waiting for the UDP data. */
186 return -1;
187 }
189 /**
190 * @b Description
191 * @n
192 * The function is available to the application layer to register themselves
193 * with the UDP layer.
194 *
195 * @param[in] ptr_socket
196 * This is the pointer to the socket structure which is populated by the
197 * application layer and registered with the UDP module.
198 *
199 * @retval
200 * Success - Socket handle
201 * @retval
202 * Error - <0
203 */
204 Int32 udp_sock_open (SOCKET* ptr_socket)
205 {
206 Int32 index = 0;
208 /* Basic Validations: The structure should be populated completely. */
209 if ((ptr_socket->remote_address == 0) || (ptr_socket->remote_port == 0) ||
210 (ptr_socket->local_port == 0) || (ptr_socket->app_fn == NULL))
211 return -1;
213 /* Cycle through all the UDP socket and create an entry. */
214 for (index= 0; index < MAX_UDP_SOCKET; index++)
215 {
216 /* Check if the socket is free or occupied?
217 * This can simply be done by verifying that the local port is not 0 */
218 if (udp_socket[index].local_port == 0)
219 {
220 /* Got a free slot. Copy the socket data over and return the index as the handle. */
221 memcpy ((void *)&udp_socket[index], (void *)ptr_socket, sizeof(SOCKET));
222 return index;
223 }
224 }
225 /* Control comes here indicates that there were no free sockets available. */
226 return -1;
227 }
229 /**
230 * @b Description
231 * @n
232 * The function is called from the application layer to send out a packet
233 * to the UDP layer.
234 *
235 * @param[in] sock
236 * This is the socket handle which was returned in the call to udp_sock_open.
237 * @param[in] ptr_app_data
238 * This is the pointer to the application data payload.
239 * @param[in] num_bytes
240 * This is the length of the application data payload
241 *
242 * @retval
243 * Success - Number of bytes transmitted
244 * @retval
245 * Error - < 0
246 */
247 Int32 udp_sock_send (Int32 sock, Uint8* ptr_app_data, Int32 num_bytes)
248 {
249 SOCKET* ptr_socket;
250 IPHDR* ptr_iphdr;
251 UDPHDR* ptr_udphdr;
252 Uint8* ptr_data;
253 PSEUDOHDR pseudo;
255 /* Get the pointer to the socket handle. */
256 ptr_socket = &udp_socket[sock];
258 /* Sanity Check: Make sure that the UDP socket is valid */
259 if (ptr_socket->local_port == 0)
260 return -1;
262 /* Allocate memory for the packet. */
263 ptr_iphdr = (IPHDR *)net_alloc_tx_packet (num_bytes + IPHDR_SIZE + UDPHDR_SIZE);
264 if (ptr_iphdr == NULL)
265 return -1;
267 /* Get the pointer to the UDP header. */
268 ptr_udphdr = (UDPHDR *)((Uint8 *)ptr_iphdr + IPHDR_SIZE);
270 /* Get the pointer to the data payload in the newly allocated packet. */
271 ptr_data = (Uint8 *)ptr_udphdr + UDPHDR_SIZE;
273 /*******************************************************************************
274 ********************************* APP Data ************************************
275 *******************************************************************************/
276 memcpy ((void *)ptr_data, (void *)ptr_app_data, num_bytes);
278 /*******************************************************************************
279 ********************************* UDP Header **********************************
280 *******************************************************************************/
281 ptr_udphdr->SrcPort = htons(ptr_socket->local_port);
282 ptr_udphdr->DstPort = htons(ptr_socket->remote_port);
283 ptr_udphdr->Length = htons(UDPHDR_SIZE + num_bytes);
285 /* Create the Pseudo header. */
286 pseudo.IPSrc = netmcb.net_device.ip_address;
287 pseudo.IPDst = ptr_socket->remote_address;
288 pseudo.Null = 0;
289 pseudo.Protocol = 17;
290 pseudo.Length = ptr_udphdr->Length;
291 udp_checksum (ptr_udphdr, &pseudo);
293 /*******************************************************************************
294 ********************************* IPv4 Header *********************************
295 *******************************************************************************/
296 ptr_iphdr->IPDst = ptr_socket->remote_address;
297 ptr_iphdr->Protocol = IPPROTO_UDP;
299 /* Send the IP packet. */
300 ip_send (ptr_iphdr, UDPHDR_SIZE + IPHDR_SIZE + num_bytes);
302 /* Packet has been sent out. */
303 return num_bytes;
304 }
306 /**
307 * @b Description
308 * @n
309 * The function is available to the application layer to deregister themselves
310 * with the UDP layer.
311 *
312 * @param[in] sock
313 * This is the socket handle which is to be closed.
314 *
315 * @retval
316 * Not Applicable.
317 */
318 void udp_sock_close (Int32 sock)
319 {
320 SOCKET* ptr_socket;
322 /* Basic Validation: Ensure the sock is in the valid range. */
323 if ((sock < 0) || (sock > MAX_UDP_SOCKET))
324 return;
326 /* Get the pointer to the socket handle. */
327 ptr_socket = &udp_socket[sock];
329 /* Reset the memory block */
330 memset ((void *)ptr_socket, 0, sizeof(SOCKET));
331 return;
332 }
334 /**
335 * @b Description
336 * @n
337 * The function initializes the UDP Module in the NET Boot module.
338 *
339 * @retval
340 * Not Applicable
341 */
342 void udp_init (void)
343 {
344 /* Initialize the socket table */
345 memset (&udp_socket, 0, sizeof(udp_socket));
346 return;
347 }