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>
47 #include "net_osal.h"
50 /**********************************************************************
51 *************************** GLOBAL Variables *************************
52 **********************************************************************/
54 /**
55 * @brief This is the global master control block for the UDP
56 * Socket Module and contains information about all the UDP sockets
57 * which are open.
58 */
59 SOCKET udp_socket[MAX_UDP_SOCKET];
61 /**********************************************************************
62 **************************** UDP Functions ***************************
63 **********************************************************************/
65 /**
66 * @b Description
67 * @n
68 * The function computes the UDP checksum and populates the UDP
69 * Checksum field.
70 *
71 * @param[in] ptr_udphdr
72 * This is the pointer to the UDP header.
73 * @param[in] ptr_pseudo
74 * This is the UDP Pseudo header used for checksum calculations.
75 *
76 * @retval
77 * Not Applicable.
78 */
79 static void udp_checksum (UDPHDR *ptr_udphdr, PSEUDOHDR* ptr_pseudo)
80 {
81 Int32 tmp1;
82 Uint16* pw;
83 Uint32 TSum;
85 /* Get header size in bytes */
86 tmp1 = ntohs(ptr_pseudo->Length);
88 /* Checksum field is NULL in checksum calculations */
89 ptr_udphdr->UDPChecksum = 0;
91 /* Checksum the header */
92 pw = (Uint16 *)ptr_udphdr;
93 TSum = 0;
94 for( ; tmp1 > 1; tmp1 -= 2 )
95 TSum += (Uint32)*pw++;
96 #ifdef BIGENDIAN
97 if( tmp1 )
98 TSum += (Uint32)(*pw & 0xFF00);
99 #else
100 if( tmp1 )
101 TSum += (Uint32)(*pw & 0x00FF);
102 #endif
104 /* Checksum the pseudo header */
105 pw = (Uint16 *)ptr_pseudo;
106 for( tmp1=0; tmp1 < 6; tmp1++ )
107 TSum += (Uint32)*pw++;
109 TSum = (TSum&0xFFFF) + (TSum>>16);
110 TSum = (TSum&0xFFFF) + (TSum>>16);
112 /* Special case the 0xFFFF checksum - don't use a checksum
113 * value of 0x0000 */
114 if( TSum != 0xFFFF )
115 TSum = ~TSum;
117 /* Note checksum is Net/Host byte order independent */
118 ptr_udphdr->UDPChecksum = (Uint16)TSum;
119 return;
120 }
122 /**
123 * @b Description
124 * @n
125 * The function handles the processing of UDP packets.
126 *
127 * @param[in] ptr_iphdr
128 * This is the pointer to the IP header.
129 *
130 * @retval
131 * Success - 0
132 * @retval
133 * Error - <0
134 */
135 Int32 udp_receive (IPHDR* ptr_iphdr)
136 {
137 UDPHDR* ptr_udphdr;
138 Uint16 l4_pkt_size;
139 PSEUDOHDR pseudo;
140 Uint16 checksum;
141 Int32 index;
143 /* Get the pointer to the ICMP header. */
144 ptr_udphdr = (UDPHDR *) ((Uint8 *)ptr_iphdr + IPHDR_SIZE);
146 /* Compute the l4 packet size. */
147 l4_pkt_size = ntohs(ptr_iphdr->TotalLen) - IPHDR_SIZE;
149 /* Make sure we have minimum size to proceed. */
150 if (l4_pkt_size < UDPHDR_SIZE)
151 return -1;
153 /* Validate the UDP Checksum if one has been provided. */
154 if (ptr_udphdr->UDPChecksum)
155 {
156 /* Create the Pseudo header. */
157 pseudo.IPSrc = ptr_iphdr->IPSrc;
158 pseudo.IPDst = ptr_iphdr->IPDst;
159 pseudo.Null = 0;
160 pseudo.Protocol = 17;
161 pseudo.Length = ptr_udphdr->Length;
163 /* Compute the checksum and compare with the one received. */
164 checksum = ptr_udphdr->UDPChecksum;
165 udp_checksum (ptr_udphdr, &pseudo);
166 if (checksum != ptr_udphdr->UDPChecksum)
167 return -1;
168 }
170 /* Cycle through the UDP sockets and pass it to the application. */
171 for (index = 0; index < MAX_UDP_SOCKET; index++)
172 {
173 /* Check if there is a match of the destination port of the received
174 * packet with a local port on the socket. */
175 if (udp_socket[index].local_port == ntohs(ptr_udphdr->DstPort))
176 {
177 /* Found the socket! Pass the packet to the application receive handler. */
178 udp_socket[index].app_fn (index, (Uint8 *)((Uint8*)ptr_udphdr + sizeof(UDPHDR)),
179 (ntohs(ptr_udphdr->Length) - sizeof(UDPHDR)));
181 /* Packet has been successfully passed to the application. */
182 return 0;
183 }
184 }
186 /* Control comes here implies that there was no application waiting for the UDP data. */
187 return -1;
188 }
190 /**
191 * @b Description
192 * @n
193 * The function is available to the application layer to register themselves
194 * with the UDP layer.
195 *
196 * @param[in] ptr_socket
197 * This is the pointer to the socket structure which is populated by the
198 * application layer and registered with the UDP module.
199 *
200 * @retval
201 * Success - Socket handle
202 * @retval
203 * Error - <0
204 */
205 Int32 udp_sock_open (SOCKET* ptr_socket)
206 {
207 Int32 index = 0;
209 /* Basic Validations: The structure should be populated completely. */
210 if ((ptr_socket->remote_address == 0) || (ptr_socket->remote_port == 0) ||
211 (ptr_socket->local_port == 0) || (ptr_socket->app_fn == NULL))
212 return -1;
214 /* Cycle through all the UDP socket and create an entry. */
215 for (index= 0; index < MAX_UDP_SOCKET; index++)
216 {
217 /* Check if the socket is free or occupied?
218 * This can simply be done by verifying that the local port is not 0 */
219 if (udp_socket[index].local_port == 0)
220 {
221 /* Got a free slot. Copy the socket data over and return the index as the handle. */
222 netMemcpy ((void *)&udp_socket[index], (void *)ptr_socket, sizeof(SOCKET));
223 return index;
224 }
225 }
226 /* Control comes here indicates that there were no free sockets available. */
227 return -1;
228 }
230 /**
231 * @b Description
232 * @n
233 * The function is called from the application layer to send out a packet
234 * to the UDP layer.
235 *
236 * @param[in] sock
237 * This is the socket handle which was returned in the call to udp_sock_open.
238 * @param[in] ptr_app_data
239 * This is the pointer to the application data payload.
240 * @param[in] num_bytes
241 * This is the length of the application data payload
242 *
243 * @retval
244 * Success - Number of bytes transmitted
245 * @retval
246 * Error - < 0
247 */
248 Int32 udp_sock_send (Int32 sock, Uint8* ptr_app_data, Int32 num_bytes)
249 {
250 SOCKET* ptr_socket;
251 IPHDR* ptr_iphdr;
252 UDPHDR* ptr_udphdr;
253 Uint8* ptr_data;
254 PSEUDOHDR pseudo;
256 /* Get the pointer to the socket handle. */
257 ptr_socket = &udp_socket[sock];
259 /* Sanity Check: Make sure that the UDP socket is valid */
260 if (ptr_socket->local_port == 0)
261 return -1;
263 /* Allocate memory for the packet. */
264 ptr_iphdr = (IPHDR *)net_alloc_tx_packet (num_bytes + IPHDR_SIZE + UDPHDR_SIZE);
265 if (ptr_iphdr == NULL)
266 return -1;
268 /* Get the pointer to the UDP header. */
269 ptr_udphdr = (UDPHDR *)((Uint8 *)ptr_iphdr + IPHDR_SIZE);
271 /* Get the pointer to the data payload in the newly allocated packet. */
272 ptr_data = (Uint8 *)ptr_udphdr + UDPHDR_SIZE;
274 /*******************************************************************************
275 ********************************* APP Data ************************************
276 *******************************************************************************/
277 netMemcpy ((void *)ptr_data, (void *)ptr_app_data, num_bytes);
279 /*******************************************************************************
280 ********************************* UDP Header **********************************
281 *******************************************************************************/
282 ptr_udphdr->SrcPort = htons(ptr_socket->local_port);
283 ptr_udphdr->DstPort = htons(ptr_socket->remote_port);
284 ptr_udphdr->Length = htons(UDPHDR_SIZE + num_bytes);
286 /* Create the Pseudo header. */
287 pseudo.IPSrc = netmcb.net_device.ip_address;
288 pseudo.IPDst = ptr_socket->remote_address;
289 pseudo.Null = 0;
290 pseudo.Protocol = 17;
291 pseudo.Length = ptr_udphdr->Length;
292 udp_checksum (ptr_udphdr, &pseudo);
294 /*******************************************************************************
295 ********************************* IPv4 Header *********************************
296 *******************************************************************************/
297 ptr_iphdr->IPDst = ptr_socket->remote_address;
298 ptr_iphdr->Protocol = IPPROTO_UDP;
300 /* Send the IP packet. */
301 ip_send (ptr_iphdr, UDPHDR_SIZE + IPHDR_SIZE + num_bytes);
303 /* Packet has been sent out. */
304 return num_bytes;
305 }
307 /**
308 * @b Description
309 * @n
310 * The function is available to the application layer to deregister themselves
311 * with the UDP layer.
312 *
313 * @param[in] sock
314 * This is the socket handle which is to be closed.
315 *
316 * @retval
317 * Not Applicable.
318 */
319 void udp_sock_close (Int32 sock)
320 {
321 SOCKET* ptr_socket;
323 /* Basic Validation: Ensure the sock is in the valid range. */
324 if ((sock < 0) || (sock > MAX_UDP_SOCKET))
325 return;
327 /* Get the pointer to the socket handle. */
328 ptr_socket = &udp_socket[sock];
330 /* Reset the memory block */
331 netMemset ((void *)ptr_socket, 0, sizeof(SOCKET));
332 return;
333 }
335 /**
336 * @b Description
337 * @n
338 * The function initializes the UDP Module in the NET Boot module.
339 *
340 * @retval
341 * Not Applicable
342 */
343 void udp_init (void)
344 {
345 /* Initialize the socket table */
346 netMemset (&udp_socket, 0, sizeof(udp_socket));
347 return;
348 }