GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / net / net_ip.c
blob03dd1fef0d932cb2f8cee7db0d37a6342d436221
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * Internet Protocol File: net_ip.c
5 *
6 * This module implements the IP layer (RFC791)
7 *
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
9 *
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"
54 #include "net_ebuf.h"
55 #include "net_ether.h"
57 #include "net_ip.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 /* *********************************************************************
69 * _ip_alloc(ipi)
71 * Allocate an ebuf and reserve space for the IP header in it.
73 * Input parameters:
74 * ipi - IP stack information
76 * Return value:
77 * ebuf - an ebuf, or NULL if there are none left
78 ********************************************************************* */
80 ebuf_t *_ip_alloc(ip_info_t *ipi)
82 ebuf_t *buf;
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);
91 return buf;
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.
102 * Input parameters:
103 * initcksum - initial checksum (usually zero)
104 * ptr - pointer to buffer to checksum
105 * len - length of data in bytes
107 * Return value:
108 * checksum (16 bits)
109 ********************************************************************* */
111 uint16_t ip_chksum(uint16_t initcksum,uint8_t *ptr,int len)
113 unsigned int cksum;
114 int idx;
115 int odd;
117 cksum = (unsigned int) initcksum;
119 odd = len & 1;
120 len -= odd;
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);
138 return cksum;
142 /* *********************************************************************
143 * _ip_send(ipi,buf,destaddr,proto)
145 * Send an IP datagram. We only support non-fragmented datagrams
146 * at this time.
148 * Input parameters:
149 * ipi - IP stack information
150 * buf - an ebuf
151 * destaddr - destination IP address
152 * proto - IP protocol number
154 * Return value:
155 * 0 if ok
156 * else error code
157 ********************************************************************* */
159 int _ip_send(ip_info_t *ipi,ebuf_t *buf,uint8_t *destaddr,uint8_t proto)
161 uint16_t cksum;
162 uint8_t masksrc[IP_ADDR_LEN];
163 uint8_t maskdest[IP_ADDR_LEN];
164 int pktlen;
165 uint8_t *ptr;
167 /* Move to the beginning of the IP hdeader */
169 ebuf_seek(buf,-IPHDR_LENGTH);
171 pktlen = ebuf_length(buf) + IPHDR_LENGTH;
173 ipi->ip_id++;
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 */
194 ptr = ebuf_ptr(buf);
195 cksum = ip_chksum(0,ptr,IPHDR_LENGTH);
196 cksum = ~cksum;
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);
207 eth_free(buf);
208 return 0;
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
230 * the gateway.
233 if (ip_compareaddr(masksrc,maskdest) == 0) {
234 return _arp_lookup_and_send(ipi,buf,destaddr);
236 else {
237 /* if no gw configured, drop packet */
238 if (ip_addriszero(ipi->net_info.ip_gateway)) {
239 eth_free(buf); /* silently drop */
240 return 0;
242 else {
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.
257 * Input parameters:
258 * buf - ebuf we received
259 * ref - reference data from the ethernet datalink
261 * Return value:
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;
269 uint8_t tmp;
270 int hdrlen;
271 uint8_t *hdr;
272 uint16_t origchksum;
273 uint16_t calcchksum;
274 uint16_t length;
275 uint16_t tmp16;
276 uint8_t proto;
277 uint8_t srcip[IP_ADDR_LEN];
278 uint8_t dstip[IP_ADDR_LEN];
279 ip_protodisp_t *pdisp;
280 int res;
281 int idx;
283 hdr = ebuf_ptr(buf); /* save current posn */
285 ebuf_get_u8(buf,tmp); /* version and header length */
288 * Check IP version
291 if ((tmp & 0xF0) != IPHDR_VER_4) {
292 goto drop; /* not IPV4 */
294 hdrlen = (tmp & 0x0F) * 4;
297 * Check header size
300 if (hdrlen < IPHDR_LENGTH) {
301 goto drop; /* header < 20 bytes */
305 * Check the checksum
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) {
311 goto drop;
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;
368 res = ETH_DROP;
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);
372 break;
374 pdisp++;
378 return res;
380 drop:
381 return ETH_DROP;
385 /* *********************************************************************
386 * _ip_init(eth)
388 * Initialize the IP layer, attaching it to an underlying Ethernet
389 * datalink interface.
391 * Input parameters:
392 * eth - Ethernet datalink information
394 * Return value:
395 * ip_info pointer (IP stack information) or NULL if error
396 ********************************************************************* */
398 ip_info_t *_ip_init(ether_info_t *eth)
400 ip_info_t *ipi;
401 uint8_t ipproto[2];
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));
412 ipi->eth_info = eth;
415 * Initialize ARP
418 if (_arp_init(ipi) < 0) {
419 KFREE(ipi);
420 return NULL;
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) {
431 _arp_uninit(ipi);
432 KFREE(ipi);
433 return NULL;
436 return ipi;
440 /* *********************************************************************
441 * _ip_uninit(ipi)
443 * Un-initialize the IP layer, freeing resources
445 * Input parameters:
446 * ipi - IP stack information
448 * Return value:
449 * nothing
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.
464 _arp_uninit(ipi);
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
483 KFREE(ipi);
487 /* *********************************************************************
488 * _ip_timer_tick(ipi)
490 * Called once per second while the IP stack is active.
492 * Input parameters:
493 * ipi - ip stack information
495 * Return value:
496 * nothing
497 ********************************************************************* */
500 void _ip_timer_tick(ip_info_t *ipi)
502 _arp_timer_tick(ipi);
506 /* *********************************************************************
507 * _ip_free(ipi,buf)
509 * Free an ebuf allocated via _ip_alloc
511 * Input parameters:
512 * ipi - IP stack information
513 * buf - ebuf to free
515 * Return value:
516 * nothing
517 ********************************************************************* */
519 void _ip_free(ip_info_t *ipi,ebuf_t *buf)
521 eth_free(buf);
524 /* *********************************************************************
525 * _ip_getaddr(ipi,buf)
527 * Return our IP address (is this used?)
529 * Input parameters:
530 * ipi - IP stack information
531 * buf - pointer to 4-byte buffer to receive IP address
533 * Return value:
534 * nothing
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.
549 * Input parameters:
550 * ipi - IP stack information
551 * param - parameter number
553 * Return value:
554 * parameter value, or NULL if the parameter is invalid or
555 * not set.
556 ********************************************************************* */
558 uint8_t *_ip_getparam(ip_info_t *ipinfo,int param)
560 uint8_t *ret = NULL;
562 switch (param) {
563 case NET_IPADDR:
564 ret = ipinfo->net_info.ip_addr;
565 break;
566 case NET_NETMASK:
567 ret = ipinfo->net_info.ip_netmask;
568 break;
569 case NET_GATEWAY:
570 ret = ipinfo->net_info.ip_gateway;
571 break;
572 case NET_NAMESERVER:
573 ret = ipinfo->net_info.ip_nameserver;
574 break;
575 case NET_HWADDR:
576 ret = ipinfo->arp_hwaddr;
577 break;
578 case NET_DOMAIN:
579 ret = (uint8_t *)ipinfo->net_info.ip_domain;
580 break;
581 case NET_HOSTNAME:
582 ret = (uint8_t *)ipinfo->net_info.ip_hostname;
583 break;
584 case NET_SPEED:
585 return NULL;
586 break;
587 case NET_LOOPBACK:
588 return NULL;
589 break;
592 return ret;
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.
602 * Input parameters:
603 * ipi - IP stack information
604 * param - parameter number
605 * value - parameter's new value
607 * Return value:
608 * 0 if ok, else error code
609 ********************************************************************* */
611 int _ip_setparam(ip_info_t *ipinfo,int param,uint8_t *ptr)
613 int res = -1;
615 switch (param) {
616 case NET_IPADDR:
617 memcpy(ipinfo->net_info.ip_addr,ptr,IP_ADDR_LEN);
618 _arp_send_gratuitous(ipinfo);
619 res = 0;
620 break;
621 case NET_NETMASK:
622 memcpy(ipinfo->net_info.ip_netmask,ptr,IP_ADDR_LEN);
623 res = 0;
624 break;
625 case NET_GATEWAY:
626 memcpy(ipinfo->net_info.ip_gateway,ptr,IP_ADDR_LEN);
627 res = 0;
628 break;
629 case NET_NAMESERVER:
630 memcpy(ipinfo->net_info.ip_nameserver,ptr,IP_ADDR_LEN);
631 res = 0;
632 break;
633 case NET_DOMAIN:
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);
639 break;
640 case NET_HOSTNAME:
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);
646 break;
647 case NET_HWADDR:
648 memcpy(ipinfo->arp_hwaddr,ptr,ENET_ADDR_LEN);
649 eth_sethwaddr(ipinfo->eth_info,ptr);
650 res = 0;
651 break;
652 case NET_SPEED:
653 res = eth_setspeed(ipinfo->eth_info,*(int *)ptr);
654 break;
655 case NET_LOOPBACK:
656 res = eth_setloopback(ipinfo->eth_info,*(int *)ptr);
657 break;
660 return res;
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
668 * callbacks.
670 * Input parameters:
671 * ipinfo - IP stack information
672 * proto - IP protocol number
673 * cb - callback routine to register
675 * Return value:
676 * nothing
677 ********************************************************************* */
679 void _ip_register(ip_info_t *ipinfo,
680 int proto,
681 int (*cb)(void *ref,ebuf_t *buf,uint8_t *dst,uint8_t *src),void *ref)
683 int idx;
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.
702 * Input parameters:
703 * ipinfo - IP stack information
704 * proto - protocol number
706 * Return value:
707 * nothing
708 ********************************************************************* */
710 void _ip_deregister(ip_info_t *ipinfo,int proto)
712 int idx;
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;