1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * Top-level API to network File: net_api.c
6 * This routine contains the highest-level API to the network
7 * routines. The global handle to the network state is right here.
9 * Author: Mitch Lichtenberg (mpl@broadcom.com)
11 *********************************************************************
13 * Copyright 2000,2001,2002,2003
14 * Broadcom Corporation. All rights reserved.
16 * This software is furnished under license and may be used and
17 * copied only in accordance with the following terms and
18 * conditions. Subject to these conditions, you may download,
19 * copy, install, use, modify and distribute modified or unmodified
20 * copies of this software in source and/or binary form. No title
21 * or ownership is transferred hereby.
23 * 1) Any source code used, modified or distributed must reproduce
24 * and retain this copyright notice and list of conditions
25 * as they appear in the source file.
27 * 2) No right is granted to use any trade name, trademark, or
28 * logo of Broadcom Corporation. The "Broadcom Corporation"
29 * name may not be used to endorse or promote products derived
30 * from this software without the prior written permission of
31 * Broadcom Corporation.
33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45 * THE POSSIBILITY OF SUCH DAMAGE.
46 ********************************************************************* */
49 #include "bsp_config.h"
51 #include "lib_types.h"
52 #include "lib_string.h"
53 #include "lib_queue.h"
54 #include "lib_malloc.h"
55 #include "lib_printf.h"
58 #include "cfe_devfuncs.h"
59 #include "cfe_ioctl.h"
60 #include "cfe_timer.h"
62 #include "cfe_error.h"
65 #include "net_ether.h"
67 #include "cfe_timer.h"
70 #include "net_ip_internal.h"
83 /* *********************************************************************
85 ********************************************************************* */
88 * Net context. All the soft context structures of all the
89 * layers of the network stack are bundled here. There's only one
90 * of these in the system when the network is active.
93 typedef struct net_ctx_s
{
100 /* Run-time info for IP interface */
103 /* Info for Ethernet interface */
104 ether_info_t
*ethinfo
;
106 /* Info specific to UDP */
109 /* Info specific to ICMP */
110 icmp_info_t
*icmpinfo
;
113 /* Info specific to TCP */
117 /* Info specific to HTTP */
118 http_info_t
*httpinfo
;
123 /* *********************************************************************
125 ********************************************************************* */
127 static net_ctx_t
*netctx
= NULL
;
130 /* *********************************************************************
132 ********************************************************************* */
134 /* *********************************************************************
137 * Allocate an ebuf with fields reserved for the UDP layer.
143 * pointer to ebuf, or NULL if no EBUFs are available
144 ********************************************************************* */
146 ebuf_t
*udp_alloc(void)
148 if (!netctx
) return NULL
;
149 return _udp_alloc(netctx
->udpinfo
);
152 /* *********************************************************************
155 * Return an ebuf to the pool. The ebuf was presumably allocated
156 * via udp_alloc() first.
159 * buf - ebuf to return to the pool
163 ********************************************************************* */
164 void udp_free(ebuf_t
*buf
)
167 _udp_free(netctx
->udpinfo
,buf
);
170 /* *********************************************************************
173 * Open a UDP socket. Once open, datagrams sent on the socket will
174 * go to the specified port number. You can change the port later
175 * using the "udp_connect" function.
181 * UDP port handle, or -1 if no ports are available.
182 ********************************************************************* */
184 int udp_socket(uint16_t port
)
186 if (!netctx
) return -1;
188 return _udp_socket(netctx
->udpinfo
,port
);
191 /* *********************************************************************
194 * Close a udp socket. You pass this handle returned from a previous
198 * handle - UDP port handle, from udp_open()
202 ********************************************************************* */
204 void udp_close(int portnum
)
208 _udp_close(netctx
->udpinfo
,portnum
);
212 /* *********************************************************************
213 * udp_send(s,buf,dest)
215 * Send a datagram to the specified destination address. The
216 * source and destination UDP port numbers are taken from the
217 * values passed to earlier calls to udp_open, udp_bind, and
221 * s - socket handle, from udp_open
222 * buf - ebuf to send (allocated via udp_alloc)
223 * dest - pointer to 4-byte destination IP address
227 * <0 if an error occured.
228 ********************************************************************* */
230 int udp_send(int s
,ebuf_t
*buf
,uint8_t *dest
)
232 if (!netctx
) return -1;
234 return _udp_send(netctx
->udpinfo
,s
,buf
,dest
);
237 /* *********************************************************************
240 * Re-"bind" the specified udp socket to a new source port.
241 * This changes the source port number that will be transmitted
242 * in subsequent calls to udp_send()
246 * port - new port number
249 * 0 if ok, else error code
250 ********************************************************************* */
252 int udp_bind(int s
,uint16_t port
)
254 if (!netctx
) return -1;
256 return _udp_bind(netctx
->udpinfo
,s
,port
);
260 /* *********************************************************************
261 * udp_connect(s,port)
263 * Set the port number to be used in the destination port field
264 * for subsequent calls to udp_send().
267 * s - udp socket handle
268 * port - new destination port number
271 * 0 if ok, else error code
272 ********************************************************************* */
274 int udp_connect(int s
,uint16_t port
)
276 if (!netctx
) return -1;
278 return _udp_connect(netctx
->udpinfo
,s
,port
);
281 /* *********************************************************************
284 * Return the next packet from the receive queue for this port.
285 * If no packets are available, NULL is returned.
288 * s - udp port handle
291 * ebuf (if a packet is available)
292 * NULL (no packet available)
293 ********************************************************************* */
295 ebuf_t
*udp_recv(int s
)
297 if (!netctx
) return NULL
;
299 return _udp_recv(netctx
->udpinfo
,s
);
303 /* *********************************************************************
304 * udp_recv_with_timeout(s,ticks)
306 * Return the next packet from the receive queue for this socket,
307 * waiting for one to arrive if there are none available.
310 * s - udp socket handle
311 * ticks - number of ticks to wait
314 * ebuf (if a packet is available)
315 * NULL (no packet available after timeout)
316 ********************************************************************* */
318 ebuf_t
*udp_recv_with_timeout(int s
,int ticks
)
323 if (!netctx
) return NULL
;
325 TIMER_SET(timer
,ticks
);
327 while (!TIMER_EXPIRED(timer
)) {
329 buf
= _udp_recv(netctx
->udpinfo
,s
);
339 /* *********************************************************************
341 ********************************************************************* */
344 /* *********************************************************************
347 * Create a new TCP port.
353 * TCP port handle, or <0 if no ports are available.
354 ********************************************************************* */
358 if (!netctx
) return -1;
360 return _tcp_socket(netctx
->tcpinfo
);
363 /* *********************************************************************
364 * tcp_connect(handle,dest,port)
366 * Connect to a remote TCP destination.
369 * handle - returned from tcp_create
370 * dest - destination IP address
371 * port - destination port number
376 ********************************************************************* */
378 int tcp_connect(int s
,uint8_t *dest
,uint16_t port
)
384 if (!netctx
) return -1;
387 * Get socket's blocking status
388 * If nonblocking, just call the tcp stack
389 * and return what it returns.
392 res
= _tcp_getflags(netctx
->tcpinfo
,s
,&flags
);
393 if (res
< 0) return res
;
395 if (flags
& TCPFLG_NBIO
) {
396 return _tcp_connect(netctx
->tcpinfo
,s
,dest
,port
);
400 * Otherwise, call connect and poll till the status
401 * changes. We want to see a transition to the
402 * CONNECTED state, so we loop while we see "CONNECTING"
403 * and return a status based on what it changes to.
406 res
= _tcp_connect(netctx
->tcpinfo
,s
,dest
,port
);
407 if (res
< 0) return res
;
408 connflag
= TCPSTATUS_NOTCONN
;
413 res
= _tcp_status(netctx
->tcpinfo
,s
,&connflag
,NULL
,NULL
);
416 if (connflag
== TCPSTATUS_CONNECTING
) continue;
420 if (connflag
!= TCPSTATUS_CONNECTED
) return CFE_ERR_NOTCONN
;
425 /* *********************************************************************
428 * Disconnect a connection (cleanly)
431 * s - handle from tcp_create
436 ********************************************************************* */
440 if (!netctx
) return -1;
442 return _tcp_close(netctx
->tcpinfo
,s
);
447 /* *********************************************************************
448 * tcp_send(s,buf,len)
450 * Send a buffer to the other TCP, buffering as much data as
451 * will fit in the send buffer.
454 * s - port handle, from tcp_open
455 * buf - buffer pointer
456 * len - length of buffer to send
459 * >=0 if ok (number of bytes sent)
460 * <0 if an error occured.
461 ********************************************************************* */
463 int tcp_send(int s
,uint8_t *buf
,int len
)
469 if (!netctx
) return -1;
472 * Get socket's blocking status
473 * If nonblocking, just call the tcp stack
474 * and return what it returns.
477 res
= _tcp_getflags(netctx
->tcpinfo
,s
,&flags
);
478 if (res
< 0) return res
;
480 if (flags
& TCPFLG_NBIO
) {
481 return _tcp_send(netctx
->tcpinfo
,s
,buf
,len
);
485 * The first time we'll check the return code for an
486 * error so we can pass up the failure.
489 res
= _tcp_send(netctx
->tcpinfo
,s
,buf
,len
);
490 if (res
< 0) return res
;
498 * Give the TCP stack and devices a chance to run
504 * Try to send some more. If we get an error, get out.
505 * otherwise, keep going till all the data is gone.
508 res
= _tcp_send(netctx
->tcpinfo
,s
,buf
,len
);
516 * If we sent nothing and have an error, return the error.
517 * Otherwise return the amount of data we sent.
519 if ((total
== 0) && (res
< 0)) return res
;
523 /* *********************************************************************
524 * tcp_recv(s,buf,len)
526 * Receive data from the remote TCP session
529 * s - port handle, from tcp_open
530 * buf - buffer pointer
531 * len - length of buffer to send
534 * >=0 if ok (number of bytes received)
535 * <0 if an error occured.
536 ********************************************************************* */
538 int tcp_recv(int s
,uint8_t *buf
,int len
)
544 if (!netctx
) return -1;
547 * Get socket's blocking status
548 * If nonblocking, just call the tcp stack
549 * and return what it returns.
552 res
= _tcp_getflags(netctx
->tcpinfo
,s
,&flags
);
553 if (res
< 0) return res
;
555 if (flags
& TCPFLG_NBIO
) {
556 return _tcp_recv(netctx
->tcpinfo
,s
,buf
,len
);
560 * The first time we'll check the return code for an
561 * error so we can pass up the failure.
564 res
= _tcp_recv(netctx
->tcpinfo
,s
,buf
,len
);
565 if (res
< 0) return res
;
573 * Give the TCP stack and devices a chance to run
579 * Try to receive some more. If we get an error, get out.
580 * otherwise, keep going till all the data is gone.
583 res
= _tcp_recv(netctx
->tcpinfo
,s
,buf
,len
);
587 _tcp_status(netctx
->tcpinfo
,s
,&flags
,NULL
,NULL
);
588 if (flags
!= TCPSTATUS_CONNECTED
) {
589 res
= CFE_ERR_NOTCONN
;
600 * If we sent received and have an error, return the error.
601 * Otherwise return the amount of data we sent.
603 if ((total
== 0) && (res
< 0)) return res
;
608 /* *********************************************************************
611 * Re-"bind" the specified tcp port handle to a new source port.
613 * Used for listening sockets.
617 * port - new port number
620 * 0 if ok, else error code
621 ********************************************************************* */
623 int tcp_bind(int s
,uint16_t port
)
625 if (!netctx
) return -1;
627 return _tcp_bind(netctx
->tcpinfo
,s
,port
);
630 /* *********************************************************************
631 * tcp_peeraddr(s,addr,port)
633 * Return the address of the remote peer.
637 * addr - points to 4-byte buffer to receive IP address
638 * port - points to uint16 to receive port number
641 * 0 if ok, else error code
642 ********************************************************************* */
644 int tcp_peeraddr(int s
,uint8_t *addr
,uint16_t *port
)
646 if (!netctx
) return -1;
648 return _tcp_peeraddr(netctx
->tcpinfo
,s
,addr
,port
);
651 /* *********************************************************************
652 * tcp_setflags(s,addr,flags)
654 * Set per-socket flags (nodelay, etc.)
658 * flags - flags for this socket
661 * 0 if ok, else error code
662 ********************************************************************* */
664 int tcp_setflags(int s
,unsigned int flags
)
666 if (!netctx
) return -1;
668 return _tcp_setflags(netctx
->tcpinfo
,s
,flags
);
671 /* *********************************************************************
672 * tcp_getflags(s,addr,flags)
674 * Get per-socket flags (nodelay, etc.)
678 * flags - flags for this socket
681 * 0 if ok, else error code
682 ********************************************************************* */
684 int tcp_getflags(int s
,unsigned int *flags
)
686 if (!netctx
) return -1;
688 return _tcp_getflags(netctx
->tcpinfo
,s
,flags
);
692 /* *********************************************************************
695 * Set the socket into "listen" mode.
699 * port - port # to listen on
704 ********************************************************************* */
706 int tcp_listen(int s
,uint16_t port
)
708 if (!netctx
) return -1;
710 return _tcp_listen(netctx
->tcpinfo
,s
,port
);
713 /* *********************************************************************
714 * tcp_status(s,connflag,rxready,rxeof)
716 * Return the TCP connection's status
720 * connflag - points to flag to receive connected status
721 * rxready - returns # of bytes ready to receive
722 * rxeof - returns TRUE if we've been FINed.
727 ********************************************************************* */
729 int tcp_status(int s
,int *connflag
,int *rxready
,int *rxeof
)
731 if (!netctx
) return -1;
733 return _tcp_status(netctx
->tcpinfo
,s
,connflag
,rxready
,rxeof
);
736 /* *********************************************************************
739 * Call the debug routine in the tcp stack.
743 * arg - passed to debug routine
746 * return value from debug routine
747 ********************************************************************* */
749 int tcp_debug(int s
,int arg
)
751 if (!netctx
) return -1;
752 return _tcp_debug(netctx
->tcpinfo
,s
,arg
);
757 /* *********************************************************************
759 ********************************************************************* */
762 /* *********************************************************************
763 * arp_add(destip,desthw)
765 * Add a permanent entry to the ARP table. This entry will
766 * persist until deleted or the interface is deactivated.
767 * This may cause a stale entry to be deleted if the table is full
770 * destip - pointer to 4-byte destination IP address
771 * desthw - pointer to 6-byte destination hardware address
775 ********************************************************************* */
777 void arp_add(uint8_t *destip
,uint8_t *desthw
)
779 if (netctx
) _arp_add(netctx
->ipinfo
,destip
,desthw
);
782 /* *********************************************************************
785 * Look up the hardware address for an IP address.
788 * destip - pointer to 4-byte IP address
791 * pointer to 6-byte hardware address, or NULL if there are
792 * no matching entries in the table.
793 ********************************************************************* */
795 uint8_t *arp_lookup(uint8_t *destip
)
797 if (!netctx
) return NULL
;
798 return _arp_lookup(netctx
->ipinfo
,destip
);
802 /* *********************************************************************
803 * arp_enumerate(entrynum,ipaddr,hwaddr)
805 * Return an entry from the ARP table.
808 * entrynum - entry number to return, starting with zero
809 * ipaddr - pointer to 4 bytes to receive IP address
810 * hwaddr - pointer to 6 bytes to receive hardware address
815 ********************************************************************* */
817 int arp_enumerate(int entrynum
,uint8_t *ipaddr
,uint8_t *hwaddr
)
819 if (!netctx
) return -1;
820 return _arp_enumerate(netctx
->ipinfo
,entrynum
,ipaddr
,hwaddr
);
823 /* *********************************************************************
826 * Delete an entry from the ARP table.
829 * ipaddr - pointer to 4-byte IP address
834 ********************************************************************* */
836 int arp_delete(uint8_t *ipaddr
)
838 if (!netctx
) return -1;
839 return _arp_delete(netctx
->ipinfo
,ipaddr
);
842 /* *********************************************************************
844 ********************************************************************* */
846 /* *********************************************************************
847 * icmp_ping(dest,seq,len)
849 * Ping a remote host, transmitting the ICMP_ECHO message and
850 * waiting for the corresponding ICMP_ECHO_REPLY.
853 * dest - pointer to 4-byte destination IP address
854 * seq - sequence number to put in to the ICMP packet
855 * len - length of data to place in ICMP packet
858 * 0 if ok (remote host responded)
860 ********************************************************************* */
862 int icmp_ping(uint8_t *dest
,int seq
,int len
)
864 if (!netctx
) return -1;
865 return _icmp_ping(netctx
->icmpinfo
,dest
,seq
,len
);
868 /* *********************************************************************
869 * INIT/CONFIG FUNCTIONS
870 ********************************************************************* */
872 /* *********************************************************************
873 * net_getparam(param)
875 * Return a parameter from the current IP configuration. This is
876 * the main call to set the IP address, netmask, gateway,
877 * name server, host name, etc.
880 * param - parameter number (see net_api.h)
883 * pointer to value of parameter, or NULL if parameter
885 ********************************************************************* */
887 uint8_t *net_getparam(int param
)
889 if (!netctx
) return NULL
;
890 if (param
== NET_DEVNAME
) return (uint8_t *) netctx
->devname
;
891 return _ip_getparam(netctx
->ipinfo
,param
);
895 /* *********************************************************************
896 * net_setparam(param,ptr)
898 * Set the value of an IP configuration parameter
901 * param - parameter number (see net_api.h)
902 * ptr - pointer to parameter's new value
907 ********************************************************************* */
909 int net_setparam(int param
,uint8_t *ptr
)
911 if (!netctx
) return NULL
;
912 return _ip_setparam(netctx
->ipinfo
,param
,ptr
);
915 /* *********************************************************************
918 * Process background tasks for the network stack, maintaining
919 * the ARP table, receive queues, etc.
926 ********************************************************************* */
928 static void net_poll(void *arg
)
931 eth_poll(netctx
->ethinfo
);
932 if (TIMER_EXPIRED(netctx
->timer
)) {
933 _ip_timer_tick(netctx
->ipinfo
);
935 TIMER_SET(netctx
->timer
,CFE_HZ
/10);
937 TIMER_SET(netctx
->timer
,CFE_HZ
);
943 /* *********************************************************************
946 * Initialize the network interface. This is the main call, once
947 * completed you should call net_setparam to set up the network
948 * addresses and stuff.
951 * devname - CFE device name for network device
956 ********************************************************************* */
958 int net_init(char *devname
)
962 if (netctx
) net_uninit();
964 ctx
= KMALLOC(sizeof(net_ctx_t
),0);
968 ctx
->devname
= strdup(devname
);
970 ctx
->ethinfo
= eth_init(devname
);
971 if (ctx
->ethinfo
== NULL
) {
975 ctx
->ipinfo
= _ip_init(ctx
->ethinfo
);
976 if (ctx
->ipinfo
== NULL
) {
977 eth_uninit(ctx
->ethinfo
);
981 ctx
->udpinfo
= _udp_init(ctx
->ipinfo
,ctx
->ipinfo
);
982 if (ctx
->udpinfo
== NULL
) {
983 _ip_uninit(ctx
->ipinfo
);
984 eth_uninit(ctx
->ethinfo
);
988 ctx
->icmpinfo
= _icmp_init(ctx
->ipinfo
);
989 if (ctx
->icmpinfo
== NULL
) {
990 _udp_uninit(ctx
->udpinfo
);
991 _ip_uninit(ctx
->ipinfo
);
992 eth_uninit(ctx
->ethinfo
);
996 cfe_bg_add(net_poll
,ctx
);
998 TIMER_SET(ctx
->timer
,CFE_HZ
/10);
1000 TIMER_SET(ctx
->timer
,CFE_HZ
);
1001 #endif /* CFG_SIM */
1004 ctx
->tcpinfo
= _tcp_init(ctx
->ipinfo
,ctx
->ipinfo
);
1005 cfe_bg_add(_tcp_poll
,ctx
->tcpinfo
);
1009 ctx
->httpinfo
= _tcphttp_init(ctx
->ipinfo
,ctx
->ipinfo
);
1017 /* *********************************************************************
1020 * Uninitialize the network, deallocating all resources allocated
1021 * to the network and closing all open device handles
1028 ********************************************************************* */
1030 void net_uninit(void)
1034 cfe_bg_remove(_tcp_poll
);
1035 _tcp_uninit(netctx
->tcpinfo
);
1038 _tcphttp_uninit(netctx
->httpinfo
);
1040 TIMER_CLEAR(netctx
->timer
);
1041 _icmp_uninit(netctx
->icmpinfo
);
1042 _udp_uninit(netctx
->udpinfo
);
1043 _ip_uninit(netctx
->ipinfo
);
1044 eth_uninit(netctx
->ethinfo
);
1045 KFREE(netctx
->devname
);
1048 cfe_bg_remove(net_poll
);
1053 /* *********************************************************************
1056 * Set environment variables related to the network.
1063 ********************************************************************* */
1065 void net_setnetvars(void)
1071 /* Clear out all the environment variables */
1072 env_delenv("NET_DEVICE");
1073 env_delenv("NET_IPADDR");
1074 env_delenv("NET_NETMASK");
1075 env_delenv("NET_GATEWAY");
1076 env_delenv("NET_NAMESERVER");
1077 env_delenv("NET_DOMAIN");
1079 x
= (char *) net_getparam(NET_DEVNAME
);
1084 x
= (char *) net_getparam(NET_DEVNAME
);
1085 if (x
) env_setenv("NET_DEVICE",x
,ENV_FLG_BUILTIN
);
1087 x
= (char *) net_getparam(NET_DOMAIN
);
1088 if (x
) env_setenv("NET_DOMAIN",x
,ENV_FLG_BUILTIN
);
1090 addr
= net_getparam(NET_IPADDR
);
1092 xsprintf(str
,"%I",addr
);
1093 env_setenv("NET_IPADDR",str
,ENV_FLG_BUILTIN
);
1096 addr
= net_getparam(NET_NETMASK
);
1098 xsprintf(str
,"%I",addr
);
1099 env_setenv("NET_NETMASK",str
,ENV_FLG_BUILTIN
);
1102 addr
= net_getparam(NET_GATEWAY
);
1104 xsprintf(str
,"%I",addr
);
1105 env_setenv("NET_GATEWAY",str
,ENV_FLG_BUILTIN
);
1108 addr
= net_getparam(NET_NAMESERVER
);
1110 xsprintf(str
,"%I",addr
);
1111 env_setenv("NET_NAMESERVER",str
,ENV_FLG_BUILTIN
);