Initial c661x version
[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>
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;
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)
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;
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)
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;
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)
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;
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)
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;
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)
345     /* Initialize the socket table */
346     netMemset (&udp_socket, 0, sizeof(udp_socket));
347     return;