]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/ibl.git/blob - src/driver/eth/udp.c
Update copyright information
[keystone-rtos/ibl.git] / src / driver / eth / udp.c
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;
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)
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;
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)
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;
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)
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;
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)
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;
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)
344     /* Initialize the socket table */
345     memset (&udp_socket, 0, sizeof(udp_socket));
346     return;