diff --git a/CHANGELOG b/CHANGELOG index 485f1d0a..873476a1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,12 @@ HISTORY ++ New features: + 2007-06-09 Dominik Spies (integrated by Frédéric Bernon) + * autoip.h, autoip.c, dhcp.h, dhcp.c, netif.h, netif.c, etharp.h, etharp.c, opt.h: + AutoIP implementation available for IPv4, with new options LWIP_AUTOIP and + LWIP_DHCP_AUTOIP_COOP if you want to cooperate with DHCP. Some tips to adapt + (see TODO mark in the source code). + 2007-06-09 Simon Goldschmidt * etharp.h, etharp.c, ethernetif.c: Modified order of parameters for etharp_output() to match netif->output so etharp_output() can be used diff --git a/src/core/dhcp.c b/src/core/dhcp.c index a3548208..09d7d3ab 100644 --- a/src/core/dhcp.c +++ b/src/core/dhcp.c @@ -538,6 +538,10 @@ err_t dhcp_start(struct netif *netif) struct dhcp *dhcp = netif->dhcp; err_t result = ERR_OK; +#if LWIP_DHCP_AUTOIP_COOP + autoip_init(); +#endif /* LWIP_DHCP_AUTOIP_COOP */ + LWIP_ASSERT("netif != NULL", netif != NULL); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); netif->flags &= ~NETIF_FLAG_DHCP; @@ -766,6 +770,13 @@ static err_t dhcp_discover(struct netif *netif) LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n")); } dhcp->tries++; +#if LWIP_DHCP_AUTOIP_COOP + /* that means we waited 57 seconds */ + if(dhcp->tries >= 9 && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; + autoip_start(netif); + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); diff --git a/src/core/ipv4/autoip.c b/src/core/ipv4/autoip.c new file mode 100644 index 00000000..f576853d --- /dev/null +++ b/src/core/ipv4/autoip.c @@ -0,0 +1,374 @@ +/** + * @file + * + * AutoIP Automatic LinkLocal IP Configuration + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + * + * Please coordinate changes and requests with Dominik Spies + * + */ + +#include +#include +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/autoip.h" +#include "netif/etharp.h" + +#if LWIP_AUTOIP /* don't build if not configured for use in lwipopt.h */ + +/* static functions */ +static void autoip_handle_arp_conflict(struct netif *netif); + +/* creates random LL IP-Address */ +static void autoip_create_rand_addr(struct ip_addr *RandomIPAddr); + +/* sends an ARP announce */ +static err_t autoip_arp_announce(struct netif *netif); + +/* configure interface for use with current LL IP-Address */ +static err_t autoip_bind(struct netif *netif); + +/** + * Initialize this module + * seed random with MAC-Address for creating pseudo-ramdom linc-local address + */ +void +autoip_init(void) +{ + /* TODO MAC_ADDRESS macaddr; */ + + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | 3, ("autoip_init()\n")); + + /* TODO Get_Current_MAC_Address(&macaddr);*/ + /*srand( + (macaddr.addr[2] << 24) | + (macaddr.addr[3] << 16) | + (macaddr.addr[4] << 8) | + (macaddr.addr[5] << 0) + );*/ +} + +/** + * TODO: Add comment + */ +static void +autoip_handle_arp_conflict(struct netif *netif) +{ + /* Somehow detect if we are defending or retreating */ + unsigned char defend = 1; // tbd + + if(defend) { + if(netif->autoip->lastconflict > 0) { + /* retreat, there was a conflicting ARP in the last + * DEFEND_INTERVAL seconds + */ + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); + + /* TODO: close all TCP sessions */ + autoip_start(netif); + } else { + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); + autoip_arp_announce(netif); + netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_FINE_TIMER_TICK_PER_SECOND; + } + } else { + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("autoip_handle_arp_conflict(): we do not defend, retreating\n")); + /* TODO: close all TCP sessions */ + autoip_start(netif); + } +} + +/** + * TODO: Add comment + */ +static void +autoip_create_rand_addr(struct ip_addr *RandomIPAddr) +{ + /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 + * compliant to RFC 3927 Section 2.1 + * We have 254 * 256 possibilities + */ + + RandomIPAddr->addr = htonl((u32_t)(rand() % (0xA9FEFEFF + 1 - 0xA9FE0100) + 0xA9FE0100)); +} + +/** + * TODO: Add comment + */ +static err_t +autoip_arp_announce(struct netif *netif) +{ + struct eth_addr eth_addr_bc, eth_addr_zero; + u8_t k = netif->hwaddr_len; + + while(k > 0) { + k--; + eth_addr_bc.addr[k] = 0xFF; + eth_addr_zero.addr[k] = 0x00; + } + + return etharp_raw( netif, + (struct eth_addr *)netif->hwaddr, + ð_addr_bc, + (struct eth_addr *)netif->hwaddr, + &netif->autoip->llipaddr, + ð_addr_zero, + &netif->autoip->llipaddr, + ARP_REQUEST + ); +} + +/** + * TODO: Add comment + */ +static err_t +autoip_bind(struct netif *netif) +{ + struct autoip *autoip = netif->autoip; + struct ip_addr sn_mask, gw_addr; + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | 3, ("autoip_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + IP4_ADDR(&sn_mask, 255, 255, 0, 0); + IP4_ADDR(&gw_addr, 0, 0, 0, 0); + + netif_set_ipaddr(netif, &autoip->llipaddr); + netif_set_netmask(netif, &sn_mask); + netif_set_gw(netif, &gw_addr); + + /* bring the interface up */ + netif_set_up(netif); + + return ERR_OK; +} + +/** + * TODO: Add comment + */ +err_t +autoip_start(struct netif *netif) +{ + struct autoip *autoip = netif->autoip; + err_t result = ERR_OK; + + if(netif_is_up(netif)) { + netif_set_down(netif); + } + + /* Set IP-Address, Netmask and Gateway to 0 to make sure that + * ARP Packets are formed correctly + */ + netif->ip_addr.addr = 0; + netif->netmask.addr = 0; + netif->gw.addr = 0; + + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | DBG_STATE, ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + if(autoip == NULL) { + /* no AutoIP client attached yet? */ + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE, ("autoip_start(): starting new AUTOIP client\n")); + autoip = mem_malloc(sizeof(struct autoip)); + if(autoip == NULL) { + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE, ("autoip_start(): could not allocate autoip\n")); + return ERR_MEM; + } + memset( autoip, 0, sizeof(struct autoip)); + /* store this AutoIP client in the netif */ + netif->autoip = autoip; + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE, ("autoip_start(): allocated autoip")); + } else { + autoip->state = AUTOIP_STATE_OFF; + autoip->ttw = 0; + autoip->sent_num = 0; + memset(&autoip->llipaddr, 0, sizeof(struct ip_addr)); + autoip->lastconflict = 0; + } + + autoip_create_rand_addr(&(autoip->llipaddr)); + autoip->tried_llipaddr++; + autoip->state = AUTOIP_STATE_PROBING; + autoip->sent_num = 0; + + /* time to wait to first probe, this is randomly + * choosen out of 0 to PROBE_WAIT seconds. + * compliant to RFC 3927 Section 2.2.1 + */ + autoip->ttw = (rand() % (PROBE_WAIT * AUTOIP_FINE_TIMER_TICK_PER_SECOND)); + + /* + * if we tried more then MAX_CONFLICTS we must limit our rate for + * accquiring and probing address + * compliant to RFC 3927 Section 2.2.1 + */ + + if(autoip->tried_llipaddr > MAX_CONFLICTS) { + autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_FINE_TIMER_TICK_PER_SECOND; + } + + return result; +} + +/** + * TODO: Add comment + */ +err_t +autoip_stop(struct netif *netif) +{ + netif->autoip->state = AUTOIP_STATE_OFF; + netif_set_down(netif); + return ERR_OK; +} + +/** + * TODO: Add comment + */ +void +autoip_fine_tmr() +{ + struct netif *netif = netif_list; + /* loop through netif's */ + while (netif != NULL) { + /* only act on AutoIP configured interfaces */ + if (netif->autoip != NULL) { + if(netif->autoip->lastconflict > 0) { + netif->autoip->lastconflict--; + } + + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | 3, ("autoip_fine_tmr()AutoIP-Sate: %d\n", netif->autoip->state)); + + switch(netif->autoip->state) { + case AUTOIP_STATE_PROBING: + if(netif->autoip->ttw > 0) { + netif->autoip->ttw--; + } else { + if(netif->autoip->sent_num == PROBE_NUM) { + netif->autoip->state = AUTOIP_STATE_ANNOUNCING; + netif->autoip->sent_num = 0; + netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_FINE_TIMER_TICK_PER_SECOND; + } else { + etharp_request(netif, &(netif->autoip->llipaddr)); + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | 3, ("autoip_fine_tmr() PROBING Sent Probe\n")); + netif->autoip->sent_num++; + /* calculate time to wait to next probe */ + netif->autoip->ttw = (rand() % ((PROBE_MAX - PROBE_MIN) * AUTOIP_FINE_TIMER_TICK_PER_SECOND) ) + PROBE_MIN * AUTOIP_FINE_TIMER_TICK_PER_SECOND; + } + } + break; + + case AUTOIP_STATE_ANNOUNCING: + if(netif->autoip->ttw > 0) { + netif->autoip->ttw--; + } else { + if(netif->autoip->sent_num == 0) { + /* We are here the first time, so we waited ANNOUNCE_WAIT seconds + * Now we can bind to an IP address and use it + */ + autoip_bind(netif); + } + + if(netif->autoip->sent_num == ANNOUNCE_NUM) { + netif->autoip->state = AUTOIP_STATE_BOUND; + netif->autoip->sent_num = 0; + netif->autoip->ttw = 0; + } else { + autoip_arp_announce(netif); + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | 3, ("autoip_fine_tmr() ANNOUNCING Sent Announce\n")); + netif->autoip->sent_num++; + netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_FINE_TIMER_TICK_PER_SECOND; + } + } + break; + } + } + /* proceed to next network interface */ + netif = netif->next; + } +} + +/** + * TODO: Add comment + */ +void +autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) +{ + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | 3, ("autoip_arp_reply()\n")); + if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { + /* when ip.src == llipaddr && hw.src != netif->hwaddr + * + * when probing ip.dst == llipaddr && hw.src != netif->hwaddr + * we have a conflict and must solve it + */ + struct ip_addr sipaddr, dipaddr; + struct eth_addr netifaddr; + netifaddr.addr[0] = netif->hwaddr[0]; + netifaddr.addr[1] = netif->hwaddr[1]; + netifaddr.addr[2] = netif->hwaddr[2]; + netifaddr.addr[3] = netif->hwaddr[3]; + netifaddr.addr[4] = netif->hwaddr[4]; + netifaddr.addr[5] = netif->hwaddr[5]; + + /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without + * structure packing (not using structure copy which breaks strict-aliasing rules). + */ + memcpy(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); + memcpy(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); + + if (netif->autoip->state == AUTOIP_STATE_PROBING || (netif->autoip->state == AUTOIP_STATE_ANNOUNCING && netif->autoip->sent_num == 0)) { + /* RFC 3927 Section 2.2.1: + * from beginning to after ANNOUNCE_WAIT + * seconds we have a conflict if + * ip.src == llipaddr OR + * ip.dst == llipaddr && hw.src != own hwaddr + */ + if((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) || (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("autoip_arp_reply(): Probe Conflict detected\n")); + autoip_start(netif); + } + } else { + /* RFC 3927 Section 2.5: + * in any state we have a conflict if + * ip.src == llipaddr && hw.src != own hwaddr + */ + if(ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) && !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { + LWIP_DEBUGF(AUTOIP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); + autoip_handle_arp_conflict(netif); + } + } + } +} + +#endif /* LWIP_AUTOIP */ diff --git a/src/core/netif.c b/src/core/netif.c index 26e0fa03..6c87f2c0 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -92,7 +92,11 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, #if LWIP_DHCP /* netif not under DHCP control by default */ netif->dhcp = NULL; -#endif +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP + /* netif not under AutoIP control by default */ + netif->autoip = NULL; +#endif /* LWIP_AUTOIP */ #if LWIP_NETIF_CALLBACK netif->status_callback = NULL; #endif /* LWIP_NETIF_CALLBACK */ diff --git a/src/include/ipv4/lwip/autoip.h b/src/include/ipv4/lwip/autoip.h new file mode 100644 index 00000000..6b17d07c --- /dev/null +++ b/src/include/ipv4/lwip/autoip.h @@ -0,0 +1,100 @@ +/** + * @file + * + * AutoIP Automatic LinkLocal IP Configuration + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + * + * Please coordinate changes and requests with Dominik Spies + * + */ + +#ifndef __LWIP_AUTOIP_H__ +#define __LWIP_AUTOIP_H__ + +#include "lwip/opt.h" +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "netif/etharp.h" + +/* AutoIP Timing */ +#define AUTOIP_FINE_TIMER_MSECS 100 +#define AUTOIP_FINE_TIMER_TICK_PER_SECOND 1000 / AUTOIP_FINE_TIMER_MSECS + +/* RFC 3927 Constants */ +#define PROBE_WAIT 1 /* second (initial random delay) */ +#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ +#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ +#define PROBE_NUM 3 /* (number of probe packets) */ +#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ +#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ +#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ +#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ +#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ +#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ + +/* AutoIP client states */ +#define AUTOIP_STATE_OFF 0 +#define AUTOIP_STATE_PROBING 1 +#define AUTOIP_STATE_ANNOUNCING 2 +#define AUTOIP_STATE_BOUND 3 + +struct autoip +{ + u8_t state; /* current AutoIP state machine state */ + u8_t sent_num; /* sent number of probes or announces, dependent on state */ + u16_t ttw; /* ticks to wait, tick is AUTOIP_FINE_TIMER_MSECS long */ + u8_t lastconflict; /* ticks until a conflict can be solved by defending */ + u8_t tried_llipaddr; /* total number of probed/used Link Local IP-Addresses */ + struct ip_addr llipaddr; /* the currently selected, probed, announced or used LL IP-Address */ +}; + + +/** Init srand, has to be called before entering mainloop */ +void autoip_init(void); + +/** Start AutoIP client */ +err_t autoip_start(struct netif *netif); + +/** Stop AutoIP client */ +err_t autoip_stop(struct netif *netif); + +/** Handles every incoming ARP Packet, called by etharp_arp_input */ +void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); + +/** Has to be called in loop every AUTOIP_FINE_TIMER_MSECS milliseconds */ +void autoip_fine_tmr(void); + +#endif /* __LWIP_AUTOIP_H__ */ diff --git a/src/include/lwip/dhcp.h b/src/include/lwip/dhcp.h index 6b6d8d30..6106fc9e 100644 --- a/src/include/lwip/dhcp.h +++ b/src/include/lwip/dhcp.h @@ -57,6 +57,9 @@ struct dhcp /** Patch #1308 * TODO: See dhcp.c "TODO"s */ +#if LWIP_DHCP_AUTOIP_COOP + u8_t autoip_coop_state; +#endif #if 0 struct ip_addr offered_si_addr; u8_t *boot_file_name; @@ -165,6 +168,10 @@ void dhcp_fine_tmr(void); /** not yet implemented #define DHCP_RELEASING 11 */ #define DHCP_BACKING_OFF 12 #define DHCP_OFF 13 + +/** AUTOIP cooperatation flags */ +#define DHCP_AUTOIP_COOP_STATE_OFF 0 +#define DHCP_AUTOIP_COOP_STATE_ON 1 #define DHCP_BOOTREQUEST 1 #define DHCP_BOOTREPLY 2 diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index 184515fa..b3a13868 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -43,6 +43,9 @@ #if LWIP_DHCP # include "lwip/dhcp.h" #endif +#if LWIP_AUTOIP +# include "lwip/autoip.h" +#endif #ifdef __cplusplus extern "C" { @@ -111,6 +114,10 @@ struct netif { /** the DHCP client state information for this netif */ struct dhcp *dhcp; #endif /* LWIP_DHCP */ +#if LWIP_AUTOIP + /** the AutoIP client state information for this netif */ + struct autoip *autoip; +#endif #if LWIP_NETIF_HOSTNAME /* the hostname for this netif, NULL is a valid value */ char* hostname; diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index bc5f0fed..43f1ac6b 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -309,6 +309,15 @@ a lot of data that needs to be copied, this should be set high. */ #define DHCP_DOES_ARP_CHECK 1 #endif +/* ---------- AUTOIP options -------- */ +#ifndef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif + +#ifndef LWIP_DHCP_AUTOIP_COOP +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + /* ---------- SNMP options ---------- */ /** @note UDP must be available for SNMP transport */ #ifndef LWIP_SNMP @@ -803,23 +812,27 @@ a lot of data that needs to be copied, this should be set high. */ #define TCPIP_DEBUG LWIP_DBG_OFF #endif -#ifndef PPP_DEBUG +#ifndef PPP_DEBUG #define PPP_DEBUG LWIP_DBG_OFF #endif -#ifndef SLIP_DEBUG +#ifndef SLIP_DEBUG #define SLIP_DEBUG LWIP_DBG_OFF #endif -#ifndef DHCP_DEBUG +#ifndef DHCP_DEBUG #define DHCP_DEBUG LWIP_DBG_OFF #endif -#ifndef SNMP_MSG_DEBUG +#ifndef AUTOIP_DEBUG +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +#ifndef SNMP_MSG_DEBUG #define SNMP_MSG_DEBUG LWIP_DBG_OFF #endif -#ifndef SNMP_MIB_DEBUG +#ifndef SNMP_MIB_DEBUG #define SNMP_MIB_DEBUG LWIP_DBG_OFF #endif diff --git a/src/include/netif/etharp.h b/src/include/netif/etharp.h index 314715a2..f9da367d 100644 --- a/src/include/netif/etharp.h +++ b/src/include/netif/etharp.h @@ -118,6 +118,10 @@ PACK_STRUCT_END #define ETHTYPE_ARP 0x0806 #define ETHTYPE_IP 0x0800 +/** ARP message types */ +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + #if ARP_QUEUEING /** struct for queueing outgoing packets for unknown address * defined here to be accessed by memp.h @@ -139,6 +143,12 @@ err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr) err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q); err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr); +#if LWIP_AUTOIP +err_t etharp_raw(struct netif *netif, struct eth_addr *ethsrc_addr, struct eth_addr *ethdst_addr, struct eth_addr *hwsrc_addr, struct ip_addr *ipsrc_addr, struct eth_addr *hwdst_addr, struct ip_addr *ipdst_addr, unsigned short int OpCode); +#endif /* LWIP_AUTOIP */ + +#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, 6) == 0) + #ifdef __cplusplus } #endif diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 69c22bfe..0b695cca 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -54,7 +54,11 @@ /* ARP needs to inform DHCP of any ARP replies? */ #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) # include "lwip/dhcp.h" -#endif +#endif /* LWIP_DHCP && DHCP_DOES_ARP_CHECK */ +/* ARP needs to inform AUTOIP of any ARP replies? */ +#if (LWIP_AUTOIP) +# include "lwip/autoip.h" +#endif /* LWIP_AUTOIP */ /** the time an ARP entry stays valid after its last update, * (240 * 5) seconds = 20 minutes. @@ -70,10 +74,6 @@ #define HWTYPE_ETHERNET 1 -/** ARP message types */ -#define ARP_REQUEST 1 -#define ARP_REPLY 2 - #define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8) #define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff) @@ -568,7 +568,15 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) } hdr = p->payload; - + +#if LWIP_AUTOIP + /* We have to check if a host already has configured our random + * created link local address and continously check if there is + * a host with this IP-address so we can detect collisions + * */ + autoip_arp_reply(netif, hdr); +#endif /* LWIP_AUTOIP */ + /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without * structure packing (not using structure copy which breaks strict-aliasing rules). */ SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); @@ -910,6 +918,92 @@ etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) return result; } +#if LWIP_AUTOIP +/** + * Send an ARP request packet asking for ipaddr. + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address for which to ask + * @return ERR_OK if the request has been sent + * any other err_t on failure + */ +err_t +etharp_request(struct netif *netif, struct ip_addr *ipaddr) +{ + struct eth_addr eth_addr_bc, eth_addr_zero; + u8_t k = netif->hwaddr_len; + while(k > 0) { + k--; + eth_addr_bc.addr[k] = 0xFF; + eth_addr_zero.addr[k] = 0x00; + } + + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n")); + return etharp_raw( netif, + (struct eth_addr *)netif->hwaddr, + ð_addr_bc, + (struct eth_addr *)netif->hwaddr, + &netif->ip_addr, + ð_addr_zero, + ipaddr, + ARP_REQUEST + ); +} + +err_t +etharp_raw(struct netif *netif, struct eth_addr *ethsrc_addr, struct eth_addr *ethdst_addr, struct eth_addr *hwsrc_addr, struct ip_addr *ipsrc_addr, struct eth_addr *hwdst_addr, struct ip_addr *ipdst_addr, unsigned short int OpCode) +{ + struct pbuf *p; + err_t result = ERR_OK; + u8_t k; /* ARP entry index */ + + /* allocate a pbuf for the outgoing ARP request packet */ + p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); + /* could allocate a pbuf for an ARP request? */ + if(p != NULL) { + struct etharp_hdr *hdr = p->payload; + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); + hdr->opcode = htons(OpCode); + k = netif->hwaddr_len; + + /* Write the ARP MAC-Addresses */ + while(k > 0) { + k--; + hdr->shwaddr.addr[k] = hwsrc_addr->addr[k]; + hdr->dhwaddr.addr[k] = hwdst_addr->addr[k]; + } + hdr->sipaddr = *(struct ip_addr2 *)ipsrc_addr; + hdr->dipaddr = *(struct ip_addr2 *)ipdst_addr; + + hdr->hwtype = htons(HWTYPE_ETHERNET); + ARPH_HWLEN_SET(hdr, netif->hwaddr_len); + + hdr->proto = htons(ETHTYPE_IP); + ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); + k = netif->hwaddr_len; + + /* Write the Ethernet MAC-Addresses */ + while(k > 0) { + k--; + hdr->ethhdr.dest.addr[k] = ethdst_addr->addr[k]; + hdr->ethhdr.src.addr[k] = ethsrc_addr->addr[k]; + } + + hdr->ethhdr.type = htons(ETHTYPE_ARP); + /* send ARP query */ + result = netif->linkoutput(netif, p); + /* free ARP query packet */ + pbuf_free(p); + p = NULL; + /* could not allocate pbuf for ARP request */ + } else { + result = ERR_MEM; + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_raw: could not allocate pbuf for ARP request.\n")); + } + + return result; +} +#else /** * Send an ARP request packet asking for ipaddr. * @@ -969,3 +1063,4 @@ etharp_request(struct netif *netif, struct ip_addr *ipaddr) } return result; } +#endif /* LWIP_AUTOIP */