1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * Internet Protocol File: net_ip.c
6 * This module implements the IP layer (RFC791)
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
10 *********************************************************************
12 * Copyright 2000,2001,2002,2003
13 * Broadcom Corporation. All rights reserved.
15 * This software is furnished under license and may be used and
16 * copied only in accordance with the following terms and
17 * conditions. Subject to these conditions, you may download,
18 * copy, install, use, modify and distribute modified or unmodified
19 * copies of this software in source and/or binary form. No title
20 * or ownership is transferred hereby.
22 * 1) Any source code used, modified or distributed must reproduce
23 * and retain this copyright notice and list of conditions
24 * as they appear in the source file.
26 * 2) No right is granted to use any trade name, trademark, or
27 * logo of Broadcom Corporation. The "Broadcom Corporation"
28 * name may not be used to endorse or promote products derived
29 * from this software without the prior written permission of
30 * Broadcom Corporation.
32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
44 * THE POSSIBILITY OF SUCH DAMAGE.
45 ********************************************************************* */
48 #include "lib_types.h"
49 #include "lib_string.h"
50 #include "lib_queue.h"
51 #include "lib_malloc.h"
52 #include "lib_printf.h"
55 #include "net_ether.h"
58 #include "net_ip_internal.h"
60 #include "cfe_error.h"
62 /* *********************************************************************
63 * Forward declarations
64 ********************************************************************* */
66 static int ip_rx_callback(ebuf_t
*buf
,void *ref
);
68 /* *********************************************************************
71 * Allocate an ebuf and reserve space for the IP header in it.
74 * ipi - IP stack information
77 * ebuf - an ebuf, or NULL if there are none left
78 ********************************************************************* */
80 ebuf_t
*_ip_alloc(ip_info_t
*ipi
)
84 buf
= eth_alloc(ipi
->eth_info
,ipi
->ip_port
);
86 if (buf
== NULL
) return buf
;
88 ebuf_seek(buf
,IPHDR_LENGTH
);
89 ebuf_setlength(buf
,0);
95 /* *********************************************************************
96 * ip_chksum(initcksum,ptr,len)
98 * Do an IP checksum for the specified buffer. You can pass
99 * an initial checksum if you're continuing a previous checksum
100 * calculation, such as for UDP headers and pseudoheaders.
103 * initcksum - initial checksum (usually zero)
104 * ptr - pointer to buffer to checksum
105 * len - length of data in bytes
109 ********************************************************************* */
111 uint16_t ip_chksum(uint16_t initcksum
,uint8_t *ptr
,int len
)
117 cksum
= (unsigned int) initcksum
;
122 for (idx
= 0; idx
< len
; idx
+= 2) {
123 cksum
+= ((unsigned long) ptr
[idx
] << 8) + ((unsigned long) ptr
[idx
+1]);
126 if (odd
) { /* buffer is odd length */
127 cksum
+= ((unsigned long) ptr
[idx
] << 8);
131 * Fold in the carries
134 while (cksum
>> 16) {
135 cksum
= (cksum
& 0xFFFF) + (cksum
>> 16);
142 /* *********************************************************************
143 * _ip_send(ipi,buf,destaddr,proto)
145 * Send an IP datagram. We only support non-fragmented datagrams
149 * ipi - IP stack information
151 * destaddr - destination IP address
152 * proto - IP protocol number
157 ********************************************************************* */
159 int _ip_send(ip_info_t
*ipi
,ebuf_t
*buf
,uint8_t *destaddr
,uint8_t proto
)
162 uint8_t masksrc
[IP_ADDR_LEN
];
163 uint8_t maskdest
[IP_ADDR_LEN
];
167 /* Move to the beginning of the IP hdeader */
169 ebuf_seek(buf
,-IPHDR_LENGTH
);
171 pktlen
= ebuf_length(buf
) + IPHDR_LENGTH
;
175 /* Insert the IP header */
177 ebuf_put_u8(buf
,IPHDR_VER_4
| IPHDR_LEN_20
);
178 ebuf_put_u8(buf
,IPHDR_TOS_DEFAULT
);
179 ebuf_put_u16_be(buf
,pktlen
);
180 ebuf_put_u16_be(buf
,ipi
->ip_id
);
181 ebuf_put_u16_be(buf
,0);
182 ebuf_put_u8(buf
,IPHDR_TTL_DEFAULT
);
183 ebuf_put_u8(buf
,proto
);
184 ebuf_put_u16_be(buf
,0); /* checksum */
185 ebuf_put_bytes(buf
,ipi
->net_info
.ip_addr
,IP_ADDR_LEN
);
186 ebuf_put_bytes(buf
,destaddr
,IP_ADDR_LEN
);
188 /* adjust pointer and add in the header length */
190 ebuf_prepend(buf
,IPHDR_LENGTH
);
192 /* Checksum the header */
195 cksum
= ip_chksum(0,ptr
,IPHDR_LENGTH
);
197 ptr
[10] = (cksum
>> 8) & 0xFF;
198 ptr
[11] = (cksum
>> 0) & 0xFF;
201 * If sending to the IP broadcast address,
202 * send to local broadcast.
205 if (ip_addrisbcast(destaddr
)) {
206 eth_send(buf
,(uint8_t *) eth_broadcast
);
212 * If the mask has not been set, don't try to
213 * determine if we should use the gateway or not.
216 if (ip_addriszero(ipi
->net_info
.ip_netmask
)) {
217 return _arp_lookup_and_send(ipi
,buf
,destaddr
);
221 * Compute (dest-addr & netmask) and (my-addr & netmask)
224 ip_mask(masksrc
,destaddr
,ipi
->net_info
.ip_netmask
);
225 ip_mask(maskdest
,ipi
->net_info
.ip_addr
,ipi
->net_info
.ip_netmask
);
228 * if destination and my address are on the same subnet,
229 * send the packet directly. Otherwise, send via
233 if (ip_compareaddr(masksrc
,maskdest
) == 0) {
234 return _arp_lookup_and_send(ipi
,buf
,destaddr
);
237 /* if no gw configured, drop packet */
238 if (ip_addriszero(ipi
->net_info
.ip_gateway
)) {
239 eth_free(buf
); /* silently drop */
243 return _arp_lookup_and_send(ipi
,buf
,ipi
->net_info
.ip_gateway
);
250 /* *********************************************************************
251 * ip_rx_callback(buf,ref)
253 * Receive callback for IP packets. This routine is called
254 * by the Ethernet datalink. We look up a suitable protocol
255 * handler and pass the packet off.
258 * buf - ebuf we received
259 * ref - reference data from the ethernet datalink
262 * ETH_KEEP to keep the packet
263 * ETH_DROP to drop the packet
264 ********************************************************************* */
266 static int ip_rx_callback(ebuf_t
*buf
,void *ref
)
268 ip_info_t
*ipi
= ref
;
277 uint8_t srcip
[IP_ADDR_LEN
];
278 uint8_t dstip
[IP_ADDR_LEN
];
279 ip_protodisp_t
*pdisp
;
283 hdr
= ebuf_ptr(buf
); /* save current posn */
285 ebuf_get_u8(buf
,tmp
); /* version and header length */
291 if ((tmp
& 0xF0) != IPHDR_VER_4
) {
292 goto drop
; /* not IPV4 */
294 hdrlen
= (tmp
& 0x0F) * 4;
300 if (hdrlen
< IPHDR_LENGTH
) {
301 goto drop
; /* header < 20 bytes */
307 origchksum
= ((uint16_t) hdr
[10] << 8) | (uint16_t) hdr
[11];
308 hdr
[10] = hdr
[11] = 0;
309 calcchksum
= ~ip_chksum(0,hdr
,hdrlen
);
310 if (calcchksum
!= origchksum
) {
315 * Okay, now go back and check other fields.
318 ebuf_skip(buf
,1); /* skip TOS field */
320 ebuf_get_u16_be(buf
,length
);
321 ebuf_skip(buf
,2); /* skip ID field */
323 ebuf_get_u16_be(buf
,tmp16
); /* get Fragment Offset field */
326 * If the fragment offset field is nonzero, or the
327 * "more fragments" bit is set, then this is a packet
328 * fragment. Our trivial IP implementation does not
329 * deal with fragments, so drop the packets.
331 if ((tmp16
& (IPHDR_FRAGOFFSET
| IPHDR_MOREFRAGMENTS
)) != 0) {
332 goto drop
; /* packet is fragmented */
335 ebuf_skip(buf
,1); /* skip TTL */
336 ebuf_get_u8(buf
,proto
); /* get protocol */
337 ebuf_skip(buf
,2); /* skip checksum */
339 ebuf_get_bytes(buf
,srcip
,IP_ADDR_LEN
);
340 ebuf_get_bytes(buf
,dstip
,IP_ADDR_LEN
);
342 ebuf_skip(buf
,hdrlen
-IPHDR_LENGTH
); /* skip rest of header */
344 ebuf_setlength(buf
,length
-hdrlen
); /* set length to just data portion */
347 * If our address is not set, let anybody in. We need this to
348 * properly pass up DHCP replies that get forwarde through routers.
349 * Otherwise, only let in matching addresses or broadcasts.
352 if (!ip_addriszero(ipi
->net_info
.ip_addr
)) {
353 if ((ip_compareaddr(dstip
,ipi
->net_info
.ip_addr
) != 0) &&
354 !(ip_addrisbcast(dstip
))) {
355 goto drop
; /* not for us */
360 * ebuf's pointer now starts at beginning of protocol data
364 * Find matching protocol dispatch
367 pdisp
= ipi
->ip_protocols
;
369 for (idx
= 0; idx
< IP_MAX_PROTOCOLS
; idx
++) {
370 if (pdisp
->cb
&& (pdisp
->protocol
== proto
)) {
371 res
= (*(pdisp
->cb
))(pdisp
->ref
,buf
,dstip
,srcip
);
385 /* *********************************************************************
388 * Initialize the IP layer, attaching it to an underlying Ethernet
389 * datalink interface.
392 * eth - Ethernet datalink information
395 * ip_info pointer (IP stack information) or NULL if error
396 ********************************************************************* */
398 ip_info_t
*_ip_init(ether_info_t
*eth
)
404 * Allocate IP stack info
407 ipi
= KMALLOC(sizeof(ip_info_t
),0);
408 if (ipi
== NULL
) return NULL
;
410 memset(ipi
,0,sizeof(ip_info_t
));
418 if (_arp_init(ipi
) < 0) {
424 * Open the Ethernet portal for IP packets
427 ipproto
[0] = (PROTOSPACE_IP
>> 8) & 0xFF; ipproto
[1] = PROTOSPACE_IP
& 0xFF;
428 ipi
->ip_port
= eth_open(ipi
->eth_info
,ETH_PTYPE_DIX
,(int8_t *)ipproto
,ip_rx_callback
,ipi
);
430 if (ipi
->ip_port
< 0) {
440 /* *********************************************************************
443 * Un-initialize the IP layer, freeing resources
446 * ipi - IP stack information
450 ********************************************************************* */
452 void _ip_uninit(ip_info_t
*ipi
)
455 * Close the IP portal
458 eth_close(ipi
->eth_info
,ipi
->ip_port
);
461 * Turn off the ARP layer.
468 * free strings containing the domain and host names
471 if (ipi
->net_info
.ip_domain
) {
472 KFREE(ipi
->net_info
.ip_domain
);
475 if (ipi
->net_info
.ip_hostname
) {
476 KFREE(ipi
->net_info
.ip_hostname
);
480 * Free the stack information
487 /* *********************************************************************
488 * _ip_timer_tick(ipi)
490 * Called once per second while the IP stack is active.
493 * ipi - ip stack information
497 ********************************************************************* */
500 void _ip_timer_tick(ip_info_t
*ipi
)
502 _arp_timer_tick(ipi
);
506 /* *********************************************************************
509 * Free an ebuf allocated via _ip_alloc
512 * ipi - IP stack information
517 ********************************************************************* */
519 void _ip_free(ip_info_t
*ipi
,ebuf_t
*buf
)
524 /* *********************************************************************
525 * _ip_getaddr(ipi,buf)
527 * Return our IP address (is this used?)
530 * ipi - IP stack information
531 * buf - pointer to 4-byte buffer to receive IP address
535 ********************************************************************* */
537 void _ip_getaddr(ip_info_t
*ipi
,uint8_t *buf
)
539 memcpy(buf
,ipi
->net_info
.ip_addr
,IP_ADDR_LEN
);
542 /* *********************************************************************
543 * _ip_getparam(ipi,param)
545 * Return the value of an IP parameter (address, netmask, etc.).
546 * The return value may need to be coerced if it's not normally
547 * a uint8_t* pointer.
550 * ipi - IP stack information
551 * param - parameter number
554 * parameter value, or NULL if the parameter is invalid or
556 ********************************************************************* */
558 uint8_t *_ip_getparam(ip_info_t
*ipinfo
,int param
)
564 ret
= ipinfo
->net_info
.ip_addr
;
567 ret
= ipinfo
->net_info
.ip_netmask
;
570 ret
= ipinfo
->net_info
.ip_gateway
;
573 ret
= ipinfo
->net_info
.ip_nameserver
;
576 ret
= ipinfo
->arp_hwaddr
;
579 ret
= (uint8_t *)ipinfo
->net_info
.ip_domain
;
582 ret
= (uint8_t *)ipinfo
->net_info
.ip_hostname
;
595 /* *********************************************************************
596 * _ip_getparam(ipi,param,value)
598 * Set the value of an IP parameter (address, netmask, etc.).
599 * The value may need to be coerced if it's not normally
600 * a uint8_t* pointer.
603 * ipi - IP stack information
604 * param - parameter number
605 * value - parameter's new value
608 * 0 if ok, else error code
609 ********************************************************************* */
611 int _ip_setparam(ip_info_t
*ipinfo
,int param
,uint8_t *ptr
)
617 memcpy(ipinfo
->net_info
.ip_addr
,ptr
,IP_ADDR_LEN
);
618 _arp_send_gratuitous(ipinfo
);
622 memcpy(ipinfo
->net_info
.ip_netmask
,ptr
,IP_ADDR_LEN
);
626 memcpy(ipinfo
->net_info
.ip_gateway
,ptr
,IP_ADDR_LEN
);
630 memcpy(ipinfo
->net_info
.ip_nameserver
,ptr
,IP_ADDR_LEN
);
634 if (ipinfo
->net_info
.ip_domain
) {
635 KFREE(ipinfo
->net_info
.ip_domain
);
636 ipinfo
->net_info
.ip_domain
= NULL
;
638 if (ptr
) ipinfo
->net_info
.ip_domain
= strdup((char *) ptr
);
641 if (ipinfo
->net_info
.ip_hostname
) {
642 KFREE(ipinfo
->net_info
.ip_hostname
);
643 ipinfo
->net_info
.ip_hostname
= NULL
;
645 if (ptr
) ipinfo
->net_info
.ip_hostname
= strdup((char *) ptr
);
648 memcpy(ipinfo
->arp_hwaddr
,ptr
,ENET_ADDR_LEN
);
649 eth_sethwaddr(ipinfo
->eth_info
,ptr
);
653 res
= eth_setspeed(ipinfo
->eth_info
,*(int *)ptr
);
656 res
= eth_setloopback(ipinfo
->eth_info
,*(int *)ptr
);
663 /* *********************************************************************
664 * _ip_register(ipinfo,proto,cb)
666 * Register a protocol handler with the IP layer. IP client
667 * protocols such as UDP, ICMP, etc. call this to register their
671 * ipinfo - IP stack information
672 * proto - IP protocol number
673 * cb - callback routine to register
677 ********************************************************************* */
679 void _ip_register(ip_info_t
*ipinfo
,
681 int (*cb
)(void *ref
,ebuf_t
*buf
,uint8_t *dst
,uint8_t *src
),void *ref
)
685 for (idx
= 0; idx
< IP_MAX_PROTOCOLS
; idx
++) {
686 if (ipinfo
->ip_protocols
[idx
].cb
== NULL
) break;
689 if (idx
== IP_MAX_PROTOCOLS
) return;
691 ipinfo
->ip_protocols
[idx
].protocol
= (uint8_t) proto
;
692 ipinfo
->ip_protocols
[idx
].cb
= cb
;
693 ipinfo
->ip_protocols
[idx
].ref
= ref
;
697 /* *********************************************************************
698 * _ip_deregister(ipinfo,proto)
700 * Deregister an IP protocol.
703 * ipinfo - IP stack information
704 * proto - protocol number
708 ********************************************************************* */
710 void _ip_deregister(ip_info_t
*ipinfo
,int proto
)
714 for (idx
= 0; idx
< IP_MAX_PROTOCOLS
; idx
++) {
715 if (ipinfo
->ip_protocols
[idx
].protocol
== (uint8_t) proto
) {
716 ipinfo
->ip_protocols
[idx
].protocol
= 0;
717 ipinfo
->ip_protocols
[idx
].ref
= 0;
718 ipinfo
->ip_protocols
[idx
].cb
= NULL
;