source: edk_user_repository/WARP/sw_services/WARP_ip_udp_v1_00_a/src/WARP_ip_udp_socket.c

Last change on this file was 4696, checked in by welsh, 9 years ago

Adding WARP IP/UDP transport.

File size: 22.3 KB
Line 
1/** @file  WARP_ip_udp_socket.c
2 *  @brief WARP IP/UDP Library (Socket)
3 *
4 *  @copyright Copyright 2015, Mango Communications. All rights reserved.
5 *          Distributed under the WARP license  (http://warpproject.org/license)
6 *
7 *  @author Chris Hunter (chunter [at] mangocomm.com)
8 *  @author Patrick Murphy (murphpo [at] mangocomm.com)
9 *  @author Erik Welsh (welsh [at] mangocomm.com)
10 */
11
12/***************************** Include Files *********************************/
13
14// Xilinx / Standard library includes
15#include <xparameters.h>
16#include <xstatus.h>
17#include <xil_io.h>
18#include <stdlib.h>
19#include <stdio.h>
20
21
22// WARP IP/UDP Library includes
23#include "WARP_ip_udp.h"
24#include "WARP_ip_udp_internal.h"
25
26
27/*************************** Constant Definitions ****************************/
28
29
30/*********************** Global Variable Definitions *************************/
31
32
33/*************************** Variable Definitions ****************************/
34
35
36/*************************** Function Prototypes *****************************/
37
38int                          socket_check_socket(int socket_index);
39warp_ip_udp_socket         * socket_get_socket(int socket_index);
40warp_ip_udp_socket         * socket_alloc_socket();
41
42/******************************** Functions **********************************/
43
44
45/*****************************************************************************/
46/**
47 * Allocate a socket from the library
48 *
49 * @param   domain       - Communications domain in which a socket is to be created
50 *                             - AF_INET    - Inter-network: UDP, TCP, etc. (only supported value)
51 * @param   type         - Type of socket to be created
52 *                             - SOCK_DGRAM - Socket datagram (connectionless) (UDP) (only supported value)
53 * @param   protocol     - Particular protocol to be used with the socket
54 *                             - 0 - Use default protocol appropriate for the requested socket type (only supported value)
55 *
56 * @return  int          - Socket Index
57 *                             - WARP_IP_UDP_FAILURE if there was an error
58 *
59 * @note    Only UDP sockets are supported:  socket_socket(AF_INET, SOCK_DGRAM, 0);
60 *
61 *****************************************************************************/
62int socket_socket(int domain, int type, int protocol) {
63
64    warp_ip_udp_socket   * socket       = NULL;
65
66    // Check this is an appropriate socket
67    if ((domain == AF_INET) && (type == SOCK_DGRAM) && (protocol == 0)) {
68   
69        // Allocate the socket from the library
70        socket = socket_alloc_socket();
71       
72        if (socket != NULL) {
73            // Record values in the socket
74            socket->sin_family = domain;
75       
76            // Return the index of the socket
77            return socket->index;
78        }
79       
80    } else {
81   
82        // !!! TBD !!! - Print error message
83    }
84   
85    return WARP_IP_UDP_FAILURE;
86}
87
88
89
90/*****************************************************************************/
91/**
92 * Bind the socket to an Ethernet device
93 *
94 * @param   socket_index - Index of the socket
95 * @param   type         - The type of socket to be created
96 * @param   protocol     - The particular protocol to be used with the socket
97 *
98 * @return  int          - Status
99 *                             - WARP_IP_UDP_SUCCESS if socket is bound
100 *                             - WARP_IP_UDP_FAILURE if there was an error
101 *
102 *****************************************************************************/
103int socket_bind_eth(int socket_index, u32 eth_dev_num, u16 port) {
104
105    warp_ip_udp_socket   * socket;
106
107    // Get the socket from the socket index
108    socket = socket_get_socket(socket_index);
109   
110    if (socket != NULL) {
111        // Populate the socket
112        socket->state       = SOCKET_OPEN;
113        socket->eth_dev_num = eth_dev_num;
114        socket->sin_port    = port;
115
116        // Populate all the header fields with static information
117        eth_init_header(&(socket->hdr->eth_hdr), eth_device[eth_dev_num].hw_addr);
118        ipv4_init_header(&(socket->hdr->ip_hdr), eth_device[eth_dev_num].ip_addr);
119        udp_init_header(&(socket->hdr->udp_hdr), port);
120
121        socket->sin_addr    = socket->hdr->ip_hdr.src_ip_addr;   // NOTE:  This is the big endian version of the IP address
122    } else {
123   
124        // !!! TBD !!! - Print error message
125       
126        return WARP_IP_UDP_FAILURE;
127    }
128   
129    return WARP_IP_UDP_SUCCESS;
130}
131
132
133
134/*****************************************************************************/
135/**
136 * Close a socket
137 *
138 * @param   socket_index - Index of socket to send the message on
139 * @param   to           - Pointer to socket address structure to send the data
140 * @param   buffers      - Array of warp_ip_udp_buffer describing data to send
141 * @param   num_buffers  - Number of warp_ip_udp_buffer in array
142 *
143 * @return  int          - Socket Index
144 *                             WARP_IP_UDP_FAILURE if there was an error
145 *
146 *****************************************************************************/
147void socket_close(int socket_index) {
148
149    warp_ip_udp_socket   * socket = NULL;
150
151    // Get the socket from the socket index
152    socket = socket_get_socket(socket_index);
153   
154    if (socket != NULL) {
155        // Mark the socket as CLOSED
156        socket->state       = SOCKET_CLOSED;
157        socket->eth_dev_num = WARP_IP_UDP_INVALID_ETH_DEVICE;
158       
159    } else {
160   
161        // !!! TBD !!! - Print error message
162       
163    }
164}
165
166
167
168/*****************************************************************************/
169/**
170 * Send the given data to the given socket
171 *
172 * @param   socket_index - Index of socket to send the message on
173 * @param   to           - Pointer to socket address structure to send the data
174 * @param   buffers      - Array of warp_ip_udp_buffer describing data to send
175 * @param   num_buffers  - Number of warp_ip_udp_buffer in array
176 *
177 * @return  int          - Number of bytes sent
178 *                             WARP_IP_UDP_FAILURE if there was an error
179 *
180 *****************************************************************************/
181int socket_sendto(int socket_index, struct sockaddr * to, warp_ip_udp_buffer ** buffers, u32 num_buffers) {
182
183    u32                      i;
184    int                      status;
185    warp_ip_udp_socket     * socket;
186   
187    u32                      eth_dev_num;
188    u8                       dest_hw_addr[ETH_MAC_ADDR_LEN];
189    u32                      dest_ip_addr = ((struct sockaddr_in*)to)->sin_addr.s_addr;    // NOTE:  Value big endian
190    u16                      dest_port    = ((struct sockaddr_in*)to)->sin_port;
191
192    // Length variables for the various headers
193    u16                      ip_length    = WARP_IP_UDP_DELIM_LEN + UDP_HEADER_LEN + IP_HEADER_LEN_BYTES;
194    u16                      udp_length   = WARP_IP_UDP_DELIM_LEN + UDP_HEADER_LEN;
195    u16                      data_length  = 0;
196   
197    // Get the socket
198    socket = socket_get_socket(socket_index);
199   
200    if (socket == NULL) {
201   
202        // !!! TBD !!! - Print error message
203
204        return WARP_IP_UDP_FAILURE;
205    }
206
207    // Get the Ethernet device from the socket
208    eth_dev_num = socket->eth_dev_num;
209   
210    // Look up destination HW address in ARP table
211    status = arp_get_hw_addr(eth_dev_num, dest_hw_addr, (u8 *)(&dest_ip_addr));
212   
213    if (status != XST_SUCCESS) {
214   
215        // !!! TBD !!! - Print error message
216
217        return WARP_IP_UDP_FAILURE;
218    }
219   
220    // Compute total length of packet data
221    for (i = 0; i < num_buffers; i++) {
222        data_length += buffers[i]->size;
223    }
224   
225    // Add the data_length to the other header lengths
226    ip_length  += data_length;
227    udp_length += data_length;
228   
229    // Update the UDP header
230    //     NOTE:  Requires dest_port to be big-endian; udp_length to be little-endian
231    //
232    udp_update_header(&(socket->hdr->udp_hdr), dest_port, udp_length);
233
234    // Update the IPv4 header
235    //     NOTE:  Requires dest_ip_addr to be big-endian; ip_length to be little-endian
236    //
237    ipv4_update_header(&(socket->hdr->ip_hdr), dest_ip_addr, ip_length, IP_PROTOCOL_UDP);
238
239    // Update the Ethernet header
240    //     NOTE:  dest_hw_addr must be big-endian; ethertype must be little-endian
241    //
242    eth_update_header(&(socket->hdr->eth_hdr), dest_hw_addr, ETHERTYPE_IP_V4);
243
244    // Send the Ethernet frame using the socket header
245    return eth_send_frame(eth_dev_num, socket, buffers, num_buffers, 0x1);
246}
247
248
249
250int socket_sendto_raw(int socket_index, warp_ip_udp_buffer ** buffers, u32 num_buffers) {
251
252    warp_ip_udp_socket     * socket;
253    u32                      eth_dev_num;
254
255    // Get the socket
256    socket = socket_get_socket(socket_index);
257
258    if (socket == NULL) {
259
260        // !!! TBD !!! - Print error message
261
262        return WARP_IP_UDP_FAILURE;
263    }
264
265    // Get the Ethernet device from the socket
266    eth_dev_num = socket->eth_dev_num;
267
268    // Send the Ethernet frame using the socket header
269    return eth_send_frame(eth_dev_num, socket, buffers, num_buffers, 0x0);
270}
271
272
273
274/*****************************************************************************/
275/**
276 * Try to receive on the socket
277 *
278 * @param   eth_dev_num      - Ethernet device number
279 * @param   socket_index     - Pointer to Socket index where the data is from
280 * @param   from             - Pointer to socket address structure where the data is from
281 * @param   buffer           - WARP IP/UDP Buffer describing data (will be filled in)
282 *
283 * @return  int              - Number of bytes of data in the processed packet
284 *                                 0 if there was no data in the packet
285 *                                -1 if there was a library failure
286 *
287 * @note    socket_recv will return a warp_ip_udp_buffer such that:
288 *              state      = WARP_BUFFER_IN_USE                                               (do not change)
289 *              max_size   = Send buffer size                                                 (do not change)
290 *              size       = Full size of the packet                                          (do not change)
291 *              data       = Pointer to start of the packet                                   (do not change)
292 *              offset     = Pointer to start of UDP packet data
293 *              length     = Length of UDP packet data
294 *              descriptor = Pointer to buffer descriptor associated with the data buffer     (do not change)
295 *
296 * @note    The library internally allocates receive buffers, but it is the requirement
297 *          of user code to free the buffer to indicate to the library it can re-use
298 *          the memory.  This allows the library to pre-allocate all of the buffer
299 *          descriptors used by the Ethernet DMA.
300 *
301 *****************************************************************************/
302int socket_recvfrom_eth(u32 eth_dev_num, int * socket_index, struct sockaddr * from, warp_ip_udp_buffer * buffer) {
303
304    warp_ip_udp_header     * header;
305    int                      recv_bytes;
306    struct sockaddr_in     * socket_addr;
307   
308    // Try to receive an Ethernet frame
309    recv_bytes = eth_recv_frame(eth_dev_num, buffer);
310
311    // Fill in the socket information
312    if (recv_bytes > 0) {
313        // If there were received bytes, buffer->data is a pointer to the beginning of the packet
314        header = (warp_ip_udp_header *) buffer->data;
315       
316        // Get the socket index for the socket this packet was intended
317        *socket_index                = socket_find_index_by_eth(eth_dev_num, Xil_Ntohs((header->udp_hdr).dest_port));
318   
319        // Since this is a valid packet, use the header to fill in the socket information
320        socket_addr                  = (struct sockaddr_in *) from;
321        socket_addr->sin_family      = AF_INET;
322        socket_addr->sin_port        = header->udp_hdr.src_port;
323        socket_addr->sin_addr.s_addr = header->ip_hdr.src_ip_addr;
324    }
325   
326    return recv_bytes;
327}
328
329
330
331/*****************************************************************************/
332/**
333 * Allocate a send buffer from the library
334 *
335 * @param   None
336 *
337 * @return  warp_ip_udp_buffer *  - Pointer to WARP IP/UDP Buffer allocated
338 *                                  NULL if buffer was not allocated
339 *
340 * @note    alloc_send_buffer will return a warp_ip_udp_buffer such that:
341 *              state      = WARP_BUFFER_IN_USE              (do not change)
342 *              max_size   = Send buffer size                (do not change)
343 *              size       = 0
344 *              data       = Pointer to start of the packet  (do not change)
345 *              offset     = data
346 *              length     = 0
347 *              descriptor = NULL                            (do not change)
348 *
349 * @note    The size of the send buffer must be set to the total number of bytes
350 *          in the buffer for it to be processed correctly.  The offset and length
351 *          can be changed by the user but will not be used by the send framework.
352 *
353 * @note    Currently, the max_size of the buffers is fixed at WARP_IP_UDP_ETH_*_BUF_SIZE
354 *          bytes.  This could be modified in the future to have a pool of bytes and
355 *          have this code allocate bytes out of that pool similar to malloc for more
356 *          efficient memory usage.
357 *
358 *****************************************************************************/
359warp_ip_udp_buffer * socket_alloc_send_buffer() {
360
361    u32                      i;
362    warp_ip_udp_buffer     * buffer         = NULL;
363   
364    // If we have allocated less than the number of buffers, then allocate one
365    if (ETH_allocated_send_buffers < WARP_IP_UDP_ETH_NUM_SEND_BUF) {
366       
367        // Find the first buffer that is free
368        for (i = 0; i < WARP_IP_UDP_ETH_NUM_SEND_BUF; i++) {
369            if (ETH_send_buffers[i].state == WARP_IP_UDP_BUFFER_FREE) { break; }
370        }
371       
372        buffer = &(ETH_send_buffers[i]);
373       
374        // Initialize the buffer (see documentation above):
375        buffer->state      = WARP_IP_UDP_BUFFER_IN_USE;
376        buffer->size       = 0;
377        buffer->offset     = buffer->data;
378        buffer->length     = 0;
379        buffer->descriptor = NULL;
380       
381        // Increment number of allocated buffers
382        ETH_allocated_send_buffers += 1;
383       
384    } else {
385   
386        // All buffers are in use, return NULL
387       
388        xil_printf("ERROR - All Buffers in Use!\n");
389        // !!! TBD !!! - Print error message
390       
391    }
392   
393    return buffer;
394}
395
396
397
398/*****************************************************************************/
399/**
400 * Free a send buffer for reuse
401 *
402 * @param   buffer           - Pointer to WARP IP/UDP buffer to be freed
403 *
404 * @return  None
405 *
406 *****************************************************************************/
407void socket_free_send_buffer(warp_ip_udp_buffer * buffer) {
408
409    // Check that we are not un-allocating a buffer in error
410    if (ETH_allocated_send_buffers > 0) {
411   
412        // Free the buffer (will be re-initialized on the next allocation)
413        buffer->state      = WARP_IP_UDP_BUFFER_FREE;
414       
415        // Decrement number of allocated buffers
416        ETH_allocated_send_buffers -= 1;
417       
418    } else {
419   
420        // !!! TBD !!! - Print error message
421    }
422}
423
424
425
426/*****************************************************************************/
427/**
428 * Free a receive buffer for reuse
429 *
430 * @param   socket_index     - Socket index
431 * @param   buffer           - Pointer to WARP IP/UDP buffer to be freed
432 *
433 * @return  None
434 *
435 * @note    The library internally allocates receive buffers, but it is the requirement
436 *          of user code to free the buffer to indicate to the library it can re-use
437 *          the memory.  This allows the library to pre-allocate all of the buffer
438 *          descriptors used by the Ethernet DMA.
439 *
440 *****************************************************************************/
441void socket_free_recv_buffer(int socket_index, warp_ip_udp_buffer * buffer) {
442
443    u32                      eth_dev_num;
444    warp_ip_udp_socket     * socket         = NULL;
445
446    // Get the socket from the socket index
447    socket = socket_get_socket(socket_index);
448   
449    if (socket != NULL) {
450        eth_dev_num = socket->eth_dev_num;
451       
452        // Free the receive buffer descriptor to be re-used
453        if (eth_free_recv_buffers(eth_dev_num, buffer->descriptor, 1) != XST_SUCCESS) {
454       
455            // !!! TBD !!! - Print error message
456        }
457       
458    } else {
459   
460        // !!! TBD !!! - Print error message
461    }
462}
463
464
465
466/*****************************************************************************/
467/**
468 * Find the socket_index by Ethernet device & Port
469 *
470 * @param   eth_dev_num      - Ethernet device number
471 * @param   port             - Port of the socket
472 *
473 * @return  int              - Socket Index
474 *                                 WARP_IP_UDP_FAILURE if there was an error
475 *
476 *****************************************************************************/
477int socket_find_index_by_eth(u32 eth_dev_num, u16 port) {
478
479    u32 i;
480    int socket_index   = SOCKET_INVALID_SOCKET;
481
482    // Search through socket pool
483    for (i = 0; i < WARP_IP_UDP_NUM_SOCKETS; i++) {
484
485        // Check socket parameters   
486        if ((ETH_sockets[i].state       == SOCKET_OPEN) &&
487            (ETH_sockets[i].eth_dev_num == eth_dev_num) &&
488            (ETH_sockets[i].sin_port    == port       ) ) {
489           
490            socket_index = i;
491            break;
492        }
493    }
494   
495    return socket_index;
496}
497
498
499
500/*****************************************************************************/
501/**
502 * Find the Ethernet device from the socket_index
503 *
504 * @param   socket_index     - Index of the socket
505 *
506 * @return  u32              - Ethernet device number
507 *                                 WARP_IP_UDP_INVALID_ETH_DEVICE if there was an error
508 *
509 *****************************************************************************/
510u32 socket_get_eth_dev_num(int socket_index) {
511
512    warp_ip_udp_socket     * socket         = NULL;
513
514    socket = socket_get_socket(socket_index);
515
516    if (socket == NULL) {
517        return WARP_IP_UDP_INVALID_ETH_DEVICE;
518    } else {
519        return (socket->eth_dev_num);
520    }
521}
522
523
524
525/*****************************************************************************/
526/**
527 * Get a pointer to the warp_ip_udp_header of socket from the socket_index
528 *
529 * @param   socket_index          - Index of the socket
530 *
531 * @return  warp_ip_udp_header *  - Ethernet device number
532 *                                      NULL if there was an error
533 *
534 *****************************************************************************/
535warp_ip_udp_header * socket_get_warp_ip_udp_header(int socket_index) {
536
537    warp_ip_udp_socket     * socket         = NULL;
538
539    socket = socket_get_socket(socket_index);
540
541    if (socket == NULL) {
542        return NULL;
543    } else {
544        return (socket->hdr);
545    }
546}
547
548
549
550
551/**********************************************************************************************************************/
552/**
553 * @brief Internal Methods
554 *
555 **********************************************************************************************************************/
556
557/******************************************************************************/
558/**
559 * Allocate a socket from the global pool
560 *
561 * @param   None
562 *
563 * @return  warp_ip_udp_socket *       - Pointer to the socket
564 *                                           NULL if not able to get the socket
565 *
566 *****************************************************************************/
567warp_ip_udp_socket * socket_alloc_socket() {
568
569    u32                      i;
570    int                      socket_index   = SOCKET_INVALID_SOCKET;
571    warp_ip_udp_socket     * socket         = NULL;
572
573    // Search through socket pool for a closed socket
574    for (i = 0; i < WARP_IP_UDP_NUM_SOCKETS; i++) {
575        if (ETH_sockets[i].state == SOCKET_CLOSED) { 
576            socket_index = i;
577            break;
578        }
579    }
580
581    if (socket_index != SOCKET_INVALID_SOCKET) {
582        // Get the socket from the global structure
583        socket = &(ETH_sockets[socket_index]);
584       
585        // Set the socket state to "ALLOCATED"
586        socket->state = SOCKET_ALLOCATED;
587       
588    } else {
589   
590        // !!! TBD !!! - Print error message
591    }
592   
593    return socket;
594} 
595
596
597 
598/******************************************************************************/
599/**
600 * Get a pointer to the socket from the socket index
601 *
602 * @param   socket_index               - Index of the socket
603 *
604 * @return  warp_ip_udp_socket *       - Pointer to the socket
605 *                                           NULL if not able to get the socket
606 *
607 *****************************************************************************/
608warp_ip_udp_socket * socket_get_socket(int socket_index) {
609
610    warp_ip_udp_socket     * socket = NULL;
611
612    // Check the socket index
613    if (socket_check_socket(socket_index) == XST_SUCCESS) {
614   
615        // Get the socket from the global structure
616        socket = &(ETH_sockets[socket_index]);
617       
618        // Check the socket status; if it is closed, then return NULL
619        if (socket->state == SOCKET_CLOSED) {
620       
621            // !!! TBD !!! - Print error message
622           
623            socket = NULL;
624        }
625    }
626   
627    return socket;
628}
629
630
631
632/*****************************************************************************/
633/**
634 * Check the socket index
635 *
636 * @param   socket_index     - Index of the socket
637 *
638 * @return  int              - Status of the command:
639 *                                 XST_SUCCESS - Command completed successfully
640 *                                 XST_FAILURE - There was an error in the command
641 *
642 *****************************************************************************/
643int socket_check_socket(int socket_index) {
644
645    // Check that the socket_index is valid
646    if ((socket_index < 0) || (socket_index > WARP_IP_UDP_NUM_SOCKETS)) {
647   
648        // !!! TBD !!! - Print error message
649       
650        return XST_FAILURE;
651    }
652
653    return XST_SUCCESS;
654}
655
656
657
Note: See TracBrowser for help on using the repository browser.