Version of http://mbed.org/cookbook/NetServicesTribute with setting set the same for LPC2368

Dependents:   UDPSocketExample 24LCxx_I2CApp WeatherPlatform_pachube HvZServerLib ... more

Files at this revision

API Documentation at this revision

Comitter:
simon
Date:
Tue Nov 23 14:15:36 2010 +0000
Commit message:
Experimental version for testing UDP

Changed in this revision

api/DNSRequest.cpp Show annotated file Show diff for this revision Revisions of this file
api/DNSRequest.h Show annotated file Show diff for this revision Revisions of this file
api/TCPSocket.cpp Show annotated file Show diff for this revision Revisions of this file
api/TCPSocket.h Show annotated file Show diff for this revision Revisions of this file
api/UDPSocket.cpp Show annotated file Show diff for this revision Revisions of this file
api/UDPSocket.h Show annotated file Show diff for this revision Revisions of this file
core/host.h Show annotated file Show diff for this revision Revisions of this file
core/ipaddr.cpp Show annotated file Show diff for this revision Revisions of this file
core/ipaddr.h Show annotated file Show diff for this revision Revisions of this file
core/net.cpp Show annotated file Show diff for this revision Revisions of this file
core/net.h Show annotated file Show diff for this revision Revisions of this file
core/netservice.cpp Show annotated file Show diff for this revision Revisions of this file
core/netservice.h Show annotated file Show diff for this revision Revisions of this file
dbg/dbg.cpp Show annotated file Show diff for this revision Revisions of this file
dbg/dbg.h Show annotated file Show diff for this revision Revisions of this file
drv/at/ATIf.cpp Show annotated file Show diff for this revision Revisions of this file
drv/at/ATIf.h Show annotated file Show diff for this revision Revisions of this file
drv/eth/eth_drv.cpp Show annotated file Show diff for this revision Revisions of this file
drv/eth/eth_drv.h Show annotated file Show diff for this revision Revisions of this file
drv/gprs/GPRSModem.cpp Show annotated file Show diff for this revision Revisions of this file
drv/gprs/GPRSModem.h Show annotated file Show diff for this revision Revisions of this file
drv/gprsmodule/TelitModule.cpp Show annotated file Show diff for this revision Revisions of this file
drv/gprsmodule/TelitModule.h Show annotated file Show diff for this revision Revisions of this file
drv/serial/buf/SerialBuf.cpp Show annotated file Show diff for this revision Revisions of this file
drv/serial/buf/SerialBuf.h Show annotated file Show diff for this revision Revisions of this file
drv/serial/lwip/sio.cpp Show annotated file Show diff for this revision Revisions of this file
drv/serial/lwip/sioMgr.cpp Show annotated file Show diff for this revision Revisions of this file
drv/serial/lwip/sioMgr.h Show annotated file Show diff for this revision Revisions of this file
drv/serial/usb/UsbSerial.cpp Show annotated file Show diff for this revision Revisions of this file
drv/serial/usb/UsbSerial.h Show annotated file Show diff for this revision Revisions of this file
drv/umtsstick/UMTSStick.cpp Show annotated file Show diff for this revision Revisions of this file
drv/umtsstick/UMTSStick.h Show annotated file Show diff for this revision Revisions of this file
drv/umtsstick/UMTSStickData.cpp Show annotated file Show diff for this revision Revisions of this file
drv/usb/UsbDevice.cpp Show annotated file Show diff for this revision Revisions of this file
drv/usb/UsbDevice.h Show annotated file Show diff for this revision Revisions of this file
drv/usb/UsbEndpoint.cpp Show annotated file Show diff for this revision Revisions of this file
drv/usb/UsbEndpoint.h Show annotated file Show diff for this revision Revisions of this file
drv/usb/UsbHostMgr.cpp Show annotated file Show diff for this revision Revisions of this file
drv/usb/UsbHostMgr.h Show annotated file Show diff for this revision Revisions of this file
drv/usb/UsbInc.h Show annotated file Show diff for this revision Revisions of this file
drv/usb/usb_mem.c Show annotated file Show diff for this revision Revisions of this file
drv/usb/usb_mem.h Show annotated file Show diff for this revision Revisions of this file
if/eth/EthernetNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
if/eth/EthernetNetIf.h Show annotated file Show diff for this revision Revisions of this file
if/gprsmodule/GPRSModuleNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
if/gprsmodule/GPRSModuleNetIf.h Show annotated file Show diff for this revision Revisions of this file
if/gprsmodule/HuaweiGTM900NetIf.cpp Show annotated file Show diff for this revision Revisions of this file
if/gprsmodule/HuaweiGTM900NetIf.h Show annotated file Show diff for this revision Revisions of this file
if/gprsmodule/TelitModuleNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
if/gprsmodule/TelitModuleNetIf.h Show annotated file Show diff for this revision Revisions of this file
if/lwip/LwipNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
if/lwip/LwipNetIf.h Show annotated file Show diff for this revision Revisions of this file
if/lwip/lwipNetDnsRequest.cpp Show annotated file Show diff for this revision Revisions of this file
if/lwip/lwipNetDnsRequest.h Show annotated file Show diff for this revision Revisions of this file
if/lwip/lwipNetTcpSocket.cpp Show annotated file Show diff for this revision Revisions of this file
if/lwip/lwipNetTcpSocket.h Show annotated file Show diff for this revision Revisions of this file
if/lwip/lwipNetUdpSocket.cpp Show annotated file Show diff for this revision Revisions of this file
if/lwip/lwipNetUdpSocket.h Show annotated file Show diff for this revision Revisions of this file
if/net/netdnsrequest.cpp Show annotated file Show diff for this revision Revisions of this file
if/net/netdnsrequest.h Show annotated file Show diff for this revision Revisions of this file
if/net/netif.cpp Show annotated file Show diff for this revision Revisions of this file
if/net/netif.h Show annotated file Show diff for this revision Revisions of this file
if/net/nettcpsocket.cpp Show annotated file Show diff for this revision Revisions of this file
if/net/nettcpsocket.h Show annotated file Show diff for this revision Revisions of this file
if/net/netudpsocket.cpp Show annotated file Show diff for this revision Revisions of this file
if/net/netudpsocket.h Show annotated file Show diff for this revision Revisions of this file
if/ppp/PPPNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
if/ppp/PPPNetIf.h Show annotated file Show diff for this revision Revisions of this file
if/umtsstick/UMTSStickNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
if/umtsstick/UMTSStickNetIf.h Show annotated file Show diff for this revision Revisions of this file
lwip/arch/cc.h Show annotated file Show diff for this revision Revisions of this file
lwip/arch/perf.h Show annotated file Show diff for this revision Revisions of this file
lwip/arch/sys_arch.cpp Show annotated file Show diff for this revision Revisions of this file
lwip/arch/sys_arch.h Show annotated file Show diff for this revision Revisions of this file
lwip/core/def.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/dhcp.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/dns.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/init.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/ipv4/autoip.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/ipv4/icmp.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/ipv4/igmp.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/ipv4/inet.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/ipv4/inet_chksum.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/ipv4/ip.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/ipv4/ip_addr.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/ipv4/ip_frag.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/mem.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/memp.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/netif.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/pbuf.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/raw.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/snmp/asn1_dec.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/snmp/asn1_enc.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/snmp/mib2.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/snmp/mib_structs.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/snmp/msg_in.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/snmp/msg_out.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/stats.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/sys.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/tcp.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/tcp_in.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/tcp_out.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/timers.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/udp.c Show annotated file Show diff for this revision Revisions of this file
lwip/include/ipv4/lwip/autoip.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/ipv4/lwip/icmp.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/ipv4/lwip/igmp.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/ipv4/lwip/inet.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/ipv4/lwip/inet_chksum.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/ipv4/lwip/ip.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/ipv4/lwip/ip_addr.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/ipv4/lwip/ip_frag.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/api.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/api_msg.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/arch.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/debug.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/def.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/dhcp.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/dns.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/err.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/init.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/mem.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/memp.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/memp_std.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/netbuf.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/netdb.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/netif.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/netifapi.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/opt.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/pbuf.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/raw.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/sio.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/snmp.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/snmp_asn1.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/snmp_msg.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/snmp_structs.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/sockets.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/stats.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/sys.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/tcp.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/tcp_impl.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/tcpip.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/timers.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/udp.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/netif/etharp.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/netif/ppp_oe.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/netif/slipif.h Show annotated file Show diff for this revision Revisions of this file
lwip/lwipopts.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/etharp.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ethernetif.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/auth.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/auth.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/chap.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/chap.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/chpms.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/chpms.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/fsm.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/fsm.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/ipcp.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/ipcp.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/lcp.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/lcp.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/magic.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/magic.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/md5.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/md5.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/pap.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/pap.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/ppp.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/ppp.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/ppp_oe.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/pppdebug.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/randm.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/randm.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/vj.c Show annotated file Show diff for this revision Revisions of this file
lwip/netif/ppp/vj.h Show annotated file Show diff for this revision Revisions of this file
lwip/netif/slipif.c Show annotated file Show diff for this revision Revisions of this file
netCfg.h Show annotated file Show diff for this revision Revisions of this file
services/email/emailMessage.cpp Show annotated file Show diff for this revision Revisions of this file
services/email/emailMessage.h Show annotated file Show diff for this revision Revisions of this file
services/email/smtp/SMTPClient.cpp Show annotated file Show diff for this revision Revisions of this file
services/email/smtp/SMTPClient.h Show annotated file Show diff for this revision Revisions of this file
services/http/client/HTTPClient.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/client/HTTPClient.h Show annotated file Show diff for this revision Revisions of this file
services/http/client/HTTPData.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/client/HTTPData.h Show annotated file Show diff for this revision Revisions of this file
services/http/client/data/HTTPFile.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/client/data/HTTPFile.h Show annotated file Show diff for this revision Revisions of this file
services/http/client/data/HTTPMap.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/client/data/HTTPMap.h Show annotated file Show diff for this revision Revisions of this file
services/http/client/data/HTTPStream.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/client/data/HTTPStream.h Show annotated file Show diff for this revision Revisions of this file
services/http/client/data/HTTPText.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/client/data/HTTPText.h Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPRequestDispatcher.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPRequestDispatcher.h Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPRequestHandler.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPRequestHandler.h Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPServer.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPServer.h Show annotated file Show diff for this revision Revisions of this file
services/http/server/impl/FSHandler.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/server/impl/FSHandler.h Show annotated file Show diff for this revision Revisions of this file
services/http/server/impl/RPCHandler.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/server/impl/RPCHandler.h Show annotated file Show diff for this revision Revisions of this file
services/http/server/impl/SimpleHandler.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/server/impl/SimpleHandler.h Show annotated file Show diff for this revision Revisions of this file
services/http/util/base64.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/util/base64.h Show annotated file Show diff for this revision Revisions of this file
services/http/util/url.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/util/url.h Show annotated file Show diff for this revision Revisions of this file
services/http/util/urlencode.cpp Show annotated file Show diff for this revision Revisions of this file
services/mysql/MySQLClient.cpp Show annotated file Show diff for this revision Revisions of this file
services/mysql/MySQLClient.h Show annotated file Show diff for this revision Revisions of this file
services/mysql/mycrypt.c Show annotated file Show diff for this revision Revisions of this file
services/mysql/mycrypt.h Show annotated file Show diff for this revision Revisions of this file
services/mysql/sha1.c Show annotated file Show diff for this revision Revisions of this file
services/mysql/sha1.h Show annotated file Show diff for this revision Revisions of this file
services/mysql/sha1config.h Show annotated file Show diff for this revision Revisions of this file
services/ntp/NTPClient.cpp Show annotated file Show diff for this revision Revisions of this file
services/ntp/NTPClient.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 350011bf8be7 api/DNSRequest.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/api/DNSRequest.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,115 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "DNSRequest.h"
+#include "if/net/netdnsrequest.h"
+
+DNSRequest::DNSRequest() : m_pNetDnsRequest(NULL), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL)
+{
+
+}
+
+DNSRequest::~DNSRequest()
+{
+  close();
+}
+  
+DNSRequestErr DNSRequest::resolve(const char* hostname)
+{
+  if(!m_pNetDnsRequest)
+  {
+    m_pNetDnsRequest = Net::dnsRequest(hostname);
+    if(!m_pNetDnsRequest)
+    {
+      return DNS_IF; //Interface did not return a NetDnsRequest (usually because a default interface does not exist)
+    }
+    m_pNetDnsRequest->setOnReply(this, &DNSRequest::onNetDnsReply);
+    return DNS_OK;
+  }
+  else
+  {
+    return DNS_INUSE; //The previous req has not completed
+  }
+}
+
+DNSRequestErr DNSRequest::resolve(Host* pHost)
+{
+  if(!m_pNetDnsRequest)
+  {
+    m_pNetDnsRequest = Net::dnsRequest(pHost);
+    if(!m_pNetDnsRequest)
+    {
+      return DNS_IF; //Interface did not return a NetDnsRequest (usually because a default interface does not exist)
+    }
+    m_pNetDnsRequest->setOnReply(this, &DNSRequest::onNetDnsReply);
+    return DNS_OK;
+  }
+  else
+  {
+    return DNS_INUSE; //The previous req has not completed
+  }
+}
+
+//Callbacks
+void DNSRequest::setOnReply( void (*pMethod)(DNSReply) )
+{
+  m_pCb = pMethod;
+}
+
+#if 0 //For doc only
+template<class T> 
+void DNSRequest::setOnReply( T* pItem, void (T::*pMethod)(DNSReply) )
+{
+  m_pCbItem = (CDummy*) pItem;
+  m_pCbMeth = (void (CDummy::*)(DNSReply)) pMethod;
+}
+#endif
+
+DNSRequestErr DNSRequest::getResult(IpAddr* pIp)
+{
+  if(!m_pNetDnsRequest)
+  {
+    return DNS_SETUP;
+  }
+  m_pNetDnsRequest->getResult(pIp);
+  return DNS_OK;
+}
+  
+DNSRequestErr DNSRequest::close()
+{
+  if(!m_pNetDnsRequest)
+  {
+    return DNS_SETUP;
+  }
+  m_pNetDnsRequest->close();
+  m_pNetDnsRequest = NULL;
+  return DNS_OK;
+}
+  
+void DNSRequest::onNetDnsReply(NetDnsReply r)
+{
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)((DNSReply) r);
+  else if(m_pCb)
+    m_pCb((DNSReply) r);
+}
diff -r 000000000000 -r 350011bf8be7 api/DNSRequest.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/api/DNSRequest.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,131 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/** \file
+DNS Request header file
+*/
+
+#ifndef DNSREQUEST_H
+#define DNSREQUEST_H
+
+#include "core/net.h"
+#include "core/ipaddr.h"
+#include "core/host.h"
+//Essentially it is a safe interface to NetDnsRequest
+
+///DNS Request error codes
+enum DNSRequestErr
+{
+  __DNS_MIN = -0xFFFF,
+  DNS_SETUP, ///<DNSRequest not properly configured
+  DNS_IF, ///<Interface has problems, does not exist or is not initialized
+  DNS_MEM, ///<Not enough mem
+  DNS_INUSE, ///<Interface / Port is in use
+  DNS_PROCESSING, ///<Request has not completed
+//...
+  DNS_OK = 0 ///<Success
+};
+
+///DNS Request Result Events
+enum DNSReply
+{
+  DNS_PRTCL,
+  DNS_NOTFOUND, ///Hostname is unknown
+  DNS_ERROR, ///Problem with DNS Service
+  //...
+  DNS_FOUND,
+};
+
+class NetDnsRequest;
+enum NetDnsReply;
+
+///This is a simple DNS Request class
+/**
+  This class exposes an API to deal with DNS Requests
+*/
+class DNSRequest
+{
+public:
+  ///Creates a new request
+  DNSRequest();
+  
+  ///Terminates and closes request
+  ~DNSRequest();
+  
+  ///Resolves an hostname
+  /**
+  @param hostname : hostname to resolve
+  */
+  DNSRequestErr resolve(const char* hostname);
+  
+  ///Resolves an hostname
+  /**
+  @param host : hostname to resolve, the result will be stored in the IpAddr field of this object
+  */
+  DNSRequestErr resolve(Host* pHost);
+  
+  ///Setups callback
+  /**
+  The callback function will be called on result.
+  @param pMethod : callback function
+  */  
+  void setOnReply( void (*pMethod)(DNSReply) );
+  
+  class CDummy;
+  ///Setups callback
+  /**
+  The callback function will be called on result.
+  @param pItem : instance of class on which to execute the callback method
+  @param pMethod : callback method
+  */
+  template<class T> 
+  void setOnReply( T* pItem, void (T::*pMethod)(DNSReply) )
+  {
+    m_pCbItem = (CDummy*) pItem;
+    m_pCbMeth = (void (CDummy::*)(DNSReply)) pMethod;
+  }
+  
+  ///Gets IP address once it has been resolved
+  /**
+  @param pIp : pointer to an IpAddr instance in which to store the resolved IP address
+  */
+  DNSRequestErr getResult(IpAddr* pIp);
+  
+  ///Closes DNS Request before completion
+  DNSRequestErr close();
+  
+protected:
+  void onNetDnsReply(NetDnsReply r);
+  DNSRequestErr checkInst();
+
+private:
+  NetDnsRequest* m_pNetDnsRequest;
+  
+  CDummy* m_pCbItem;
+  void (CDummy::*m_pCbMeth)(DNSReply);
+  
+  void (*m_pCb)(DNSReply);
+
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 api/TCPSocket.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/api/TCPSocket.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,147 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "TCPSocket.h"
+#include "if/net/nettcpsocket.h"
+
+TCPSocket::TCPSocket() : m_pNetTcpSocket(NULL), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL)
+{
+
+}
+
+TCPSocket::TCPSocket(NetTcpSocket* pNetTcpSocket) : m_pNetTcpSocket(pNetTcpSocket), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL)
+{
+  m_pNetTcpSocket->setOnEvent(this, &TCPSocket::onNetTcpSocketEvent);
+}
+
+TCPSocket::~TCPSocket() //close()
+{
+  close();
+}
+  
+TCPSocketErr TCPSocket::bind(const Host& me)
+{
+  TCPSocketErr tcpSocketErr = checkInst();
+  if(tcpSocketErr)
+    return tcpSocketErr;
+  return (TCPSocketErr) m_pNetTcpSocket->bind(me); 
+}
+
+TCPSocketErr TCPSocket::listen()
+{
+  TCPSocketErr tcpSocketErr = checkInst();
+  if(tcpSocketErr)
+    return tcpSocketErr;
+  return (TCPSocketErr) m_pNetTcpSocket->listen(); 
+}
+
+TCPSocketErr TCPSocket::connect(const Host& host)
+{
+  TCPSocketErr tcpSocketErr = checkInst();
+  if(tcpSocketErr)
+    return tcpSocketErr;
+  return (TCPSocketErr) m_pNetTcpSocket->connect(host); 
+}
+
+TCPSocketErr TCPSocket::accept(Host* pClient, TCPSocket** ppNewTCPSocket)
+{
+  TCPSocketErr tcpSocketErr = checkInst();
+  if(tcpSocketErr)
+    return tcpSocketErr;
+  NetTcpSocket* pNewNetTcpSocket;
+  tcpSocketErr = (TCPSocketErr) m_pNetTcpSocket->accept(pClient, &pNewNetTcpSocket);
+  if(pNewNetTcpSocket)
+    *ppNewTCPSocket = new TCPSocket(pNewNetTcpSocket);
+  return tcpSocketErr;
+}
+  
+int /*if < 0 : TCPSocketErr*/ TCPSocket::send(const char* buf, int len)
+{
+  TCPSocketErr tcpSocketErr = checkInst();
+  if(tcpSocketErr)
+    return tcpSocketErr;
+  return m_pNetTcpSocket->send(buf, len);  
+}
+
+int /*if < 0 : TCPSocketErr*/ TCPSocket::recv(char* buf, int len)
+{
+  TCPSocketErr tcpSocketErr = checkInst();
+  if(tcpSocketErr)
+    return tcpSocketErr;
+  return m_pNetTcpSocket->recv(buf, len);
+}
+
+TCPSocketErr TCPSocket::close()
+{
+  if(!m_pNetTcpSocket)
+    return TCPSOCKET_SETUP;
+  m_pNetTcpSocket->resetOnEvent();
+  TCPSocketErr tcpSocketErr = (TCPSocketErr) m_pNetTcpSocket->close(); //Close (can already be closed)
+  Net::releaseTcpSocket(m_pNetTcpSocket); //And release it so it can be freed when properly removed
+  m_pNetTcpSocket = NULL;
+  return tcpSocketErr;
+}
+
+//Callbacks
+void TCPSocket::setOnEvent( void (*pMethod)(TCPSocketEvent) )
+{
+  m_pCb = pMethod;
+}
+
+#if 0 //For info only
+template<class T> 
+void TCPSocket::setOnEvent( T* pItem, void (T::*pMethod)(TCPSocketEvent) )
+{
+  m_pCbItem = (CDummy*) pItem;
+  m_pCbMeth = (void (CDummy::*)(TCPSocketEvent)) pMethod;
+}
+#endif
+  
+void TCPSocket::resetOnEvent() //Disable callback
+{
+  m_pCb = NULL;
+  m_pCbItem = NULL;
+  m_pCbMeth = NULL;
+}
+
+void TCPSocket::onNetTcpSocketEvent(NetTcpSocketEvent e)
+{
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)((TCPSocketEvent) e);
+  else if(m_pCb)
+    m_pCb((TCPSocketEvent) e);
+}
+
+TCPSocketErr TCPSocket::checkInst()
+{
+  if(!m_pNetTcpSocket)
+  {
+    m_pNetTcpSocket = Net::tcpSocket();
+    if(!m_pNetTcpSocket)
+    {
+      return TCPSOCKET_IF; //Interface did not return a socket (usually because a default interface does not exist)
+    }
+    m_pNetTcpSocket->setOnEvent(this, &TCPSocket::onNetTcpSocketEvent);
+  }
+  return TCPSOCKET_OK;
+}
diff -r 000000000000 -r 350011bf8be7 api/TCPSocket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/api/TCPSocket.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,148 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/** \file
+TCP Socket header file
+*/
+
+#ifndef TCPSOCKET_H
+#define TCPSOCKET_H
+
+#include "core/net.h"
+#include "core/host.h"
+//Essentially it is a safe interface to NetTcpSocket
+
+///TCP Socket error codes
+enum TCPSocketErr
+{
+  __TCPSOCKET_MIN = -0xFFFF,
+  TCPSOCKET_SETUP, ///<TCPSocket not properly configured
+  TCPSOCKET_TIMEOUT, ///<Connection timed out
+  TCPSOCKET_IF, ///<Interface has problems, does not exist or is not initialized
+  TCPSOCKET_MEM, ///<Not enough mem
+  TCPSOCKET_INUSE, ///<Interface / Port is in use
+  TCPSOCKET_EMPTY, ///<Connections queue is empty
+  TCPSOCKET_RST, ///<Connection was reset by remote host
+//...
+  TCPSOCKET_OK = 0 ///<Success
+};
+
+///TCP Socket Events
+enum TCPSocketEvent
+{
+  TCPSOCKET_CONNECTED, ///<Connected to host
+  TCPSOCKET_ACCEPT,  ///<Client is connected, must call accept() to get a new Socket
+  TCPSOCKET_READABLE, ///<Data in buf
+  TCPSOCKET_WRITEABLE, ///<Can write data to buf
+  TCPSOCKET_CONTIMEOUT, ///<Connection timed out
+  TCPSOCKET_CONRST, ///<Connection was reset by remote host
+  TCPSOCKET_CONABRT, ///<Connection was aborted
+  TCPSOCKET_ERROR, ///<Unknown error
+  TCPSOCKET_DISCONNECTED ///<Disconnected
+};
+
+class NetTcpSocket;
+enum NetTcpSocketEvent;
+
+///This is a simple TCP Socket class
+/**
+  This class exposes an API to deal with TCP Sockets
+*/
+class TCPSocket
+{
+public:
+  ///Creates a new socket
+  TCPSocket();
+protected:
+  TCPSocket(NetTcpSocket* pNetTcpSocket);
+public:
+  ///Closes if needed and destroys the socket
+  ~TCPSocket(); //close()
+  
+  ///Binds the socket to (local) host
+  TCPSocketErr bind(const Host& me);
+  
+  ///Starts listening
+  TCPSocketErr listen();
+  
+  ///Connects socket to host
+  TCPSocketErr connect(const Host& host);
+  
+  ///Accepts connection from client and gets connected socket
+  TCPSocketErr accept(Host* pClient, TCPSocket** ppNewTcpSocket);
+  
+  ///Sends data
+  /*
+  @return a negative error code or the number of bytes transmitted
+  */
+  int /*if < 0 : TCPSocketErr*/ send(const char* buf, int len);
+  
+  ///Receives data
+  /*
+  @return a negative error code or the number of bytes received
+  */
+  int /*if < 0 : TCPSocketErr*/ recv(char* buf, int len);
+
+  /* TODO NTH : printf / scanf helpers that call send/recv */
+
+  ///Closes socket
+  TCPSocketErr close();
+
+  //Callbacks
+  ///Setups callback
+  /**
+  @param pMethod : callback function
+  */
+  void setOnEvent( void (*pMethod)(TCPSocketEvent) );
+  
+  class CDummy;
+  ///Setups callback
+  /**
+  @param pItem : instance of class on which to execute the callback method
+  @param pMethod : callback method
+  */
+  template<class T> 
+  void setOnEvent( T* pItem, void (T::*pMethod)(TCPSocketEvent) )
+  {
+    m_pCbItem = (CDummy*) pItem;
+    m_pCbMeth = (void (CDummy::*)(TCPSocketEvent)) pMethod;
+  }
+  
+  ///Disables callback
+  void resetOnEvent(); 
+  
+protected:
+  void onNetTcpSocketEvent(NetTcpSocketEvent e);
+  TCPSocketErr checkInst();
+
+private:
+  NetTcpSocket* m_pNetTcpSocket;
+  
+  CDummy* m_pCbItem;
+  void (CDummy::*m_pCbMeth)(TCPSocketEvent);
+  
+  void (*m_pCb)(TCPSocketEvent);
+  
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 api/UDPSocket.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/api/UDPSocket.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,114 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "UDPSocket.h"
+#include "if/net/netudpsocket.h"
+
+UDPSocket::UDPSocket() : m_pNetUdpSocket(NULL), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL)
+{
+
+}
+
+UDPSocket::~UDPSocket() //close()
+{
+  close();
+}
+  
+UDPSocketErr UDPSocket::bind(const Host& me)
+{
+  UDPSocketErr udpSocketErr = checkInst();
+  if(udpSocketErr)
+    return udpSocketErr;
+  return (UDPSocketErr) m_pNetUdpSocket->bind(me); 
+}
+  
+int /*if < 0 : UDPSocketErr*/ UDPSocket::sendto(const char* buf, int len, Host* pHost)
+{
+  UDPSocketErr udpSocketErr = checkInst();
+  if(udpSocketErr)
+    return udpSocketErr;
+  return m_pNetUdpSocket->sendto(buf, len, pHost);  
+}
+
+int /*if < 0 : UDPSocketErr*/ UDPSocket::recvfrom(char* buf, int len, Host* pHost)
+{
+  UDPSocketErr udpSocketErr = checkInst();
+  if(udpSocketErr)
+    return udpSocketErr;
+  return m_pNetUdpSocket->recvfrom(buf, len, pHost);
+}
+
+UDPSocketErr UDPSocket::close()
+{
+  if(!m_pNetUdpSocket)
+    return UDPSOCKET_SETUP;
+  m_pNetUdpSocket->resetOnEvent();
+  UDPSocketErr udpSocketErr = (UDPSocketErr) m_pNetUdpSocket->close(); //Close (can already be closed)
+  Net::releaseUdpSocket(m_pNetUdpSocket); //And release it so it can be freed when properly removed
+  m_pNetUdpSocket = NULL;
+  return udpSocketErr;
+}
+
+//Callbacks
+void UDPSocket::setOnEvent( void (*pMethod)(UDPSocketEvent) )
+{
+  m_pCb = pMethod;
+}
+
+#if 0 //For info only
+template<class T> 
+void UDPSocket::setOnEvent( T* pItem, void (T::*pMethod)(UDPSocketEvent) )
+{
+  m_pCbItem = (CDummy*) pItem;
+  m_pCbMeth = (void (CDummy::*)(UDPSocketEvent)) pMethod;
+}
+#endif
+  
+void UDPSocket::resetOnEvent() //Disable callback
+{
+  m_pCb = NULL;
+  m_pCbItem = NULL;
+  m_pCbMeth = NULL;
+}
+
+void UDPSocket::onNetUdpSocketEvent(NetUdpSocketEvent e)
+{
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)((UDPSocketEvent) e);
+  else if(m_pCb)
+    m_pCb((UDPSocketEvent) e);
+}
+
+UDPSocketErr UDPSocket::checkInst()
+{
+  if(!m_pNetUdpSocket)
+  {
+    m_pNetUdpSocket = Net::udpSocket();
+    if(!m_pNetUdpSocket)
+    {
+      return UDPSOCKET_IF; //Interface did not return a socket (usually because a default interface does not exist)
+    }
+    m_pNetUdpSocket->setOnEvent(this, &UDPSocket::onNetUdpSocketEvent);
+  }
+  return UDPSOCKET_OK;
+}
diff -r 000000000000 -r 350011bf8be7 api/UDPSocket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/api/UDPSocket.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,128 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/** \file
+UDP Socket header file
+*/
+
+#ifndef UDPSOCKET_H
+#define UDPSOCKET_H
+
+#include "core/net.h"
+#include "core/host.h"
+//Essentially it is a safe interface to NetUdpSocket
+
+///UDP Socket error codes
+enum UDPSocketErr
+{
+  __UDPSOCKET_MIN = -0xFFFF,
+  UDPSOCKET_SETUP, ///<UDPSocket not properly configured
+  UDPSOCKET_IF, ///<Interface has problems, does not exist or is not initialized
+  UDPSOCKET_MEM, ///<Not enough mem
+  UDPSOCKET_INUSE, ///<Interface / Port is in use
+//...
+  UDPSOCKET_OK = 0 ///<Success
+};
+
+///UDP Socket Event(s)
+enum UDPSocketEvent //Only one event here for now, but keeps that model in case we need to implement some others
+{
+  UDPSOCKET_READABLE, ///<Data in buf
+};
+
+class NetUdpSocket;
+enum NetUdpSocketEvent;
+
+///This is a simple UDP Socket class
+/**
+  This class exposes an API to deal with UDP Sockets
+*/
+class UDPSocket
+{
+public:
+  ///Creates a new socket
+  UDPSocket();
+  
+  ///Closes and destroys socket
+  ~UDPSocket(); //close()
+  
+  ///Binds the socket to local host or a multicast address
+  UDPSocketErr bind(const Host& me);
+  
+  ///Sends data
+  /*
+  @param pHost : host to send data to
+  @return a negative error code or the number of bytes transmitted
+  */
+  int /*if < 0 : UDPSocketErr*/ sendto(const char* buf, int len, Host* pHost);
+  
+  ///Receives data
+  /*
+  @param pHost : host from which this piece of data comes from
+  @return a negative error code or the number of bytes received
+  */
+  int /*if < 0 : UDPSocketErr*/ recvfrom(char* buf, int len, Host* pHost);
+
+  /* TODO NTH : printf / scanf helpers that call send/recv */
+
+  ///Closes socket
+  UDPSocketErr close();
+
+  //Callbacks
+  ///Setups callback
+  /**
+  @param pMethod : callback function
+  */  
+  void setOnEvent( void (*pMethod)(UDPSocketEvent) );
+  
+  class CDummy;
+  ///Setups callback
+  /**
+  @param pItem : instance of class on which to execute the callback method
+  @param pMethod : callback method
+  */
+  template<class T> 
+  void setOnEvent( T* pItem, void (T::*pMethod)(UDPSocketEvent) )
+  {
+    m_pCbItem = (CDummy*) pItem;
+    m_pCbMeth = (void (CDummy::*)(UDPSocketEvent)) pMethod;
+  }
+  
+  ///Disables callback
+  void resetOnEvent();
+
+protected:
+  void onNetUdpSocketEvent(NetUdpSocketEvent e);
+  UDPSocketErr checkInst();
+
+private:
+  NetUdpSocket* m_pNetUdpSocket;
+  
+  CDummy* m_pCbItem;
+  void (CDummy::*m_pCbMeth)(UDPSocketEvent);
+  
+  void (*m_pCb)(UDPSocketEvent);
+
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 core/host.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/host.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,109 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef HOST_H
+#define HOST_H
+
+#include "ipaddr.h"
+#include <string.h>
+
+///Host information container
+/**
+This class is a container for data relative to a connection:
+- IP Address
+- Port number
+- Host Name
+*/
+class Host 
+{
+public:
+  ///Initiliazes host with null values
+  Host() : m_ip(0,0,0,0), m_port(0), m_name(NULL)
+  {
+    
+  }
+  
+  ///Initializes host
+  Host(const IpAddr& ip, const int& port, const char* name="" ) : m_ip(ip), m_port(port), m_name(NULL)
+  {
+    setName(name); 
+  }
+  
+  ~Host()
+  {
+    if(m_name)
+    {
+      delete[] m_name;
+    }
+  }
+  
+  ///Returns IP address
+  const IpAddr& getIp() const
+  {
+    return m_ip;
+  }
+  
+  ///Returns port number
+  const int& getPort() const
+  {
+    return m_port;
+  }
+  
+  ///Returns host name
+  const char* getName() const
+  {
+    return m_name;
+  }
+  
+  ///Sets IP address
+  void setIp(const IpAddr& ip)
+  {
+    m_ip = ip;
+  }
+  
+  ///Sets port number
+  void setPort(int port)
+  {
+    m_port = port;
+  }
+  
+  ///Sets host name
+  void setName(const char* name)
+  {
+    if(m_name)
+      delete[] m_name;
+    int len = strlen(name);
+    if(len)
+    {
+      m_name = new char[len+1];
+      strcpy(m_name, name);
+    }
+  }
+  
+private:
+  IpAddr m_ip;
+  int m_port;
+  char* m_name;
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 core/ipaddr.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/ipaddr.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,104 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "ipaddr.h"
+
+#include "netCfg.h"
+#if NET_LWIP_STACK
+#include "lwip/ip_addr.h"
+#endif
+
+
+#if NET_LWIP_STACK
+IpAddr::IpAddr(ip_addr_t* pIp)
+{
+  *((uint32_t*)m_ip) = pIp->addr;
+}
+#endif
+
+///Initializes IP address with provided values
+IpAddr::IpAddr(uint8_t ip0, uint8_t ip1, uint8_t ip2, uint8_t ip3)
+{
+  //We are in LE
+  m_ip[0] = ip0;
+  m_ip[1] = ip1;
+  m_ip[2] = ip2;
+  m_ip[3] = ip3;
+}
+
+///Initializes IP address with null values 
+IpAddr::IpAddr()
+{
+  m_ip[0] = 0;
+  m_ip[1] = 0;
+  m_ip[2] = 0;
+  m_ip[3] = 0;
+}
+
+
+#if NET_LWIP_STACK
+ip_addr_t IpAddr::getStruct() const
+{
+  ip_addr_t ip_struct;
+  ip_struct.addr = *((uint32_t*)m_ip);
+  return ip_struct;
+}
+#endif
+
+uint8_t IpAddr::operator[](unsigned int i) const
+{
+  uint8_t null = 0;
+  if( i > 3 )
+    return null;
+  return m_ip[i];
+}
+
+bool IpAddr::isEq(const IpAddr& b) const
+{
+  return (*((uint32_t*)m_ip) == *((uint32_t*)(b.m_ip)));
+}
+
+bool IpAddr::operator==(const IpAddr& b) const
+{
+  return isEq(b);
+}
+ 
+bool IpAddr::operator!=(const IpAddr& b) const
+{
+  return !(operator==(b));
+}
+
+bool IpAddr::isNull() const
+{
+  return (*((uint32_t*)m_ip) == 0);
+}
+
+bool IpAddr::isBroadcast() const
+{
+  return (*((uint32_t*)m_ip) == 0xFFFFFFFF);
+}
+
+bool IpAddr::isMulticast() const
+{
+  return ((m_ip[0] & 0xF0) == 0xE0);
+}
diff -r 000000000000 -r 350011bf8be7 core/ipaddr.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/ipaddr.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,98 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef IPADDR_H
+#define IPADDR_H
+
+#include "netCfg.h"
+#if NET_LWIP_STACK
+typedef struct ip_addr ip_addr_t;
+#endif
+
+#include "stdint.h"
+
+///IP Address container
+/**
+This class is a container for an IPv4 address.
+*/
+class IpAddr //Basically a C++ frontend to ip_addr_t
+{
+public:
+  #if NET_LWIP_STACK
+  IpAddr(ip_addr_t* pIp);
+  #endif
+  
+  ///Initializes IP address with provided values
+  IpAddr(uint8_t ip0, uint8_t ip1, uint8_t ip2, uint8_t ip3);
+  
+  ///Initializes IP address with null values 
+  IpAddr();
+
+  #if NET_LWIP_STACK
+  ip_addr_t getStruct() const;
+  #endif
+  
+  ///Returns IP address byte #
+  uint8_t operator[](unsigned int i) const;
+  
+  ///Compares too addresses
+  /**
+  @return true if the two addresses are equal
+  */
+  bool isEq(const IpAddr& b) const;
+  
+  ///Compares too addresses
+  /**
+  @return true if the two addresses are equal
+  */
+  bool operator==(const IpAddr& b) const;
+ 
+  ///Compares too addresses
+  /**
+  @return true if the two addresses are different
+  */ 
+  bool operator!=(const IpAddr& b) const;
+  
+  ///Checks whether the address is null
+  /**
+  @return true if the address is null
+  */
+  bool isNull() const;
+  
+  ///Checks whether the address is a broadcast address
+  /**
+  @return true if the address is a broadcast address
+  */
+  bool isBroadcast() const;
+
+  ///Checks whether the address is a multicast address
+  /**
+  @return true if the address is a multicast address
+  */
+  bool isMulticast() const;
+  
+private:
+  uint8_t m_ip[4];
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 core/net.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/net.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,229 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "net.h"
+
+#include "host.h"
+#include "ipaddr.h"
+#include "netservice.h"
+#include "if/net/netif.h"
+#include "if/net/nettcpsocket.h"
+#include "if/net/netudpsocket.h"
+#include "if/net/netdnsrequest.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+Net::Net() : m_defaultIf(NULL), m_lpIf(), m_lpNetTcpSocket(), m_lpNetUdpSocket()
+{
+
+}
+
+Net::~Net()
+{
+
+}
+
+
+void Net::poll()
+{
+  //DBG("\r\nNet : Services polling\r\n");
+
+  //Poll Services
+  NetService::servicesPoll();  
+  
+  //DBG("\r\nNet : Interfaces polling\r\n");   
+      
+  //Poll Interfaces
+  list<NetIf*>::iterator pIfIt;
+
+  for ( pIfIt = net().m_lpIf.begin() ; pIfIt != net().m_lpIf.end(); pIfIt++ )
+  {
+    (*pIfIt)->poll();
+  }
+  
+  //DBG("\r\nNet : Sockets polling\r\n");
+  
+  //Poll Tcp Sockets
+  list<NetTcpSocket*>::iterator pNetTcpSocketIt;
+
+  for ( pNetTcpSocketIt = net().m_lpNetTcpSocket.begin() ; pNetTcpSocketIt != net().m_lpNetTcpSocket.end(); )
+  {
+    (*pNetTcpSocketIt)->poll();
+    
+    if( (*pNetTcpSocketIt)->m_closed && !((*pNetTcpSocketIt)->m_refs) )
+    {
+      (*pNetTcpSocketIt)->m_removed = true;
+      delete (*pNetTcpSocketIt);
+      (*pNetTcpSocketIt) = NULL;
+      pNetTcpSocketIt = net().m_lpNetTcpSocket.erase(pNetTcpSocketIt);
+    }
+    else
+    {
+      pNetTcpSocketIt++;
+    }
+  }
+  
+  //Poll Udp Sockets
+  list<NetUdpSocket*>::iterator pNetUdpSocketIt;
+
+  for ( pNetUdpSocketIt = net().m_lpNetUdpSocket.begin() ; pNetUdpSocketIt != net().m_lpNetUdpSocket.end(); )
+  {
+    (*pNetUdpSocketIt)->poll();
+    
+    if( (*pNetUdpSocketIt)->m_closed && !((*pNetUdpSocketIt)->m_refs) )
+    {
+      (*pNetUdpSocketIt)->m_removed = true;
+      delete (*pNetUdpSocketIt);
+      (*pNetUdpSocketIt) = NULL;
+      pNetUdpSocketIt = net().m_lpNetUdpSocket.erase(pNetUdpSocketIt);
+    }
+    else
+    {
+      pNetUdpSocketIt++;
+    }
+  }
+
+
+}
+
+NetTcpSocket* Net::tcpSocket(NetIf& netif) {
+  NetTcpSocket* pNetTcpSocket = netif.tcpSocket();
+  pNetTcpSocket->m_refs++;
+  return pNetTcpSocket; 
+}
+
+NetTcpSocket* Net::tcpSocket() { //NetTcpSocket on default if
+ if ( net().m_defaultIf == NULL )
+      return NULL;
+  NetTcpSocket* pNetTcpSocket = net().m_defaultIf->tcpSocket();
+  pNetTcpSocket->m_refs++;
+  return pNetTcpSocket;
+}
+
+void Net::releaseTcpSocket(NetTcpSocket* pNetTcpSocket)
+{
+  pNetTcpSocket->m_refs--;
+  if(!pNetTcpSocket->m_closed && !pNetTcpSocket->m_refs)
+    pNetTcpSocket->close();
+}
+
+NetUdpSocket* Net::udpSocket(NetIf& netif) {
+  NetUdpSocket* pNetUdpSocket = netif.udpSocket();
+  pNetUdpSocket->m_refs++;
+  return pNetUdpSocket; 
+}
+
+NetUdpSocket* Net::udpSocket() { //NetTcpSocket on default if
+ if ( net().m_defaultIf == NULL )
+      return NULL;
+  NetUdpSocket* pNetUdpSocket = net().m_defaultIf->udpSocket();
+  pNetUdpSocket->m_refs++;
+  return pNetUdpSocket;
+}
+
+void Net::releaseUdpSocket(NetUdpSocket* pNetUdpSocket)
+{
+  pNetUdpSocket->m_refs--;
+  if(!pNetUdpSocket->m_closed && !pNetUdpSocket->m_refs)
+    pNetUdpSocket->close();
+}
+
+NetDnsRequest* Net::dnsRequest(const char* hostname, NetIf& netif) {
+  return netif.dnsRequest(hostname);
+}
+
+NetDnsRequest* Net::dnsRequest(const char* hostname) { //Create a new NetDnsRequest object from default if
+  if ( net().m_defaultIf == NULL )
+      return NULL;
+  return net().m_defaultIf->dnsRequest(hostname);
+}
+
+NetDnsRequest* Net::dnsRequest(Host* pHost, NetIf& netif)
+{
+  return netif.dnsRequest(pHost);
+}
+
+NetDnsRequest* Net::dnsRequest(Host* pHost) //Creats a new NetDnsRequest object from default if
+{
+  if ( net().m_defaultIf == NULL )
+      return NULL;
+  return net().m_defaultIf->dnsRequest(pHost);
+}
+
+void Net::setDefaultIf(NetIf& netif) {
+  net().m_defaultIf = &netif;
+}
+
+void Net::setDefaultIf(NetIf* pIf)
+{
+  net().m_defaultIf = pIf;
+}
+
+NetIf* Net::getDefaultIf() {
+  return net().m_defaultIf;
+}
+
+void Net::registerIf(NetIf* pIf)
+{
+  net().m_lpIf.push_back(pIf);
+}
+
+void Net::unregisterIf(NetIf* pIf)
+{
+  if( net().m_defaultIf == pIf )
+    net().m_defaultIf = NULL;
+  net().m_lpIf.remove(pIf);
+}
+
+void Net::registerNetTcpSocket(NetTcpSocket* pNetTcpSocket)
+{
+  net().m_lpNetTcpSocket.push_back(pNetTcpSocket);
+  DBG("\r\nNetTcpSocket [ + %p ] %d\r\n", (void*)pNetTcpSocket, net().m_lpNetTcpSocket.size());
+}
+
+void Net::unregisterNetTcpSocket(NetTcpSocket* pNetTcpSocket)
+{
+  DBG("\r\nNetTcpSocket [ - %p ] %d\r\n", (void*)pNetTcpSocket, net().m_lpNetTcpSocket.size() - 1);
+  if(!pNetTcpSocket->m_removed)
+    net().m_lpNetTcpSocket.remove(pNetTcpSocket);
+}
+
+void Net::registerNetUdpSocket(NetUdpSocket* pNetUdpSocket)
+{
+  net().m_lpNetUdpSocket.push_back(pNetUdpSocket);
+  DBG("\r\nNetUdpSocket [ + %p ] %d\r\n", (void*)pNetUdpSocket, net().m_lpNetUdpSocket.size());
+}
+
+void Net::unregisterNetUdpSocket(NetUdpSocket* pNetUdpSocket)
+{
+  DBG("\r\nNetUdpSocket [ - %p ] %d\r\n", (void*)pNetUdpSocket, net().m_lpNetUdpSocket.size() - 1);
+  if(!pNetUdpSocket->m_removed)
+    net().m_lpNetUdpSocket.remove(pNetUdpSocket);
+}
+
+Net& Net::net()
+{
+  static Net* pInst = new Net(); //Called only once
+  return *pInst;
+}
diff -r 000000000000 -r 350011bf8be7 core/net.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/net.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,101 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef NET_H
+#define NET_H
+
+class NetIf;
+class NetTcpSocket;
+class NetUdpSocket;
+class NetDnsRequest;
+
+#include <list>
+using std::list;
+
+/*
+#include "host.h"
+#include "ipaddr.h"
+#include "netservice.h"
+#include "if/net/netif.h"
+#include "if/net/nettcpsocket.h"
+#include "if/net/netudpsocket.h"
+#include "if/net/netdnsrequest.h"
+*/
+
+class Host;
+class NetIf;
+class NetTcpSocket;
+class NetUdpSocket;
+class NetDnsRequest;
+
+class Net
+{
+private:
+  Net();
+  ~Net();
+public:  
+  static void poll(); //Poll every if & socket
+  
+  static NetTcpSocket* tcpSocket(NetIf& netif);
+  static NetTcpSocket* tcpSocket(); //Socket on default if
+  static void releaseTcpSocket(NetTcpSocket* pNetTcpSocket);
+  
+  static NetUdpSocket* udpSocket(NetIf& netif);
+  static NetUdpSocket* udpSocket(); //Socket on default if
+  static void releaseUdpSocket(NetUdpSocket* pNetUdpSocket);
+  
+  static NetDnsRequest* dnsRequest(const char* hostname, NetIf& netif);
+  static NetDnsRequest* dnsRequest(const char* hostname); //Create a new NetDnsRequest object from default if
+
+  static NetDnsRequest* dnsRequest(Host* pHost, NetIf& netif);
+  static NetDnsRequest* dnsRequest(Host* pHost); //Create a new NetDnsRequest object from default if
+  
+  static void setDefaultIf(NetIf& netif); //Deprecated
+  static void setDefaultIf(NetIf* pIf);
+  static NetIf* getDefaultIf();
+  
+protected:
+  friend class NetIf;
+  friend class NetTcpSocket;
+  friend class NetUdpSocket;
+  
+  static void registerIf(NetIf* pIf);
+  static void unregisterIf(NetIf* pIf);
+  
+  static void registerNetTcpSocket(NetTcpSocket* pNetTcpSocket);
+  static void unregisterNetTcpSocket(NetTcpSocket* pNetTcpSocket);  
+  
+  static void registerNetUdpSocket(NetUdpSocket* pNetUdpSocket);
+  static void unregisterNetUdpSocket(NetUdpSocket* pNetUdpSocket);  
+  
+private:
+  static Net& net(); //Return inst of singleton
+
+  NetIf* m_defaultIf;
+  
+  list<NetIf*> m_lpIf;
+  list<NetTcpSocket*> m_lpNetTcpSocket;
+  list<NetUdpSocket*> m_lpNetUdpSocket;
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 core/netservice.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/netservice.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,88 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "netservice.h"
+#include "net.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+NetService::NetService(bool owned /*= true*/) : m_closed(false), m_removed(false), m_owned(owned)
+{
+  NetService::lpServices().push_back(this);
+  DBG("\r\n[ + %p ] %d\r\n", (void*)this, lpServices().size());
+}
+
+NetService::~NetService()
+{
+ // DBG("\r\nService removed\r\n");
+//  DBG("\r\nNow %d services running\r\n", lpServices().size()-1);
+  DBG("\r\n[ - %p ] %d\r\n", (void*)this, lpServices().size()-1);
+  if((!m_owned) || (!m_removed)) //Destructor was not called by servicesPoll()
+  { 
+    if(m_owned)
+      DBG("\r\nWARN!!!Service removed in dtor!!!\r\n");
+    NetService::lpServices().remove(this);
+  }
+}
+
+void NetService::poll()
+{
+
+}
+  
+void NetService::servicesPoll() //Poll all registered services & destroy closed ones
+{
+  list<NetService*>::iterator it;
+  DBG("\r\nServices polling over %d services\r\n", lpServices().size());
+  for( it = lpServices().begin(); it != lpServices().end();  )
+  {
+    if( (*it)->m_owned && (*it)->m_closed  )
+    {
+      DBG("\r\nService %p is flagged as closed\r\n", (*it));
+      (*it)->m_removed = true;
+      delete (*it);
+      it = lpServices().erase(it);
+    }
+    else
+    {
+      //DBG("Service %p polling start\n", (*it));
+      (*it)->poll();
+      //DBG("Service %p polling end\n", (*it));
+      it++;
+    }
+  }
+  
+}
+
+void NetService::close()
+{
+  DBG("\r\nService %p to be closed (owned = %d)\r\n", this, m_owned);
+  m_closed = true;
+}
+
+list<NetService*>& NetService::lpServices()
+{
+  static list<NetService*>* pInst = new list<NetService*>(); //Called only once
+  return *pInst;
+}
diff -r 000000000000 -r 350011bf8be7 core/netservice.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/netservice.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,67 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/**
+\file Net Service base class header file
+*/
+
+#ifndef NETSERVICE_H
+#define NETSERVICE_H
+
+#include <list>
+using std::list;
+
+///Net Service base class
+/**
+Each connection-oriented object can register as service (by inheriting this class), so that it is polled regularly.
+It notifies the pool when the connection is terminated so that it can be destroyed.
+*/
+class NetService
+{
+public:
+  ///Instantiates a new service
+  /**
+  @param owned If true the object is owned by the pool and will be destroyed on closure.
+  */
+  NetService(bool owned = true); //Is owned by the pool?
+  virtual ~NetService();
+
+  ///This method can be inherited so that it is called on each @a Net::poll() call.
+  virtual void poll();
+ 
+  static void servicesPoll(); //Poll all registered services & destroy closed ones
+
+protected:
+  ///This flags the service as to be destructed if owned by the pool.
+  void close();
+  
+private:
+  bool m_closed;
+  bool m_removed;
+  bool m_owned;
+  
+  static list<NetService*>& lpServices(); //Helper to prevent static initialization fiasco  
+
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 dbg/dbg.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbg/dbg.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,63 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#define __LWIP_DEBUG
+#define __DEBUG
+#include "dbg.h"
+#include "mbed.h"
+#include <cstdarg>
+
+void DebugStream::debug(const char* format, ...)
+{ 
+  va_list argp;
+  
+  va_start(argp, format);
+  vprintf(format, argp);
+  va_end(argp);
+}
+
+void DebugStream::release()
+{
+
+}
+
+void DebugStream::breakPoint(const char* file, int line)
+{
+  printf("\r\nBREAK in %s at line %d\r\n", file, line);
+  fflush(stdout);
+  getchar();
+  fflush(stdin);
+}
+
+/*
+int snprintf(char *str, int size, const char *format, ...)
+{
+  va_list argp;
+  
+  va_start(argp, format);
+  vsprintf(str, format, argp);
+  va_end(argp);
+  
+  return strlen(str);
+}
+*/
diff -r 000000000000 -r 350011bf8be7 dbg/dbg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbg/dbg.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,94 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/** \file
+Debugging helpers header file
+*/
+
+//#ifdef DBG_H
+//#define DBG_H
+
+#ifdef __LWIP_DEBUG
+#define __DEBUG
+#endif
+
+/*!
+  \def __DEBUG
+  To define to enable debugging in one file
+*/
+
+#ifdef __DEBUG
+
+#ifndef __DEBUGSTREAM
+#define __DEBUGSTREAM
+
+
+class DebugStream
+{
+public:
+static void debug(const char* format, ...);
+static void release();
+static void breakPoint(const char* file, int line);
+private:
+
+};
+
+#undef DBG
+#undef DBG_END
+#undef BREAK
+
+///Debug output (if enabled), same syntax as printf, with heading info
+#define DBG(...) do{ DebugStream::debug("[%s:%s@%d] ", __FILE__, __FUNCTION__, __LINE__); DebugStream::debug(__VA_ARGS__); } while(0);
+
+///Debug output (if enabled), same syntax as printf, no heading info
+#define DBGL(...) do{ DebugStream::debug(__VA_ARGS__); } while(0);
+#define DBG_END DebugStream::release
+
+///Break point usin serial debug interface (if debug enbaled)
+#define BREAK() DebugStream::breakPoint(__FILE__, __LINE__)
+#endif
+
+#else
+#undef DBG
+#undef DBG_END
+#undef BREAK
+#define DBG(...)
+#define DBG_END()
+#define BREAK()
+#endif
+
+#ifdef __LWIP_DEBUG
+#ifndef __SNPRINTF
+#define __SNPRINTF
+#include "mbed.h"
+
+//int snprintf(char *str, int size, const char *format, ...);
+#endif
+#endif
+
+#ifdef __LWIP_DEBUG
+#undef __DEBUG
+#endif
+
+//#endif
+
diff -r 000000000000 -r 350011bf8be7 drv/at/ATIf.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/at/ATIf.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,772 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "ATIf.h"
+#include "mbed.h"
+#include <cstdarg>
+
+#define READ_TIMEOUT 100
+#define TMP_BUF_SIZE 128//512
+
+#define SERIAL_BUF_LEN 512 //Huge buf needed for PPP (esp. when transferring big data chunks, using TCP)
+
+#define BAUDRATE 9600//9600//115200// 19200
+
+#include "netCfg.h"
+#if NET_GPRS
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+ATIf::ATIf() : SerialBuf(SERIAL_BUF_LEN), m_isOpen(false)//, m_signalsEnable(false), m_isOpen(false), m_pCurrentSignal(NULL), m_signals() 
+{
+  DBG("New AT If@%p\n", this);
+
+  m_readTimeout = READ_TIMEOUT; //default 1s
+  //tmpBuf = NULL;
+  m_lineMode = false;
+  m_tmpBuf = new char[TMP_BUF_SIZE];
+}
+
+ATIf::~ATIf()
+{
+  if(m_tmpBuf)
+    delete[] m_tmpBuf;
+}
+
+int ATIf::printf(const char* format, ... )
+{
+
+/*if(!m_tmpBuf)
+    m_tmpBuf = new char[TMP_BUF_SIZE]; //is it really necessary ??*/
+  *m_tmpBuf=0;
+     
+  int len = 0;
+  
+  //
+//  flushBuffer();
+//wait(1);
+  //
+    
+  va_list argp;
+  
+  va_start(argp, format);
+  len += vsprintf(m_tmpBuf, format, argp);
+  va_end(argp);
+  
+  //DBG("\r\nOutBuf is : %s, mode is %d.", m_tmpBuf, m_lineMode);
+  
+  int err = write( m_tmpBuf, m_lineMode );
+  if (err<0)
+    return 0;
+    
+  return len;
+  
+}
+
+int ATIf::scanf(const char* format, ... )
+{
+/*if(!m_tmpBuf)
+    m_tmpBuf = new char[TMP_BUF_SIZE];*/
+  int err = read( m_tmpBuf, TMP_BUF_SIZE - 1,  m_readTimeout, m_lineMode, 1/*Ensure at least one char is read*/ );
+  if (err<0)
+    return -1;//EOF
+    
+  DBG("Scanf'ing:\r\n%s\r\n",m_tmpBuf);
+    
+  int len = 0;
+  
+  if(strchr(format,'%')) //Ugly, determines wether format string is null or not
+  {
+    va_list argp;
+    
+    va_start(argp, format);
+    len += vsscanf(m_tmpBuf, format, argp);
+    va_end(argp);
+  }
+  else //No varargs, call strncmp
+  {
+ /*   if(strlen(m_tmpBuf) == 0 )
+      return -1;*/
+    if( !strncmp(m_tmpBuf, format, strlen(format)) )
+    {
+      return 0;
+    }
+    else
+    {
+      return -1;
+    }
+  }
+  
+  return len;
+  
+}
+
+void ATIf::setTimeout(int timeout) //used by scanf
+{
+  m_readTimeout = timeout;
+}
+
+void ATIf::setLineMode(bool lineMode) //Switch btw line & raw fns
+{
+  m_lineMode = lineMode;
+}
+
+#if 0
+void ATIf::setSignals(bool signalsEnable)
+{
+  m_signalsEnable=signalsEnable;
+}
+#endif
+
+#if 0
+template<class T>
+void ATIf::attachSignal( const char* sigName, T* pItem, bool (T::*pMethod)(ATIf*, bool, bool*) ) //Attach Signal ("Unsollicited response code" in Telit_AT_Reference_Guide.pdf) to an handler fn
+{
+  ATSigHandler sig(sigName, (ATSigHandler::CDummy*)pItem, (bool (ATSigHandler::CDummy::*)(ATIf*, bool, bool*))pMethod);
+  m_signals.push_back(sig);
+}
+#endif
+
+#if 0
+void ATIf::detachSignal( const char* sigName )
+{
+  list<ATSigHandler>::iterator it;
+  
+  for ( it = m_signals.begin(); it != m_signals.end(); it++ )
+  {
+    if( !strcmp((*it).m_name,sigName) )
+    {
+      m_signals.erase(it);
+      break;
+    }
+  }
+}
+#endif
+
+ATErr ATIf::open(Serial* pSerial) //Deactivate echo, etc
+{
+  DBG("Opening...\n");
+  m_isOpen = true; //Must be set so that the serial port-related fns work
+  //Setup options  
+//  pSerial->baud(BAUDRATE); //FIXME
+  SerialBuf::attach(pSerial);
+
+  setReadMode(false); //Discard chars
+  setTimeout(1000);
+  setLineMode(true); //Line Mode
+  
+  DBG("Trmt...\n");
+ // printf("AT+IPR=%d", BAUDRATE); //FIXME
+  printf("ATZ"); //Reset
+  wait(.100);
+  printf("ATE"); //Deactivate echo
+  wait(.500);
+  flushBuffer();
+  
+  DBG("ATZ ATE...\n");
+  
+  int len = writeLine("ATV1");
+  ATErr err = AT_OK;
+  if(len<0)
+    err=(ATErr)len;
+    
+  if(!err)
+  {
+    err = checkOK();
+    if (err) //No ACK from module
+    {
+      DBG("\r\nOpening port, error %d.", err);
+      if(err==AT_TIMEOUT)
+        err = AT_NOANSWER;
+    }
+  }
+  
+  if(err)
+  {
+    SerialBuf::detach();
+    m_isOpen = false;
+    return err;
+  }
+  
+  DBG("\r\nNo error.");
+  #if 0//FIXME
+  m_signalsEnable = true;
+  #endif
+  //FIXME:
+//  m_pSerial->attach<ATIf>(this, &ATIf::onSerialInterrupt);
+  
+  return AT_OK;
+}
+
+#if NET_USB_SERIAL
+ATErr ATIf::open(UsbSerial* pUsbSerial) //Deactivate echo, etc
+{
+  DBG("Opening...\n");
+  m_isOpen = true; //Must be set so that the serial port-related fns work
+  //Setup options  
+  SerialBuf::attach(pUsbSerial);
+
+  setReadMode(false); //Discard chars
+  setTimeout(1000);
+  setLineMode(true); //Line Mode
+
+  printf("ATZ"); //Reinit
+  wait(.500);  
+  //flushBuffer();
+//  printf("ATE0 ^CURC=0"); //Deactivate echo & notif
+  printf("ATE0"); //Deactivate echo & notif
+  wait(.500);
+  flushBuffer();
+  
+  DBG("ATZ ATE...\n");
+  
+  int len = writeLine("ATQ0 V1 S0=0 &C1 &D2 +FCLASS=0");//writeLine("ATQ0 V1 S0=0 &C1 &D2 +FCLASS=0");
+  ATErr err = AT_OK;
+  if(len<0)
+    err=(ATErr)len;
+    
+  if(!err)
+  {
+    err = checkOK();
+    if (err) //No ACK from module
+    {
+      DBG("Opening port, error %d.\n", err);
+      if(err==AT_TIMEOUT)
+        err = AT_NOANSWER;
+    }
+  }
+  
+  if(err)
+  {
+    SerialBuf::detach();
+    m_isOpen = false;
+    return err;
+  }
+  
+  DBG("No error.\n");
+  #if 0//FIXME
+  m_signalsEnable = true;
+  #endif
+  //FIXME:
+//  m_pSerial->attach<ATIf>(this, &ATIf::onSerialInterrupt);
+  
+  return AT_OK;
+}
+#endif
+
+ATErr ATIf::close() //Release port
+{
+  SerialBuf::detach(); //Detach serial buf
+  m_isOpen = false;
+  //m_signalsEnable = false;
+  return AT_OK;
+}
+
+ATErr ATIf::flushBuffer()
+{
+  if(!m_isOpen)
+    return AT_CLOSED;
+  
+  int len=0;
+  //char c;
+  while(readable())
+  {
+    //DBG("Readable\n"); 
+    /*c =*/ getc();
+    //DBG("\r\n[%c] discarded.", c);    
+ //   wait(0.01);
+    len++;
+  }
+  
+  DBG("\r\n%d chars discarded.", len);
+  
+  return AT_OK;
+}
+
+ATErr ATIf::flushLine(int timeout)
+{
+  if(!m_isOpen)
+    return AT_CLOSED;
+    
+  Timer timer;
+  
+  timer.start();
+  
+  int len=0;
+  char c=0;
+  while(true)
+  {
+    while(!readable())
+    {      if(timer.read_ms()>timeout)
+      {
+ //       DBG("Timeout!!0");
+        return AT_TIMEOUT;
+      }
+    }
+    if(c=='\x0D')
+    {
+      c = getc();
+      len++;
+      if(c=='\x0A')
+        break;
+    }
+    else
+    {
+      c = getc();
+      len++;
+    }
+  }
+  
+//  DBG("\r\n%d chars discarded.", len);
+  
+  return AT_OK;
+}
+
+#if 0
+bool ATIf::onRead()
+{
+  if(!m_signalsEnable)
+    return false;
+
+  //Save Usermode params
+  volatile int u_readTimeout = m_readTimeout;
+  volatile bool u_lineMode = m_lineMode;
+//  bool u_isOpen = m_isOpen;
+  SerialBuf::setReadMode(true);
+  
+  m_readTimeout = 0; //No timeout in an interrupt fn!
+  
+  bool handled;
+  if(!!flushLine(0))
+  {
+    SerialBuf::resetRead();
+    //Not a complete line here, wait...
+    handled = false;
+  }
+  else
+  {
+   SerialBuf::resetRead();
+   handled = true; 
+   if( handleSignal() ) //Was that a signal ?
+    {
+      //OK, discard data since it has been processed
+      SerialBuf::flushRead();
+    }
+    else
+    {
+      //Keep data since it has not been processed yet
+      //Have to be processed in usermode
+      SerialBuf::resetRead();
+//      handled = false; 
+    }
+  }  
+  //Restore Usermode params
+  m_readTimeout = u_readTimeout;
+  m_lineMode = u_lineMode;
+  //m_isOpen = u_isOpen;
+  return handled;
+}
+#endif
+
+ATErr ATIf::rawOpen(Serial* pSerial, int baudrate) //Simple open function for similar non-conforming protocols
+{
+  DBG("\r\nOpening...");
+  m_isOpen = true; //Must be set so that the serial port-related fns work
+  //Setup options  
+  pSerial->baud(baudrate);
+  SerialBuf::attach(pSerial);
+
+  return AT_OK;
+}
+
+#if 0
+ATErr ATIf::command(const char* cmd, char* result, int resultLen, int timeout) ////WARN/FIXME: result has to be long enough!!!
+{  
+  if(!m_isOpen)
+    return AT_CLOSED;
+  
+  flushBuffer();
+  
+  int err;
+  err = writeLine(cmd);
+  
+  if(err<0)
+    { m_receiveStatus = AT_READY; return (ATErr)err; }
+    
+  err = readLine(result, resultLen, timeout);
+  
+  if(err<0)
+    { m_receiveStatus = AT_READY; return (ATErr)err; }
+      
+  m_receiveStatus = AT_READY;
+    
+  return AT_OK;
+  
+}
+#endif
+
+ATErr ATIf::write(const char* cmd, bool lineMode /*= false*/)
+{
+  if(!m_isOpen)
+    return AT_CLOSED;
+
+  int err;  
+  err = lineMode ? writeLine(cmd) : writeRaw(cmd);
+
+  if(err<0)
+    return (ATErr)err;
+      
+  return AT_OK;
+}
+
+
+ATErr ATIf::read(char* result, int resultMaxLen, int timeout, bool lineMode /*= false*/, int resultMinLen/* = 0*/)
+{
+  if(!m_isOpen)
+    return AT_CLOSED;
+  
+  int err;  
+  err = lineMode ? readLine(result, resultMaxLen, timeout) :  readRaw(result, resultMaxLen, timeout, resultMinLen);
+  
+  if(err<0)
+    return (ATErr)err;
+    
+  return AT_OK;
+}
+
+bool ATIf::isOpen()
+{
+  return m_isOpen;
+}
+
+ATErr ATIf::checkOK() //Helper fn to quickly check that OK has been returned
+{
+  char ret[16] = {0};
+  int err = readLine(ret,16,m_readTimeout);
+  
+  if(err<0)
+  {
+    DBG("\r\nError in check (%s).\r\n", ret);
+    flushBuffer(); //Discard anything in buf to avoid misparsing in the following calls
+    return (ATErr)err;
+  }
+  
+  if(!!strcmp("OK",ret))
+  {
+    DBG("\r\nNot an OK <%s>.\r\n", ret);
+    flushBuffer();
+    return AT_ERROR;
+  }
+  
+  DBG("\r\nCHECK OK\r\n");
+  
+  return AT_OK;
+}
+
+#if 0
+void ATIf::onSerialInterrupt() //Callback from m_pSerial
+{
+return;//FIXME
+
+  if(m_receiveStatus == AT_READING)
+    return;
+
+  if( m_cbObj && m_cbMeth )
+    return (m_cbObj->*m_cbMeth)();
+}
+#endif
+
+int ATIf::readLine(char* line, int maxLen, int timeout) //Read a single line from serial port, return length or ATErr(<0)
+{
+#ifdef OLDREADLINE
+  if(!m_isOpen)
+    return AT_CLOSED;
+    
+  int len = 0;
+  
+  Timer timer;
+  
+  timer.start();
+#ifdef __START_CLRF_MANDAT
+  for( int i=0; i<2; i++ )
+  {
+    while(!readable())
+    {
+      if(timer.read_ms()>timeout)
+      {
+//        DBG("Timeout!!0");
+        return AT_TIMEOUT;
+      }
+      wait_ms(10); //Wait 10ms
+    }
+    *line = getc();
+  //  DBG("In readLine(), read : %c", *line);
+    if( ( (i == 0) && (*line!='\x0D') )
+     || ( (i == 1) && (*line!='\x0A') ) )
+     return AT_PARSE;
+  }
+#else
+  
+#endif
+
+  for( ; len < maxLen ; len++ )
+  {
+    timer.reset();
+    while(!readable())
+    {
+      if(timer.read_ms()>timeout)
+      {
+//        DBG("Timeout!!1");
+        return AT_TIMEOUT;
+      }
+      wait_ms(10); //Wait 10ms
+    }
+    *line = getc();
+    //DBG("In readLine(), read : %c", *line);
+
+    if(*line=='\x0D')
+    {
+      timer.reset();
+      while(!readable())
+      {
+        if(timer.read_ms()>timeout)
+        {
+          return AT_TIMEOUT;
+        }
+        wait_ms(10); //Wait 1ms
+      }
+      *line = getc();
+    //  DBG("In readLine(), read : %c", *line);
+      if(*line=='\x0A')
+      {
+        if(len==0)
+        {
+          //Start of line
+          len--;
+          continue;
+        }
+        else
+        {
+          *line=0; //End of line
+          break;
+        }
+      }
+      else
+      {
+        //Should not happen, must have lost some bytes somewhere or non AT protocol
+        return AT_PARSE;
+      }
+    }
+    line++;
+  }
+  
+  if(len==maxLen)
+    return AT_INCOMPLETE; //Buffer full, must call this method again to get end of line
+  
+  return len;
+#else
+ if(!m_isOpen)
+    return AT_CLOSED;
+  
+  Timer timer;  
+  timer.start();
+
+  int len = 0;
+  while( len < maxLen )
+  {
+    timer.reset();
+    while(!readable())
+    {
+      if(timer.read_ms()>timeout)
+      {
+        return AT_TIMEOUT;
+      }
+      wait_ms(10); //Wait 10ms
+    }
+    *line = getc();
+
+    if( (*line=='\x0D') || (*line=='\x0A') )
+    {
+    
+      if(len==0)
+      {
+        //Start of line
+        continue;
+      }
+      else
+      {
+        *line=0; //End of line
+        break;
+      }
+    }
+    len++;  
+    line++;
+  }
+  
+  if(len==maxLen)
+    return AT_INCOMPLETE; //Buffer full, must call this method again to get end of line
+  
+  return len;
+#endif
+}
+
+int ATIf::writeLine(const char* line) //Write a single line to serial port
+{
+//  char* line = (char*) _line;
+  if(!m_isOpen)
+    return AT_CLOSED;
+  
+//  DBG("\n\rIn writeline.");
+  
+  int len = 0;
+
+  while(*line)
+  {
+    putc(*line);
+    line++;
+    len++;
+  }
+  
+ /* putc('\r');
+  
+    putc('\n');*/
+  
+  putc('\x0D');
+//  putc('\x0A');
+
+// DBG("\n\rWritten %d + 1", len);
+  
+  return len;
+ 
+}
+
+
+    
+int ATIf::readRaw(char* str, int maxLen, int timeout /*= 0*/, int minLen /*= 0*/) //Read from serial port in buf
+{
+  if(!m_isOpen)
+    return AT_CLOSED;
+    
+  int len = 0;
+  
+  Timer timer;
+  
+  timer.start();
+
+  for( ; len < maxLen ; len++ )
+  {
+    while( (len < minLen) && !readable())
+    {
+      if(timer.read_ms()>timeout)
+      {
+        return AT_TIMEOUT;
+      }
+      wait(.01); //Wait 10ms
+    }
+    
+    if(!readable()) //Buffer read entirely
+      break;
+      
+    *str = getc();
+    str++;
+    len++;
+  }
+  
+  *str = 0; //End char
+  
+  return len;
+  
+}
+
+int ATIf::writeRaw(const char* str) //Write directly to serial port    
+{
+  if(!m_isOpen)
+    return AT_CLOSED;
+    
+  int len = 0;
+
+  while(*str)
+  {
+    putc(*str);
+    str++;
+    len++;
+  }
+  
+  return len;
+}    
+
+#if 0
+bool ATIf::handleSignal()
+{
+  bool beg = false;
+  
+//  SerialBuf::setReadMode(true); //Keep chars in buf when read  
+//  SerialBuf::resetRead();
+   
+  //if( !m_pCurrentSignal ) //If no signal asked for this line
+  if(true) //Check anyway, could have been some parsing error before
+  {
+    //Extract Signal Name
+    char sigName[32]; //Should not be longer than that
+    setLineMode(true); //Read one line  
+
+    int len = scanf("%[^:]:%*[^\n]", sigName);
+    if(len != 1)
+      return false; //This is not a signal      
+ //   DBG("\r\nGot signal %s\r\n", sigName);
+  
+    list<ATSigHandler>::iterator it;
+
+    for ( it = m_signals.begin(); it != m_signals.end(); it++ )
+    {
+      if( !strcmp((*it).m_name, sigName) )
+      {
+  //      DBG("\r\nFound signal %s\r\n", sigName);
+        m_pCurrentSignal = &(*it);
+        beg = true;
+        break;
+      }
+    }
+    
+    
+  }
+  
+  if( !m_pCurrentSignal ) 
+    return false; //This is not a signal or it cannot be handled
+    
+  bool moreData = false;
+  //Call signal handling routine
+  SerialBuf::resetRead(); //Rollback so that the handling fn can call scanf properly
+  bool result = ((m_pCurrentSignal->m_cbObj)->*(m_pCurrentSignal->m_cbMeth))(this, beg, &moreData);
+  
+  if( !moreData ) //Processing completed
+  {
+    m_pCurrentSignal = NULL;
+  }
+  
+  return result;
+}
+#endif
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/at/ATIf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/at/ATIf.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,130 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef ATIF_H
+#define ATIF_H
+
+#include "netCfg.h"
+
+#include "mbed.h"
+#include "drv/serial/buf/SerialBuf.h"
+#include <list>
+using std::list;
+
+//class Serial; //Pb w forward decl
+
+enum ATErr
+{
+  __AT_MIN = -0xFFFF,
+  AT_CLOSED,
+  AT_NOANSWER,
+  AT_ERROR,
+  AT_TIMEOUT, 
+  AT_BUSY,
+  AT_PARSE,
+  AT_INCOMPLETE,
+  AT_OK = 0
+};
+
+class ATIf : public SerialBuf
+{
+  public:
+    
+    ATIf();
+    virtual ~ATIf();
+
+#if 0    
+    template<class T> 
+    //void attachSignal( const char* sigName, T* pItem, bool (T::*pMethod)(ATIf*, bool, bool*) ); //Attach Signal ("Unsollicited response code" in Telit_AT_Reference_Guide.pdf) to an handler fn
+    //Linker bug : Must be defined here :(
+    void attachSignal( const char* sigName, T* pItem, bool (T::*pMethod)(ATIf*, bool, bool*) ) //Attach Signal ("Unsollicited response code" in Telit_AT_Reference_Guide.pdf) to an handler fn
+    {
+      ATSigHandler sig(sigName, (ATSigHandler::CDummy*)pItem, (bool (ATSigHandler::CDummy::*)(ATIf*, bool, bool*))pMethod);
+      m_signals.push_back(sig);
+    }
+    void detachSignal( const char* sigName );    
+#endif
+  
+    ATErr open(Serial* pSerial); //Deactivate echo, etc
+    #if NET_USB_SERIAL
+    ATErr open(UsbSerial* pUsbSerial); //Deactivate echo, etc
+    #endif
+    ATErr close(); //Release port
+    
+    int printf(const char* format, ... );
+    int scanf(const char* format, ... );
+    void setTimeout(int timeout); //used by scanf
+    void setLineMode(bool lineMode); //Switch btw line & raw fns
+    //void setSignals(bool signalsEnable);
+    ATErr flushBuffer(); //Discard input buffer
+    ATErr flushLine(int timeout); //Discard input buffer until CRLF is encountered
+    
+  protected:
+    //virtual bool onRead(); //Inherited from SerialBuf, return true if data is incomplete
+    ATErr rawOpen(Serial* pSerial, int baudrate); //Simple open function for similar non-conforming protocols
+
+  public:
+/*    ATErr command(const char* cmd, char* result, int resultLen, int timeout); */ //Kinda useless
+    ATErr write(const char* cmd, bool lineMode = false);
+    ATErr read(char* result, int resultMaxLen, int timeout, bool lineMode = false, int resultMinLen = 0);
+    bool isOpen();
+    ATErr checkOK(); //Helper fn to quickly check that OK has been returned
+  
+  private:  
+    int readLine(char* line, int maxLen, int timeout); //Read a single line from serial port
+    int writeLine(const char* line); //Write a single line to serial port
+    
+    int readRaw(char* str, int maxLen, int timeout = 0, int minLen = 0); //Read from serial port in buf
+    int writeRaw(const char* str); //Write directly to serial port
+      
+    volatile int m_readTimeout;
+    volatile bool m_lineMode;
+    //bool m_signalsEnable;
+    bool m_isOpen;
+    
+    char* m_tmpBuf;
+ 
+#if 0 
+    class ATSigHandler
+    {
+      class CDummy;
+      public:
+        ATSigHandler(const char* name, CDummy* cbObj, bool (CDummy::*cbMeth)(ATIf* pIf, bool beg, bool* pMoreData)) : m_cbObj(cbObj), m_cbMeth(cbMeth), m_name(name) 
+        {}
+      protected:
+        CDummy* m_cbObj;
+        bool (CDummy::*m_cbMeth)(ATIf* pIf, bool beg, bool* pMoreData); //*pMoreData set to true if needs to read next line, beg = true if beginning of new code
+        const char* m_name;
+     
+      friend class ATIf;
+    };
+    
+    volatile ATSigHandler* m_pCurrentSignal; //Signal that asked more data
+    
+    bool handleSignal(); //Returns true if signal has been handled
+    list<ATSigHandler> m_signals;
+#endif
+    
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/eth/eth_drv.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/eth/eth_drv.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,212 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "netCfg.h"
+#if NET_ETH
+
+#include "mbed.h"
+
+Ethernet *pEth = NULL;
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "lwip/opt.h"
+
+#include "lwip/def.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+#include "lwip/stats.h"
+#include "netif/etharp.h"
+#include "string.h"
+
+//#include "eth_drv.h"
+
+#define IFNAME0 'E'
+#define IFNAME1 'X'
+
+#define min(x,y) (((x)<(y))?(x):(y))
+
+struct netif* eth_netif;
+
+static err_t eth_output(struct netif *netif, struct pbuf *p) {
+  #if ETH_PAD_SIZE
+    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
+  #endif
+
+  do {
+    pEth->write((const char *)p->payload, p->len);
+  } while((p = p->next)!=NULL);
+
+  pEth->send();
+
+  #if ETH_PAD_SIZE
+    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
+  #endif
+  
+  LINK_STATS_INC(link.xmit);
+  return ERR_OK;
+}
+
+/*
+void show(char *buf, int size) {
+    printf("Destination:  %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
+            buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+    printf("Source: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
+            buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
+  
+    printf("Type %hd\n", htons((short)buf[12]));
+    
+   // hexview(buf, size);
+}
+*/
+
+void eth_poll() {
+  struct eth_hdr *ethhdr;
+  struct pbuf *frame, *p;
+  int len, read;
+
+  while((len = pEth->receive()) != 0) {
+      frame = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
+      if(frame == NULL) {
+          return;
+      }
+      p = frame;
+      /* no packet could be read, silently ignore this */
+      if (p == NULL) return;
+      do {
+         read = pEth->read((char *)p->payload, p->len);
+         p = p->next;
+      } while(p != NULL && read != 0);
+           
+      #if ETH_PAD_SIZE
+          pbuf_header(p, ETH_PAD_SIZE);
+      #endif
+
+      ethhdr = (struct eth_hdr *)(frame->payload);
+      
+     // show((char*)ethhdr, 13);
+      
+      /*
+      switch(htons(ethhdr->type)) {
+          
+          case ETHTYPE_IP:
+              etharp_ip_input(gnetif, frame);
+              pbuf_header(frame, -((s16_t) sizeof(struct eth_hdr)));
+              gnetif->input(frame, gnetif);
+              break;
+          
+          case ETHTYPE_ARP:
+              etharp_arp_input(gnetif, (struct eth_addr *)(gnetif->hwaddr), frame);
+              break;
+          
+          default:
+              break;
+      }*/
+      
+      
+      
+      //ethernet_input(frame, gnetif);
+      
+      switch (htons(ethhdr->type)) {
+      /* IP or ARP packet? */
+      case ETHTYPE_IP:
+      case ETHTYPE_ARP:
+      #if PPPOE_SUPPORT
+      /* PPPoE packet? */
+      case ETHTYPE_PPPOEDISC:
+      case ETHTYPE_PPPOE:
+      #endif /* PPPOE_SUPPORT */
+      /* full packet send to tcpip_thread to process */
+        //if (netif->input(p, gnetif)!=ERR_OK)
+        if (ethernet_input(frame, eth_netif)!=ERR_OK)
+        { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
+          pbuf_free(frame);
+          frame = NULL;
+        }
+        break;
+
+      default:
+        pbuf_free(frame);
+        frame = NULL;
+        break;
+      }
+      
+      /* pbuf_free(frame); */
+  }
+
+  
+ 
+  
+}
+
+err_t eth_init(struct netif *netif) {
+  LWIP_ASSERT("netif != NULL", (netif != NULL));
+  
+  NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 0x2EA);
+  
+  /* maximum transfer unit */
+  netif->mtu = 0x2EA;
+  
+  /* device capabilities */
+  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
+  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_IGMP;
+
+  netif->state = NULL;
+  eth_netif = netif;
+
+  netif->name[0] = IFNAME0;
+  netif->name[1] = IFNAME1;
+
+  /* We directly use etharp_output() here to save a function call.
+   * You can instead declare your own function an call etharp_output()
+   * from it if you have to do some checks before sending (e.g. if link
+   * is available...) */
+  netif->output          = etharp_output;
+  netif->linkoutput      = eth_output;
+
+  if (!pEth) pEth = new Ethernet(); // only create Ethernet object if required
+
+  return ERR_OK;
+}
+
+void eth_free()
+{
+  if(pEth)
+    delete pEth;
+  pEth = NULL;
+}
+
+void eth_address(char* mac) {
+    pEth->address(mac);
+}
+
+Ethernet* eth_interface() {
+    return pEth;
+}    
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/eth/eth_drv.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/eth/eth_drv.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,41 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef ETHDRV_H
+#define ETHDRV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void eth_poll();
+err_t eth_init(struct netif* netif);
+void eth_address(char* mac);
+void eth_free();
+Ethernet* eth_interface();
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/gprs/GPRSModem.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/gprs/GPRSModem.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,292 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "GPRSModem.h"
+#include "mbed.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#define WAIT_BTW_NETW_POLLS 3.
+
+#include "netCfg.h"
+#if NET_GPRS
+
+GPRSModem::GPRSModem() : ATIf()
+{
+  DBG("New GPRSModem@%p\n", this);
+}
+
+GPRSModem::~GPRSModem()
+{
+
+}
+  
+GPRSErr GPRSModem::getNetworkState()
+{
+  ATIf::flushBuffer();
+  /*
+  netState can be : (Telit_AT_Reference_Guide.pdf p.98)
+  0 - not registered, ME is not currently searching a new operator to register to
+  1 - registered, home network
+  2 - not registered, but ME is currently searching a new operator to register to
+  3 - registration denied
+  4 - unknown
+  5 - registered, roaming
+  */
+ // DBG("Network?...\r\n");
+  ATIf::setReadMode(false); //Discard chars
+  ATIf::setTimeout(10000);
+  ATIf::setLineMode(true); //Line mode
+  int netState = 0;
+  int len;
+  len = ATIf::printf("AT+CREG?"); //Registered ?
+  if(!len) DBG("\r\nprintf - len=%d\r\n",len);
+  if(!len)
+    return GPRS_MODEM; //Nothing was actually sent
+    
+  len = ATIf::scanf("+CREG: 0,%d", &netState); //Get status
+  if(len != 1) DBG("\r\nscanf - len=%d\r\n",len);
+  if(len != 1) //Likely +CMS ERROR was returned
+    return GPRS_MODEM;
+
+  if( !!ATIf::checkOK() ) //Should not be a problem
+    {DBG("\r\nNOK\r\n"); return GPRS_MODEM; }
+    
+  switch(netState)
+  {
+  case 1:
+  case 5: //TODO: Option allow roaming
+    DBG("\r\nNetwork is up!\r\n");
+    return GPRS_OK;
+  case 3:
+    DBG("\r\nAccess to network denied.\r\n");
+    return GPRS_DENIED;
+  case 0:
+    DBG("\r\nNo network.\r\n");
+    return GPRS_NONETWORK;
+  case 4:
+  case 2:
+    //DBG("\r\nRegistering...\r\n");
+    return GPRS_REGISTERING;
+  }
+    
+  return GPRS_MODEM; // Should not reach this
+  
+}
+
+GPRSErr GPRSModem::setNetworkUp()
+{
+  ATIf::flushBuffer();
+  GPRSErr err = GPRS_REGISTERING;
+  while(true)
+  {
+    err = getNetworkState();
+    if(err != GPRS_REGISTERING)
+      break;
+    wait(WAIT_BTW_NETW_POLLS);
+  }
+  return err;
+}
+
+//Same, but for GPRS
+GPRSErr GPRSModem::getGPRSState()
+{
+  ATIf::flushBuffer();
+  /*
+  netState can be : (Telit_AT_Reference_Guide.pdf p.192)
+  0 - not registered, terminal is not currently searching a new operator to register to
+  1 - registered, home network
+  2 - not registered, but terminal is currently searching a new operator to register to
+  3 - registration denied
+  4 - unknown
+  5 - registered, roaming
+  */
+  
+  DBG("GPRS?...\r\n");
+  ATIf::setReadMode(false); //Discard chars
+  ATIf::setTimeout(10000);
+  ATIf::setLineMode(true); //Line mode
+  int netState = 0;
+  int len;
+  len = ATIf::printf("AT+CGREG?"); //Registered ?
+  if(!len)
+    return GPRS_MODEM; //Nothing was actually sent
+    
+  len = ATIf::scanf("+CGREG: %*d,%d", &netState); //Get GPRS status, see GSM 07.07 spec as Telit AT ref is wrong
+  if(len != 1) DBG("\r\nscanf - len=%d\r\n",len);
+  if(len != 1) //Likely +CMS ERROR was returned
+    return GPRS_MODEM;
+
+  if( !!ATIf::checkOK() ) //Should not be a problem
+    return GPRS_MODEM;
+    
+  switch(netState)
+  {
+  case 1:
+  case 5: //TODO: Option allow roaming
+    DBG("\r\nNetwork is up!\r\n");
+    return GPRS_OK;
+  case 3:
+    DBG("\r\nAccess to network denied.\r\n");
+    return GPRS_DENIED;
+  case 0:
+    DBG("\r\nNo network.\r\n");
+    return GPRS_NONETWORK;
+  case 4:
+  case 2:
+    DBG("\r\nRegistering...\r\n");
+    return GPRS_REGISTERING;
+  }
+    
+  return GPRS_MODEM; // Should not reach this
+  
+}
+
+GPRSErr GPRSModem::setGPRSUp()
+{
+  ATIf::flushBuffer();
+  GPRSErr err;
+  
+  err = setNetworkUp();
+  if(err)
+    return err;
+  
+  DBG("\r\nAttaching GPRS...\r\n");
+  ATIf::setReadMode(false); //Discard chars
+  ATIf::setTimeout(10000);
+  ATIf::setLineMode(true); //Line mode
+  int len;  
+  
+  err = getGPRSState();
+  if(err == GPRS_NONETWORK)
+  {  
+    len = ATIf::printf("AT+CGATT=1"); //Attach
+    if(!len)
+      return GPRS_MODEM; //Nothing was actually sent  
+
+    if( !!ATIf::checkOK() ) //Should not be a problem
+      return GPRS_MODEM;
+  }
+  
+  while(true)
+  {
+    err = getGPRSState();
+    if(err != GPRS_REGISTERING)
+      break;
+    wait(WAIT_BTW_NETW_POLLS);
+  }
+  return err;
+}
+
+GPRSErr GPRSModem::setGPRSDown()
+{ 
+  ATIf::flushBuffer();
+  DBG("\r\nDetaching GPRS...\r\n");
+  ATIf::setReadMode(false); //Discard chars
+  ATIf::setTimeout(10000);
+  ATIf::setLineMode(true); //Line mode
+  int len;
+  
+  len = ATIf::printf("AT+CGATT=0"); //Detach
+  if(!len)
+    return GPRS_MODEM; //Nothing was actually sent  
+
+  if( !!ATIf::checkOK() ) //Should not be a problem
+    return GPRS_MODEM;
+ 
+  return GPRS_OK;
+}
+
+  
+GPRSErr GPRSModem::connect(const char* apn /*=NULL*/)
+{
+  ATIf::flushBuffer();
+  GPRSErr err;
+    
+  ATIf::setReadMode(false); //Discard chars
+  ATIf::setTimeout(5000);
+  ATIf::setLineMode(true); //Line mode
+  
+  DBG("\r\nConnecting...\r\n");  
+  
+  int len;
+  
+  if( apn != NULL ) //Config APN
+  {
+    len = ATIf::printf("AT+CGDCONT=1,\"IP\",\"%s\"",apn); //Define APN
+    if(!len)
+      return GPRS_MODEM; //Nothing was actually sent
+
+    if( !!ATIf::checkOK() ) //Should not be a problem
+      return GPRS_MODEM;
+  }
+    
+  err = setGPRSUp();
+  if(err)
+    return err;
+    
+  ATIf::setReadMode(false); //Discard chars
+  ATIf::setTimeout(60000);
+  ATIf::setLineMode(true); //Line mode
+  //
+  //len = ATIf::printf("AT+CGDATA=\"PPP\",1"); //Connect using PDP context #1
+//  len = ATIf::printf("ATDT *99***1#");
+  len = ATIf::printf("ATDT *99#");
+  if(!len)
+    return GPRS_MODEM; //Nothing was actually sent
+    
+  len = ATIf::scanf("CONNECT"); //Beginning of session
+  if(len != 0) //Likely +CME ERROR was returned or NO CARRIER
+    return GPRS_MODEM;
+    
+  //ATIf::setSignals(false);
+  
+  DBG("\r\nConnected.\r\n");
+    
+  return GPRS_OK; //Time to enter a PPP Session !   
+  
+}
+
+GPRSErr GPRSModem::disconnect()
+{
+  ATIf::flushBuffer();
+  ATIf::setReadMode(false); //Discard chars
+  ATIf::setTimeout(5000);
+  ATIf::setLineMode(true); //Line mode
+  
+  if( !!ATIf::checkOK() ) //Should be present at the end of connection
+    return GPRS_MODEM;
+  
+  GPRSErr err;  
+  err = setGPRSDown();
+  if(err)
+    return err;
+    
+  DBG("\r\nDisconnected.\r\n");
+    
+  return GPRS_OK;
+}
+
+#endif
+
diff -r 000000000000 -r 350011bf8be7 drv/gprs/GPRSModem.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/gprs/GPRSModem.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,57 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef GPRSMODEM_H
+#define GPRSMODEM_H
+
+#include "drv/at/ATIf.h"
+
+enum GPRSErr
+{
+  __GPRS_MIN = -0xFFFF,
+  GPRS_MODEM, //ATErr returned
+  GPRS_DENIED,
+  GPRS_NONETWORK,
+  GPRS_REGISTERING,
+  GPRS_OK = 0
+};
+
+class GPRSModem : public ATIf
+{
+public:
+  GPRSModem();
+  virtual ~GPRSModem();
+  
+  GPRSErr getNetworkState();
+  GPRSErr setNetworkUp();
+  
+  GPRSErr getGPRSState();
+  GPRSErr setGPRSUp();
+  GPRSErr setGPRSDown();
+  
+  GPRSErr connect(const char* apn = NULL);
+  GPRSErr disconnect();
+  
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/gprsmodule/TelitModule.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/gprsmodule/TelitModule.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,100 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "TelitModule.h"
+
+#include "mbed.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#include "netCfg.h"
+#if NET_GPRS_MODULE
+
+TelitModule::TelitModule(PinName pwrSetPin, PinName pwrMonPin) : m_pwrSetPin(pwrSetPin), m_pwrMonPin(pwrMonPin)
+{
+  //m_pwrSetPin.write(0);
+
+  //m_pwrMonPin.mode(PullDown);
+}
+
+TelitModule::~TelitModule() {
+
+}
+
+bool TelitModule::isOn() //True if on
+{ 
+  return m_pwrMonPin.read();
+}
+
+bool TelitModule::on() //True if OK
+{ 
+  Timer tmr;
+  if(!m_pwrMonPin.read()){
+    //On
+    DBG("Switching On...\n");
+    m_pwrSetPin.write(1);
+    wait(1.);
+    m_pwrSetPin.write(0);
+       
+    tmr.start();
+    while(!m_pwrMonPin.read())
+    {
+      wait(.001);
+      if(tmr.read() > 2)
+      { 
+         DBG("ERROR - MUST RESET MODULE\n");
+         break;
+      }
+    }
+    tmr.stop();
+  }
+  wait(.1);
+  return m_pwrMonPin.read();
+}
+
+bool TelitModule::off() { //True if OK
+  Timer tmr;
+  if(m_pwrMonPin.read()){
+    //Off
+    DBG("Switching Off...\n");
+    m_pwrSetPin.write(1);
+    wait(3.);
+    m_pwrSetPin.write(0);
+      DBG("Waiting....\n"); 
+    tmr.start();
+    while(m_pwrMonPin.read())
+    {
+      wait(.001);
+      if(tmr.read() > 15)
+      { 
+         DBG("ERROR - MUST RESET MODULE\n");
+         break;
+      }
+    }
+    tmr.stop();
+  }
+  return !m_pwrMonPin.read();
+}
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/gprsmodule/TelitModule.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/gprsmodule/TelitModule.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,47 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef TELITMODULE_H
+#define TELITMODULE_H
+
+#include "mbed.h"
+
+class TelitModule
+{
+public:
+  TelitModule(PinName pwrSetPin, PinName pwrMonPin);
+  ~TelitModule();
+  
+  bool isOn(); //True if on
+  bool on(); //True if OK
+  bool off(); //True if OK
+  
+protected:
+ 
+private:
+  DigitalOut m_pwrSetPin;
+  DigitalIn m_pwrMonPin;
+
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/serial/buf/SerialBuf.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/serial/buf/SerialBuf.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,235 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "SerialBuf.h"
+#include "mbed.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#include "netCfg.h"
+#if NET_GPRS
+
+#if NET_USB_SERIAL
+#define m_pStream( a ) (m_pSerial?m_pSerial->a:m_pUsbSerial->a)
+#else
+#define m_pStream( a ) (m_pSerial->a)
+#endif
+
+//Circular buf
+
+SerialCircularBuf::SerialCircularBuf(int len) : m_readMode(false)
+{
+  m_buf = new char[len];
+  m_len = len;
+  m_pReadStart = m_pRead = m_buf;
+  m_pWrite = m_buf;
+} 
+
+SerialCircularBuf::~SerialCircularBuf()
+{
+  if(m_buf)
+    delete[] m_buf;
+}
+
+int SerialCircularBuf::room() //Return room available in buf
+{
+  //return m_len - len() - 1; //-1 is to avoid loop
+  if ( m_pReadStart > m_pWrite )
+    return ( m_pReadStart - m_pWrite - 1 );
+  else
+    return m_len - ( m_pWrite - m_pReadStart ) - 1;
+}
+
+int SerialCircularBuf::len() //Return chars length in buf
+{
+  if ( m_pWrite >= m_pRead )
+    return ( m_pWrite - m_pRead );
+  else
+    return m_len - ( m_pRead - m_pWrite ); // = ( ( m_buf + m_len) - m_pRead ) + ( m_pWrite - m_buf )
+}
+
+void SerialCircularBuf::write(char c)
+{
+#if 0
+  if(!room())
+    return;
+#endif
+  //WARN: Must call room() before
+  *m_pWrite = c;
+  m_pWrite++;
+  if(m_pWrite>=m_buf+m_len)
+    m_pWrite=m_buf;
+}
+char SerialCircularBuf::read()
+{
+#if 0
+  if(!len())
+    return 0;
+#endif
+  //WARN: Must call len() before
+  char c = *m_pRead;
+  m_pRead++;
+  
+  if(m_pRead>=m_buf+m_len)
+    m_pRead=m_buf;
+    
+  if(!m_readMode) //If readmode=false, trash this char
+    m_pReadStart=m_pRead;
+    
+  return c;
+}
+
+void SerialCircularBuf::setReadMode(bool readMode) //If true, keeps chars in buf when read, false by default
+{
+  if(m_readMode == true && readMode == false)
+  {
+    //Trash bytes that have been read
+    flushRead();
+  }
+  m_readMode = readMode;
+}
+
+void SerialCircularBuf::flushRead() //Delete chars that have been read & return chars len (only useful with readMode = true)
+{
+  m_pReadStart = m_pRead;
+}
+
+void SerialCircularBuf::resetRead() //Go back to initial read position & return chars len (only useful with readMode = true)
+{
+  m_pRead = m_pReadStart;
+}
+
+//SerialBuf
+
+SerialBuf::SerialBuf(int len) : m_rxBuf(len), m_txBuf(len), m_pSerial(NULL) //Buffer length
+#if NET_USB_SERIAL
+, m_pUsbSerial(NULL) 
+#endif
+{
+  DBG("New Serial buf@%p\n", this);
+}
+
+SerialBuf::~SerialBuf()
+{
+
+}
+
+void SerialBuf::attach(Serial* pSerial)
+{
+  DBG("Serial buf@%p in attach\n", this);
+  m_pSerial = pSerial;
+  m_pSerial->attach<SerialBuf>(this, &SerialBuf::onRxInterrupt, Serial::RxIrq);
+  m_pSerial->attach<SerialBuf>(this, &SerialBuf::onTxInterrupt, Serial::TxIrq);
+  onRxInterrupt(); //Read data
+}
+
+void SerialBuf::detach()
+{
+  if(m_pSerial)
+  {
+    m_pSerial->attach<SerialBuf>(NULL, NULL, Serial::RxIrq);
+    m_pSerial->attach<SerialBuf>(NULL, NULL, Serial::TxIrq);
+    m_pSerial = NULL;
+  }
+  #if NET_USB_SERIAL
+  else if(m_pUsbSerial)
+  {
+    m_pUsbSerial->attach<SerialBuf>(NULL, NULL, UsbSerial::RxIrq);
+    m_pUsbSerial->attach<SerialBuf>(NULL, NULL, UsbSerial::TxIrq);
+    m_pUsbSerial = NULL;
+  }
+  #endif
+}
+
+#if NET_USB_SERIAL
+void SerialBuf::attach(UsbSerial* pUsbSerial)
+{
+  m_pUsbSerial = pUsbSerial;
+  m_pUsbSerial->attach<SerialBuf>(this, &SerialBuf::onRxInterrupt, UsbSerial::RxIrq);
+  m_pUsbSerial->attach<SerialBuf>(this, &SerialBuf::onTxInterrupt, UsbSerial::TxIrq);
+  onRxInterrupt(); //Read data
+}
+#endif
+
+char SerialBuf::getc()
+{
+  while(!readable());
+  char c = m_rxBuf.read();
+  return c;
+}
+
+void SerialBuf::putc(char c)
+{
+  while(!writeable());
+  m_txBuf.write(c);
+  onTxInterrupt();
+}
+
+bool SerialBuf::readable()
+{
+  if( !m_rxBuf.len() ) //Fill buf if possible
+    onRxInterrupt();
+  return (m_rxBuf.len() > 0);
+}
+
+bool SerialBuf::writeable()
+{
+  if( !m_txBuf.room() ) //Free buf is possible
+    onTxInterrupt();
+  return (m_txBuf.room() > 0);
+}
+
+void SerialBuf::setReadMode(bool readMode) //If true, keeps chars in buf when read, false by default
+{
+  m_rxBuf.setReadMode(readMode);
+}
+
+void SerialBuf::flushRead() //Delete chars that have been read & return chars len (only useful with readMode = true)
+{
+  m_rxBuf.flushRead();
+}
+
+void SerialBuf::resetRead() //Go back to initial read position & return chars len (only useful with readMode = true)
+{
+  m_rxBuf.resetRead();
+}
+
+void SerialBuf::onRxInterrupt() //Callback from m_pSerial
+{
+  while( m_rxBuf.room() && m_pStream(readable()) )
+  {
+    m_rxBuf.write(m_pStream(getc()));
+  }
+}
+
+void SerialBuf::onTxInterrupt() //Callback from m_pSerial
+{
+  while( m_txBuf.len() && m_pStream(writeable()) )
+  {
+    m_pStream(putc(m_txBuf.read()));
+  }
+}
+
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/serial/buf/SerialBuf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/serial/buf/SerialBuf.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,99 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef SERIALBUF_H
+#define SERIALBUF_H
+
+#include "mbed.h"
+#include "netCfg.h"
+#if NET_USB_SERIAL
+#include "drv/serial/usb/UsbSerial.h"
+#endif
+
+class SerialCircularBuf
+{
+public:
+  SerialCircularBuf(int len);  
+  ~SerialCircularBuf();
+  
+  int room();
+  int len();
+  
+  void write(char c);
+  char read();
+  
+  void setReadMode(bool readMode); //If true, keeps chars in buf when read, false by default
+  void flushRead(); //Delete chars that have been read & return chars len (only useful with readMode = true)
+  void resetRead(); //Go back to initial read position & return chars len (only useful with readMode = true)
+  
+private:
+  char* m_buf;
+  int m_len;
+  
+  volatile char* m_pReadStart;
+  volatile char* m_pRead;
+  volatile char* m_pWrite;
+  volatile bool m_readMode;
+};
+
+class SerialBuf
+{
+public:
+  SerialBuf(int len); //Buffer length
+  virtual ~SerialBuf();
+  
+  void attach(Serial* pSerial);
+  void detach();
+  
+  #if NET_USB_SERIAL
+  void attach(UsbSerial* pUsbSerial);
+  #endif
+  
+  //Really useful for debugging
+  char getc();    
+  void putc(char c);
+  bool readable();
+  bool writeable();
+/*protected:*/
+  void setReadMode(bool readMode); //If true, keeps chars in buf when read, false by default
+  void flushRead(); //Delete chars that have been read & return chars len (only useful with readMode = true)
+  void resetRead(); //Go back to initial read position & return chars len (only useful with readMode = true)
+  
+private:
+  void onRxInterrupt(); //Callback from m_pSerial
+  void onTxInterrupt(); //Callback from m_pSerial
+    
+  SerialCircularBuf m_rxBuf;
+  SerialCircularBuf m_txBuf;
+
+  Serial* m_pSerial; //Not owned
+
+  #if NET_USB_SERIAL
+  //USB Serial Impl
+  UsbSerial* m_pUsbSerial; //Not owned
+  //Ticker m_usbTick;
+  #endif
+};
+
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/serial/lwip/sio.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/serial/lwip/sio.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,202 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+
+This is a wrapper around Serial if for lwIP (acts as a serial driver)
+
+See sio.h for functions to be implemented
+
+sio_fd_t is a void* defined type, we use it as a SerialBuf ptr
+
+
+
+*/
+
+
+#include "netCfg.h"
+#if NET_PPP
+
+//#define MAX_SERIAL_PORTS 8
+
+#include "lwip/sio.h"
+#include "mbed.h"
+//#include "sioMgr.h"
+#include "drv/serial/buf/SerialBuf.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+//extern "C" {
+
+/**
+ * Opens a serial device for communication.
+ * 
+ * @param devnum device number
+ * @return handle to serial device if successful, NULL otherwise
+ */
+sio_fd_t sio_open(u8_t devnum)
+{
+#if 0
+  SerialBuf* pIf = SioMgr::getIf(devnum);
+  if(pIf == NULL)
+    return NULL;
+    
+  //Got a SerialBuf* object
+  //WARN: It HAS to be initialised (instanciated + attached to a Serial obj)
+  
+  return (sio_fd_t) pIf;
+  #endif
+  return NULL;
+}
+
+/**
+ * Sends a single character to the serial device.
+ * 
+ * @param c character to send
+ * @param fd serial device handle
+ * 
+ * @note This function will block until the character can be sent.
+ */
+void sio_send(u8_t c, sio_fd_t fd)
+{
+  SerialBuf* pIf = (SerialBuf*) fd;
+  //while(!pIf->writeable());
+  pIf->putc( (char) c );
+}
+
+/**
+ * Receives a single character from the serial device.
+ * 
+ * @param fd serial device handle
+ * 
+ * @note This function will block until a character is received.
+ */
+u8_t sio_recv(sio_fd_t fd)
+{
+  SerialBuf* pIf = (SerialBuf*) fd;
+  pIf->setReadMode(false);
+  while(!pIf->readable());
+  return (u8_t) pIf->getc();
+}
+
+/**
+ * Reads from the serial device.
+ * 
+ * @param fd serial device handle
+ * @param data pointer to data buffer for receiving
+ * @param len maximum length (in bytes) of data to receive
+ * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
+ * 
+ * @note This function will block until data can be received. The blocking
+ * can be cancelled by calling sio_read_abort().
+ */
+static volatile bool m_abort = false;
+u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)
+{
+  u32_t recvd = 0; //bytes received
+  SerialBuf* pIf = (SerialBuf*) fd;
+  pIf->setReadMode(false);
+  while(!m_abort && len)
+  {
+    while(!pIf->readable());
+    *data = (u8_t) pIf->getc();
+    data++;
+    len--;
+    recvd++;
+  }
+  m_abort = false;
+  return recvd;
+}
+
+/**
+ * Tries to read from the serial device. Same as sio_read but returns
+ * immediately if no data is available and never blocks.
+ * 
+ * @param fd serial device handle
+ * @param data pointer to data buffer for receiving
+ * @param len maximum length (in bytes) of data to receive
+ * @return number of bytes actually received
+ */
+u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len)
+{
+  u32_t recvd = 0; //bytes received
+  SerialBuf* pIf = (SerialBuf*) fd;
+  pIf->setReadMode(false);
+  while(len)
+  {
+   /* if(!pIf->readable())
+    {
+      wait_ms(4);
+    }*/
+    if(!pIf->readable())
+    {
+      return recvd;
+    }
+    *data = (u8_t) pIf->getc();
+    data++;
+    len--;
+    recvd++;
+  }
+  return recvd;
+}
+
+/**
+ * Writes to the serial device.
+ * 
+ * @param fd serial device handle
+ * @param data pointer to data to send
+ * @param len length (in bytes) of data to send
+ * @return number of bytes actually sent
+ * 
+ * @note This function will block until all data can be sent.
+ */
+u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)
+{
+  u32_t sent = 0; //bytes sent
+  SerialBuf* pIf = (SerialBuf*) fd;
+  while(len)
+  {
+    while(!pIf->writeable());
+    pIf->putc(*data);
+    data++;
+    len--;
+    sent++;
+  }
+  return sent; //Well, this is bound to be len if no interrupt mechanism
+}
+
+/**
+ * Aborts a blocking sio_read() call.
+ * 
+ * @param fd serial device handle
+ */
+void sio_read_abort(sio_fd_t fd)
+{
+  m_abort = true;
+}
+
+//}
+
+#endif
+
diff -r 000000000000 -r 350011bf8be7 drv/serial/lwip/sioMgr.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/serial/lwip/sioMgr.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,49 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#if 0 //Dep 
+
+#include "sioMgr.h"
+
+
+u8_t SioMgr::m_count=0;
+SerialBuf* SioMgr::m_pSerialBufList[MAX_SERIAL_PORTS] = {NULL};
+
+u8_t SioMgr::registerSerialIf(SerialBuf* pIf)
+{
+  if(m_count==MAX_SERIAL_PORTS)
+    return 0;
+    
+  m_pSerialBufList[m_count] = pIf;
+  m_count++;
+  
+  return m_count; //We do not want a fd to be NULL, so return value is p+1
+}
+  
+SerialBuf* SioMgr::getIf(u8_t item)
+{
+  if (!item || item > m_count)
+    return NULL;
+    
+  return m_pSerialBufList[item-1];
+}
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/serial/lwip/sioMgr.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/serial/lwip/sioMgr.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,50 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#if 0 //Dep
+#ifndef SIOMGR_H
+#define SIOMGR_H
+
+#include "drv/serial/buf/SerialBuf.h"
+
+typedef unsigned char u8_t;
+#define MAX_SERIAL_PORTS 8
+
+//Helps to make the link btw SerialBuf classes and lwIP fd based system
+//See sio.cpp
+
+class SioMgr
+{
+public:
+  
+  static u8_t registerSerialIf(SerialBuf* pIf);
+  static SerialBuf* getIf(u8_t item);
+  
+private:
+
+  static SerialBuf* m_pSerialBufList[MAX_SERIAL_PORTS];
+  static u8_t m_count;
+  
+};
+
+#endif
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/serial/usb/UsbSerial.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/serial/usb/UsbSerial.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,300 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "rpc.h"
+
+#include "UsbSerial.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#include "netCfg.h"
+#if NET_USB_SERIAL
+
+namespace mbed {
+
+#define BUF_LEN 64
+#define FLUSH_TMOUT 100000 //US
+
+UsbSerial::UsbSerial(UsbDevice* pDevice, int epIn, int epOut, const char* name /*= NULL*/) : Stream(name), m_epIn(pDevice, epIn, true, USB_BULK, BUF_LEN), m_epOut(pDevice, epOut, false, USB_BULK, BUF_LEN),
+m_pInCbItem(NULL), m_pInCbMeth(NULL), m_pOutCbItem(NULL), m_pOutCbMeth(NULL)
+{ 
+  m_inBufEven = new char[BUF_LEN];
+  m_inBufOdd = new char[BUF_LEN];
+  m_pInBufPos = m_inBufUsr = m_inBufEven;
+  m_inBufTrmt = m_inBufOdd;
+  
+  m_outBufEven = new char[BUF_LEN];
+  m_outBufOdd = new char[BUF_LEN];
+  m_pOutBufPos = m_outBufUsr = m_outBufEven;
+  m_outBufTrmt = m_outBufOdd;
+  
+  m_inBufLen = m_outBufLen = 0;
+  
+  DBG("Starting RX'ing on in ep\n");
+  
+  m_timeout = false;
+  
+  m_epIn.setOnCompletion(this, &UsbSerial::onEpInTransfer);
+  m_epOut.setOnCompletion(this, &UsbSerial::onEpOutTransfer);
+  
+  startRx();
+}
+
+UsbSerial::~UsbSerial()
+{
+  delete[] m_inBufEven;
+  delete[] m_inBufOdd;
+  delete[] m_outBufEven;
+  delete[] m_outBufOdd;
+}
+
+void UsbSerial::baud(int baudrate) { 
+    //
+}
+
+void UsbSerial::format(int bits, int parity, int stop) { 
+  //
+} 
+
+#if 0 //For doc only
+template <class T>
+void attach(T* pCbItem, void (T::*pCbMeth)())
+{
+  m_pCbItem = (CDummy*) pCbItem;
+  m_pCbMeth = (void (CDummy::*)()) pCbMeth;
+}
+#endif
+
+int UsbSerial::_getc() { 
+    NVIC_DisableIRQ(US_TICKER_TIMER_IRQn);
+    NVIC_DisableIRQ(USB_IRQn);
+    char c;
+    c = *m_pInBufPos;
+    m_pInBufPos++;
+    NVIC_EnableIRQ(USB_IRQn);
+    NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
+    return c;
+}
+
+int UsbSerial::_putc(int c) { 
+    NVIC_DisableIRQ(US_TICKER_TIMER_IRQn);
+    NVIC_DisableIRQ(USB_IRQn);
+    if( (m_pOutBufPos - m_outBufUsr) < BUF_LEN )
+    {
+      *m_pOutBufPos = (char) c;
+      m_pOutBufPos++;
+    }
+    else
+    {
+      DBG("NO WAY!!!\n");
+    }
+    #if 1
+    if( (m_pOutBufPos - m_outBufUsr) >= BUF_LEN ) //Must flush
+    {
+      if(m_timeout)
+        m_txTimeout.detach();
+      startTx();
+    }
+    else
+    {
+      /*if(m_timeout)
+        m_txTimeout.detach();
+      m_timeout = true;
+      m_txTimeout.attach_us(this, &UsbSerial::startTx, FLUSH_TMOUT);*/
+      if(!m_timeout)
+      {
+        m_timeout = true;
+        m_txTimeout.attach_us(this, &UsbSerial::startTx, FLUSH_TMOUT);
+      }
+    }
+    #endif
+    //startTx();
+    NVIC_EnableIRQ(USB_IRQn);
+    NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
+    return c;
+}
+
+int UsbSerial::readable() { 
+    NVIC_DisableIRQ(US_TICKER_TIMER_IRQn);
+    NVIC_DisableIRQ(USB_IRQn);
+    int res;
+    if( (m_pInBufPos - m_inBufUsr) < m_inBufLen )
+    {
+      //DBG("\r\nREADABLE\r\n");
+      res = true;
+    }
+    else
+    {
+      //DBG("\r\nNOT READABLE\r\n");
+      startRx(); //Try to swap packets & start another transmission
+      res = ((m_pInBufPos - m_inBufUsr) < m_inBufLen )?true:false;
+    }
+    NVIC_EnableIRQ(USB_IRQn);
+    NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
+    return (bool)res;
+}
+
+int UsbSerial::writeable() { 
+    NVIC_DisableIRQ(US_TICKER_TIMER_IRQn);
+    NVIC_DisableIRQ(USB_IRQn);
+  //  DBG("\r\nWRITEABLE???\r\n");
+    int res = (bool)( (m_pOutBufPos - m_outBufUsr) < BUF_LEN);
+    NVIC_EnableIRQ(USB_IRQn);
+    NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
+    return res;
+}
+
+void UsbSerial::onReadable()
+{
+  if(m_pInCbItem && m_pInCbMeth)
+    (m_pInCbItem->*m_pInCbMeth)();
+}
+
+void UsbSerial::onWriteable()
+{
+  if(m_pOutCbItem && m_pOutCbMeth)
+    (m_pOutCbItem->*m_pOutCbMeth)();
+}
+
+void UsbSerial::onEpInTransfer()
+{
+  int len = m_epIn.status();
+  DBG("RX transfer completed w len=%d\n",len);
+  startRx();
+  if(len > 0)
+    onReadable();
+}
+
+void UsbSerial::onEpOutTransfer()
+{
+  int len = m_epOut.status();
+  DBG("TX transfer completed w len=%d\n",len);
+  if(m_timeout)
+    m_txTimeout.detach();
+  startTx();
+  if(len > 0)
+    onWriteable();
+}
+
+void UsbSerial::startTx()
+{
+  
+  DBG("Transfer>\n");
+  
+  m_timeout = false;
+  
+//  m_txTimeout.detach();
+   
+  if(!(m_pOutBufPos - m_outBufUsr))
+  {
+    DBG("?!?!?\n");
+    return;
+  }
+  
+  if( m_epOut.status() == USBERR_PROCESSING )
+  {
+    //Wait & retry
+    //m_timeout = true;
+    //m_txTimeout.attach_us(this, &UsbSerial::startTx, FLUSH_TMOUT);
+    DBG("Ep is busy...\n");
+    return;
+  }
+  
+  if( m_epOut.status() < 0 )
+  {
+    DBG("Tx trying again...\n");
+    m_epOut.transfer((volatile uint8_t*)m_outBufTrmt, m_outBufLen);
+    return;
+  }
+
+  m_outBufLen = m_pOutBufPos - m_outBufUsr;
+  
+  //Swap buffers
+  volatile char* swapBuf = m_outBufUsr;
+  m_outBufUsr = m_outBufTrmt;
+  m_outBufTrmt = swapBuf;
+  
+  m_epOut.transfer((volatile uint8_t*)m_outBufTrmt, m_outBufLen);
+  
+  m_pOutBufPos = m_outBufUsr;
+
+}
+
+void UsbSerial::startRx()
+{
+  if( (m_pInBufPos - m_inBufUsr) < m_inBufLen )
+  {
+    //User buf is not empty, cannot swap now...
+    return;
+  }
+  int len = m_epIn.status();
+  if( len == USBERR_PROCESSING )
+  {
+    //Previous transmission not completed
+    return;
+  }
+  if( len < 0 )
+  {
+    DBG("Rx trying again...\n");
+    m_epIn.transfer((volatile uint8_t*)m_inBufTrmt, BUF_LEN); //Start another transmission
+    return;
+  }
+  
+  m_inBufLen = len;
+  
+  //Swap buffers
+  volatile char* swapBuf = m_inBufUsr;
+  m_inBufUsr =  m_inBufTrmt;
+  m_inBufTrmt = swapBuf;
+  m_pInBufPos = m_inBufUsr;
+  
+  DBG("Starting new transfer\n");
+  m_epIn.transfer((volatile uint8_t*)m_inBufTrmt, BUF_LEN); //Start another transmission
+  
+}
+
+#ifdef MBED_RPC
+const struct rpc_method *UsbSerial::get_rpc_methods() { 
+    static const rpc_method methods[] = {
+        { "readable", rpc_method_caller<int, UsbSerial, &UsbSerial::readable> },
+        { "writeable", rpc_method_caller<int, UsbSerial, &UsbSerial::writeable> },
+        RPC_METHOD_SUPER(Stream)
+    };
+    return methods;
+}
+
+struct rpc_class *UsbSerial::get_rpc_class() {
+    static const rpc_function funcs[] = {
+        /*{ "new", rpc_function_caller<const char*, UsbDevice*, int, int, const char*, Base::construct<UsbSerial,UsbDevice*,int,int,const char*> > },*/ //RPC is buggy
+        RPC_METHOD_END
+    };
+    static rpc_class c = { "UsbSerial", funcs, NULL };
+    return &c;
+}
+#endif
+
+} // namespace mbed
+
+#endif
+
diff -r 000000000000 -r 350011bf8be7 drv/serial/usb/UsbSerial.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/serial/usb/UsbSerial.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,189 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef USB_SERIAL_H
+#define USB_SERIAL_H
+
+//DG 2010
+//Essentially a clone of Serial if
+#include "Stream.h"
+#include "mbed.h"
+
+#include "drv/usb/UsbDevice.h"
+#include "drv/usb/UsbEndpoint.h"
+
+namespace mbed {
+
+class UsbSerial : public Stream {
+
+public:
+
+    UsbSerial(UsbDevice* pDevice, int epIn, int epOut, const char* name = NULL);
+    virtual ~UsbSerial();
+    //Apart from the ctor/dtor, exactly the same protos as Serial
+
+    void baud(int baudrate);
+
+    enum Parity {
+        None = 0,
+        Odd = 1,
+        Even = 2,
+        Forced1 = 3,
+        Forced0 = 4
+    };
+    
+    enum IrqType {
+        RxIrq = 0
+        , TxIrq
+    };
+
+    void format(int bits, int parity, int stop); 
+    
+    class CDummy;
+    template <class T>
+    void attach(T* pCbItem, void (T::*pCbMeth)(), IrqType type = RxIrq)
+    {
+      if(type == RxIrq)
+      {
+        m_pInCbItem = (CDummy*) pCbItem;
+        m_pInCbMeth = (void (CDummy::*)()) pCbMeth;
+      }
+      else
+      {
+        m_pOutCbItem = (CDummy*) pCbItem;
+        m_pOutCbMeth = (void (CDummy::*)()) pCbMeth;
+      }
+    }
+    
+#if 0 // Inhereted from Stream, for documentation only
+
+    /* Function: putc
+     *  Write a character
+     *
+     * Variables:
+     *  c - The character to write to the serial port
+     */
+    int putc(int c);
+
+    /* Function: getc
+     *  Read a character
+     *
+     * Variables:
+     *  returns - The character read from the serial port
+     */
+    int getc();
+        
+    /* Function: printf
+     *  Write a formated string
+     *
+     * Variables:
+     *  format - A printf-style format string, followed by the 
+     *      variables to use in formating the string.
+     */
+    int printf(const char* format, ...);
+
+    /* Function: scanf
+     *  Read a formated string 
+     *
+     * Variables:
+     *  format - A scanf-style format string,
+     *      followed by the pointers to variables to store the results. 
+     */
+    int scanf(const char* format, ...);
+         
+#endif
+               
+    /* Function: readable
+     *  Determine if there is a character available to read
+     *
+     * Variables:
+     *  returns - 1 if there is a character available to read, else 0
+     */
+    int readable();
+
+    /* Function: writeable
+     *  Determine if there is space available to write a character
+     * 
+     * Variables:
+     *  returns - 1 if there is space to write a character, else 0
+     */
+    int writeable();    
+
+#ifdef MBED_RPC
+    virtual const struct rpc_method *get_rpc_methods();
+    static struct rpc_class *get_rpc_class();
+#endif
+    
+protected:
+
+    virtual int _getc();    
+    virtual int _putc(int c);
+    
+    void onReadable();
+    void onWriteable();
+    
+    void onEpInTransfer();
+    void onEpOutTransfer();
+    
+private:
+
+    UsbEndpoint m_epIn;
+    UsbEndpoint m_epOut;
+    
+    CDummy* m_pInCbItem;
+    void (CDummy::*m_pInCbMeth)();
+
+    CDummy* m_pOutCbItem;
+    void (CDummy::*m_pOutCbMeth)();
+
+    void startTx();
+    void startRx();
+    
+    Timeout m_txTimeout;
+    volatile bool m_timeout;
+
+    volatile char* m_inBufEven;    
+    volatile char* m_inBufOdd;
+    volatile char* m_inBufUsr;
+    volatile char* m_inBufTrmt;
+    
+    volatile char* m_outBufEven;
+    volatile char* m_outBufOdd;
+    volatile char* m_outBufUsr;
+    volatile char* m_outBufTrmt;
+    
+    volatile int m_inBufLen;
+    volatile int m_outBufLen;
+    
+    volatile char* m_pInBufPos;
+    volatile char* m_pOutBufPos;
+    
+    
+    
+};
+
+}
+
+
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/umtsstick/UMTSStick.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/umtsstick/UMTSStick.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,326 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "netCfg.h"
+#if NET_UMTS
+
+#include "UMTSStick.h"
+
+#define __DEBUG
+#include "dbg/dbg.h"
+
+UMTSStick::UMTSStick() : m_host(), m_pDev(NULL)
+{
+
+}
+
+UMTSStick::~UMTSStick()
+{
+
+}
+
+
+UMTSStickErr UMTSStick::getSerial(UsbSerial** ppUsbSerial)
+{
+  m_host.init();
+  
+  UMTSStickErr rc;
+  
+  rc = waitForDevice();
+  if(rc)
+    return rc;
+   
+  //Device is now enumerated, read table
+  
+  uint16_t vid = m_pDev->getVid();
+  uint16_t pid = m_pDev->getPid();
+  
+  DBG("Configuration set: vid:%04x pid:%04x\n", vid, pid);
+    
+  bool handled = false;
+  bool cdfs = false;
+  const UMTSSwitchingInfo* pInfo;
+  for(int i = 0; i < UMTS_SWITCHING_COUNT; i++)
+  {
+    pInfo = &UMTSwitchingTable[i];
+    if( !checkDeviceState(pInfo, &cdfs) )
+    {
+      handled = true;
+      break;
+    }
+    
+  } //for(int i = 0; i < UMTS_SWITCHING_COUNT; i++)
+  
+  if(!handled)
+  {
+    DBG("Don't know this device!\n");
+    return UMTSERR_NOTIMPLEMENTED;
+  }
+  
+  //Check if the device is in CDFS mode, in this case switch
+  if(cdfs)
+  {
+    DBG("Switching the device by sending a magic packet\n");
+  
+    rc = switchMode(pInfo);
+    if(rc)
+      return rc;
+      
+    DBG("Now wait for device to reconnect\n");
+    
+    m_host.releaseDevice(m_pDev);
+      
+    //Wait for device to reconnect
+    wait(3);
+    rc = waitForDevice();
+    if(rc)
+      return rc;
+  }
+  
+  rc = findSerial(ppUsbSerial);
+  if(rc)
+    return rc;
+  
+  return UMTSERR_OK;
+}
+
+UMTSStickErr UMTSStick::waitForDevice()
+{
+  bool ready = false;
+  while(!ready)
+  {
+    while(!m_host.devicesCount())
+    {}
+    wait(1);
+    if(m_host.devicesCount())
+      ready = true;
+  }
+  
+  wait(2); //Wait for device to be initialized
+  
+  if(!m_host.devicesCount())
+    return UMTSERR_DISCONNECTED;
+  
+  m_pDev = m_host.getDevice(0);
+  
+  while(!m_pDev->enumerated())
+  {
+    m_host.poll();
+    if(!m_host.devicesCount())
+      return UMTSERR_DISCONNECTED;
+  }
+   
+  return UMTSERR_OK;
+}
+
+UMTSStickErr UMTSStick::checkDeviceState(const UMTSSwitchingInfo* pInfo, bool* pCdfs)
+{
+  uint16_t vid = m_pDev->getVid();
+  uint16_t pid = m_pDev->getPid();
+  bool handled = false;
+  if( (vid == pInfo->cdfsVid) && (pid == pInfo->cdfsPid) )
+  {
+    DBG("Match on dongles list\n");
+    if( !pInfo->targetClass ) //No specific interface to check, vid/pid couple is specific to CDFS mode
+    {
+      DBG("Found device in CDFS mode\n");
+      handled = true;
+      *pCdfs = true;
+    }
+    else //if( !pInfo->targetClass )
+    {
+      //Has to check if there is an interface of class targetClass
+      byte* desc = NULL;
+      int c = 0;
+             
+      while( !m_pDev->getInterfaceDescriptor(1, c++, &desc) )
+      {
+        if( desc[5] == pInfo->targetClass )
+        {
+          DBG("Found device in Serial mode\n");
+          handled = true;
+          *pCdfs = false;
+          break;
+        }
+      }        
+      
+      if(!handled)
+      {
+        //All interfaces were tried, so we are in CDFS mode
+        DBG("Found device in CDFS mode\n");
+        handled = true;
+        *pCdfs = true;
+      }
+    } //if( !pInfo->targetClass )
+  } //if( (vid == pInfo->cdfsVid) && (pid == pInfo->cdfsPid) )
+  else
+  {
+    //Try every vid/pid couple of the serial list
+    for( int i = 0; i < 16 ; i++)
+    {
+      if(!pInfo->serialPidList[i])
+        break;
+      if( (pInfo->serialVid == vid) && (pInfo->serialPidList[i] == pid) )
+      {
+        DBG("Found device in Serial mode\n");
+        handled = true;
+        *pCdfs = false;
+        break;
+      }
+    }
+  } //if( (vid == pInfo->cdfsVid) && (pid == pInfo->cdfsPid) )
+  
+  if(!handled)
+    return UMTSERR_NOTFOUND;
+    
+  return UMTSERR_OK;
+}
+
+UMTSStickErr UMTSStick::switchMode(const UMTSSwitchingInfo* pInfo)
+{
+  if(!pInfo->huaweiPacket) //Send SCSI packet on first bulk ep
+  {
+    //Find first bulk ep           
+    byte* desc = NULL;
+    int c = 0;
+    
+    UsbEndpoint *pEpOut = NULL;
+       
+    while( !m_pDev->getInterfaceDescriptor(1, c++, &desc) )
+    {
+      byte* p = desc;
+      int epNum = 0;
+      p = p + p[0]; //Move to next descriptor (which should be an ep descriptor)
+      while (epNum < desc[4]) //Eps count in this if
+      {
+        if (p[1] != USB_DESCRIPTOR_TYPE_ENDPOINT)
+          break;
+        
+        if( (p[3] == 0x02) && !(p[2] & 0x80) ) //Bulk endpoint, out
+        {
+          DBG("Found bulk ep %02x\n", p[2]);
+          pEpOut = new UsbEndpoint( m_pDev, p[2], false, USB_BULK, *((uint16_t*)&p[4]) );
+          break;
+        }
+        
+        p = p + p[0]; //Move to next ep desc
+        epNum++;
+      }
+      if(pEpOut)
+        break;
+    }        
+    
+    if(!pEpOut)
+      return UMTSERR_NOTFOUND;
+      
+    //Send SCSI packet
+    
+    DBG("Sending SCSI Packet to switch\n");
+    byte ramCdfsBuf[31];
+    memcpy(ramCdfsBuf, pInfo->cdfsPacket, 31);
+    pEpOut->transfer((volatile byte*)ramCdfsBuf, 31);
+    while(pEpOut->status() == USBERR_PROCESSING);
+    int ret = pEpOut->status();
+    if((ret < 0) && (ret !=USBERR_DISCONNECTED)) //Packet was not transfered
+    {
+      DBG("Usb error %d\n", ret);
+      delete pEpOut;
+      return UMTSERR_USBERR;
+    }
+    
+    delete pEpOut;
+  }  
+  else
+  {
+    UsbErr usbErr;
+    //Send the Huawei-specific control packet
+    usbErr = m_pDev->controlSend(0, 0x03, 1, 0, NULL, 0);
+    if(usbErr && (usbErr != USBERR_DISCONNECTED))
+      return UMTSERR_USBERR;  
+  }
+  
+  DBG("The stick should be switching in serial mode now\n");
+  
+  return UMTSERR_OK;
+}
+
+UMTSStickErr UMTSStick::findSerial(UsbSerial** ppUsbSerial)
+{
+  byte* desc = NULL;
+  int c = 0;
+
+  int epOut = 0;
+  int epIn = 0;
+      
+  while( !m_pDev->getInterfaceDescriptor(1, c++, &desc) )
+  {
+    byte* p = desc;
+    int epNum = 0;
+    
+    DBG("Interface of type %02x\n", desc[5]);
+    
+    if(desc[5] != 0xFF) //Not a serial-like if
+      continue;
+    
+    p = p + p[0]; //Move to next descriptor (which should be an ep descriptor)
+    while (epNum < desc[4]) //Eps count in this if
+    {
+      if (p[1] == USB_DESCRIPTOR_TYPE_ENDPOINT)
+      {
+        if( (p[3] == 0x02) && !(p[2] & 0x80) && !epOut ) //Bulk endpoint, out
+        {
+          DBG("Found bulk out ep %02x of payload size %04x\n", p[2], *((uint16_t*)&p[4]));
+          epOut = p[2] & 0x7F;
+        }
+      
+        if( (p[3] == 0x02) && (p[2] & 0x80) && !epIn ) //Bulk endpoint, in
+        {
+          DBG("Found bulk in ep %02x of payload size %04x\n", p[2], *((uint16_t*)&p[4]));
+          epIn = p[2] & 0x7F;
+        }
+       
+        if(epOut && epIn)
+          break;
+      }
+      
+      p = p + p[0]; //Move to next ep desc
+      epNum++;
+    }
+    
+    if(epOut && epIn)
+      break;
+  }
+  
+  if(!epOut || !epIn)
+    return UMTSERR_NOTFOUND;
+    
+  DBG("Endpoints found, create serial object\n");
+    
+  *ppUsbSerial = new UsbSerial(m_pDev, epIn, epOut);
+  
+  DBG("UsbSerial object created\n");
+    
+  return UMTSERR_OK;
+}
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/umtsstick/UMTSStick.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/umtsstick/UMTSStick.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,87 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/** \file
+UMTS Stick driver header file
+*/
+
+#ifndef UMTS_STICK_H
+#define UMTS_STICK_H
+
+#include "mbed.h"
+
+#include "drv/usb/UsbHostMgr.h"
+#include "drv/usb/UsbDevice.h"
+#include "drv/usb/UsbEndpoint.h"
+
+#include "drv/serial/usb/UsbSerial.h"
+
+#define UMTS_SWITCHING_COUNT 2
+
+typedef unsigned char byte;
+
+struct UMTSSwitchingInfo
+{
+  uint16_t cdfsVid;
+  uint16_t cdfsPid;
+  uint16_t serialVid;
+  uint16_t serialPidList[16];
+  byte targetClass;
+  bool huaweiPacket;
+  byte cdfsPacket[31];
+};
+
+extern const UMTSSwitchingInfo UMTSwitchingTable[UMTS_SWITCHING_COUNT];
+
+///UMTS Stick error codes
+enum UMTSStickErr
+{
+  __UMTSERR_MIN = -0xFFFF,
+  UMTSERR_NOTFOUND, ///<Stick was not found
+  UMTSERR_NOTIMPLEMENTED, ///<This model is not implemented
+  UMTSERR_USBERR, ///<USB Error
+  UMTSERR_DISCONNECTED, ///<Stick disconnected
+  UMTSERR_OK = 0 ///<Success
+};
+
+class UMTSStick
+{
+public:
+  UMTSStick();
+  ~UMTSStick();
+  
+  UMTSStickErr getSerial(UsbSerial** ppUsbSerial);
+  
+private:
+  UMTSStickErr waitForDevice();
+  UMTSStickErr checkDeviceState(const UMTSSwitchingInfo* pInfo, bool* pCdfs);
+
+  UMTSStickErr switchMode(const UMTSSwitchingInfo* pInfo);
+  UMTSStickErr findSerial(UsbSerial** ppUsbSerial);
+  
+  
+  UsbHostMgr m_host;
+  UsbDevice* m_pDev;
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/umtsstick/UMTSStickData.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/umtsstick/UMTSStickData.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,24 @@
+#include "UMTSStick.h"
+
+const UMTSSwitchingInfo UMTSwitchingTable[UMTS_SWITCHING_COUNT] = {
+
+/*
+struct UMTSSwitchingInfo
+{
+  uint16_t cdfsVid;
+  uint16_t cdfsPid;
+  uint16_t serialVid;
+  uint16_t serialPidList[16];
+  byte targetClass;
+  bool huaweiPacket;
+  byte cdfsPacket[31];
+};
+*/
+
+//Huawei E220, E230, E270, E870
+{ 0x12d1, 0x1003, 0, {0}, 0xFF, true, {0} },
+
+//Huawei E1550, E270+
+{ 0x12d1, 0x1446, 0x12d1, {0x1001, 0x1406, 0x140c, 0x14ac/*, 0x1003*/}, 0, false, { 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 0,    0, 0, 0, 0,    0, 0, 0x11, 0x06, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
+
+};
diff -r 000000000000 -r 350011bf8be7 drv/usb/UsbDevice.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/usb/UsbDevice.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,291 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "UsbDevice.h"
+
+#include "netCfg.h"
+#if NET_USB
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+UsbDevice::UsbDevice( UsbHostMgr* pMgr, int hub, int port, int addr ) : m_pControlEp(NULL), /*m_controlEp( this, 0x00, false, USB_CONTROL, 8 ),*/
+m_pMgr(pMgr), m_connected(false), m_enumerated(false), m_hub(hub), m_port(port), m_addr(addr), m_refs(0),
+m_vid(0), m_pid(0)
+{
+
+}
+
+UsbDevice::~UsbDevice()
+{
+  if(m_pControlEp)
+    delete m_pControlEp;
+}
+
+UsbErr UsbDevice::enumerate()
+{
+ // USB_INT32S  rc;
+ 
+  UsbErr rc;
+
+  DBG("Starting enumeration (m_pMgr = %p)\n", m_pMgr);
+  
+#if 1
+  m_pMgr->resetPort(m_hub, m_port);
+#else 
+  wait_ms(100);                             /* USB 2.0 spec says atleast 50ms delay beore port reset */
+  LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset
+  while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS)
+    __WFI(); // Wait for port reset to complete...
+  LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal
+  wait_ms(200); /* Wait for 100 MS after port reset  */
+#endif
+
+  DBG("Port reset\n");
+  
+  wait_ms(200);
+   
+  m_pControlEp = new UsbEndpoint( this, 0x00, false, USB_CONTROL, 8, 0 );
+  
+  //EDCtrl->Control = 8 << 16;/* Put max pkt size = 8              */
+  /* Read first 8 bytes of device desc */
+  rc = controlReceive(USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, GET_DESCRIPTOR, (USB_DESCRIPTOR_TYPE_DEVICE << 8)|(0), 0, m_controlDataBuf, 8);
+  if (rc)
+  {
+    DBG("RC=%d",rc);
+    return (rc);
+  }
+  
+  DBG("Got descriptor, max ep size is %d\n", m_controlDataBuf[7]);
+  
+  m_pControlEp->updateSize(m_controlDataBuf[7]); /* Get max pkt size of endpoint 0    */
+  rc = controlSend(USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE, SET_ADDRESS, m_addr, 0, NULL, 0); /* Set the device address to m_addr       */
+  if (rc)
+  {
+  //  PRINT_Err(rc);
+    return (rc);
+  }
+  wait_ms(2);
+  //EDCtrl->Control = (EDCtrl->Control) | 1; /* Modify control pipe with address 1 */
+  
+  //Update address
+  m_pControlEp->updateAddr(m_addr);
+  DBG("Ep addr is now %d", m_addr);
+  /**/
+  
+  //rc = HOST_GET_DESCRIPTOR(USB_DESCRIPTOR_TYPE_DEVICE, 0, TDBuffer, 17); //Read full device descriptor
+  rc = controlReceive(USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, GET_DESCRIPTOR, (USB_DESCRIPTOR_TYPE_DEVICE << 8)|(0), 0, m_controlDataBuf, 17);
+  if (rc)
+  {
+    //PRINT_Err(rc);
+    return (rc);
+  }
+  /*
+  rc = SerialCheckVidPid();
+  if (rc != OK) {
+    PRINT_Err(rc);
+    return (rc);
+  }
+  */
+  /**/
+  
+  m_vid = *((uint16_t*)&m_controlDataBuf[8]);
+  m_pid = *((uint16_t*)&m_controlDataBuf[10]);
+  
+  DBG("VID: %02x, PID: %02x\n", m_vid, m_pid);
+  /* Get the configuration descriptor   */
+  //rc = HOST_GET_DESCRIPTOR(USB_DESCRIPTOR_TYPE_CONFIGURATION, 0, TDBuffer, 9);
+  rc = controlReceive(USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, GET_DESCRIPTOR, (USB_DESCRIPTOR_TYPE_CONFIGURATION << 8)|(0), 0, m_controlDataBuf, 9);
+  if (rc)
+  {
+    //PRINT_Err(rc);
+    return (rc);
+  }
+  /* Get the first configuration data  */
+  //rc = HOST_GET_DESCRIPTOR(USB_DESCRIPTOR_TYPE_CONFIGURATION, 0, TDBuffer, *((uint16_t*)&TDBuffer[2]));
+  rc = controlReceive(USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, GET_DESCRIPTOR, (USB_DESCRIPTOR_TYPE_CONFIGURATION << 8)|(0), 0, m_controlDataBuf, *((uint16_t*)&m_controlDataBuf[2]));
+  if (rc)
+  {
+    //PRINT_Err(rc);
+    return (rc);
+  }
+  
+  DBG("Desc len is %d\n", *((uint16_t*)&m_controlDataBuf[2]));
+  
+  DBG("Set configuration\n");
+  
+  //rc = USBH_SET_CONFIGURATION(1);/* Select device configuration 1     */
+  rc = controlSend(USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE, SET_CONFIGURATION, 1, 0, NULL, 0);
+  if (rc)
+  {
+   // PRINT_Err(rc);
+   return rc;
+  }
+  wait_ms(100);/* Some devices may require this delay */
+  
+  m_enumerated = true;
+  return USBERR_OK;
+}
+
+bool UsbDevice::connected()
+{
+  return m_connected;
+}
+
+bool UsbDevice::enumerated()
+{
+  return m_enumerated;
+}
+
+int UsbDevice::getPid()
+{
+  return m_pid;
+}
+
+int UsbDevice::getVid()
+{
+  return m_vid;
+}
+
+UsbErr UsbDevice::getConfigurationDescriptor(int config, uint8_t** pBuf)
+{
+  //For now olny one config
+  *pBuf = m_controlDataBuf;
+  return USBERR_OK;
+}
+
+UsbErr UsbDevice::getInterfaceDescriptor(int config, int item, uint8_t** pBuf)
+{
+  byte* desc_ptr = m_controlDataBuf;
+
+/*  if (desc_ptr[1] != USB_DESCRIPTOR_TYPE_CONFIGURATION)
+  {    
+    return USBERR_BADCONFIG;
+  }*/
+  
+  if(item>=m_controlDataBuf[4])//Interfaces count
+    return USBERR_NOTFOUND;
+  
+  desc_ptr += desc_ptr[0];
+  
+  *pBuf = NULL;
+  
+  while (desc_ptr < m_controlDataBuf + *((uint16_t*)&m_controlDataBuf[2]))
+  {
+
+    switch (desc_ptr[1]) {
+      case USB_DESCRIPTOR_TYPE_INTERFACE: 
+        if(desc_ptr[2] == item)
+        {
+          *pBuf = desc_ptr;
+          return USBERR_OK;
+        }
+        desc_ptr += desc_ptr[0]; // Move to next descriptor start
+        break;
+    }
+      
+  }
+  
+  if(*pBuf == NULL)
+    return USBERR_NOTFOUND;
+    
+  return USBERR_OK;
+}
+
+
+UsbErr UsbDevice::setConfiguration(int config)
+{
+  return USBERR_OK;
+}
+
+UsbErr UsbDevice::controlSend(byte requestType, byte request, word value, word index, const byte* buf, int len)
+{
+  UsbErr rc;
+  fillControlBuf(requestType, request, value, index, len);
+  m_pControlEp->setNextToken(TD_SETUP);
+  rc = m_pControlEp->transfer(m_controlBuf, 8);
+  while(m_pControlEp->status() == USBERR_PROCESSING);
+  rc = (UsbErr) MIN(0, m_pControlEp->status());
+  if(rc)
+    return rc;
+  if(len)
+  {
+    m_pControlEp->setNextToken(TD_OUT);
+    rc = m_pControlEp->transfer((byte*)buf, len);
+    while(m_pControlEp->status() == USBERR_PROCESSING);
+    rc = (UsbErr) MIN(0, m_pControlEp->status());
+    if(rc)
+      return rc;
+  }
+  m_pControlEp->setNextToken(TD_IN);
+  rc = m_pControlEp->transfer(NULL, 0);
+  while(m_pControlEp->status() == USBERR_PROCESSING);
+  rc = (UsbErr) MIN(0, m_pControlEp->status());
+  if(rc)
+    return rc;
+  return USBERR_OK;
+}
+
+UsbErr UsbDevice::controlReceive(byte requestType, byte request, word value, word index, const byte* buf, int len)
+{
+  UsbErr rc;
+  fillControlBuf(requestType, request, value, index, len);
+  m_pControlEp->setNextToken(TD_SETUP);
+  rc = m_pControlEp->transfer(m_controlBuf, 8);
+  while(m_pControlEp->status() == USBERR_PROCESSING);
+  rc = (UsbErr) MIN(0, m_pControlEp->status());
+  if(rc)
+    return rc;
+  if(len)
+  {
+    m_pControlEp->setNextToken(TD_IN);
+    rc = m_pControlEp->transfer( (byte*) buf, len);
+    while(m_pControlEp->status() == USBERR_PROCESSING);
+    rc = (UsbErr) MIN(0, m_pControlEp->status());
+    if(rc)
+      return rc;
+  }
+  m_pControlEp->setNextToken(TD_OUT);
+  rc = m_pControlEp->transfer(NULL, 0);
+  while(m_pControlEp->status() == USBERR_PROCESSING);
+  rc = (UsbErr) MIN(0, m_pControlEp->status());
+  if(rc)
+    return rc;
+  return USBERR_OK;
+}
+
+void UsbDevice::fillControlBuf(byte requestType, byte request, word value, word index, int len)
+{
+#ifdef __BIG_ENDIAN
+  #error "Must implement BE to LE conv here"
+#endif
+  m_controlBuf[0] = requestType;
+  m_controlBuf[1] = request;
+  //We are in LE so it's fine
+  *((word*)&m_controlBuf[2]) = value;
+  *((word*)&m_controlBuf[4]) = index;
+  *((word*)&m_controlBuf[6]) = (word) len;
+}
+
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/usb/UsbDevice.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/usb/UsbDevice.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,87 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef USB_DEVICE_H
+#define USB_DEVICE_H
+
+#include "mbed.h"
+#include "UsbInc.h"
+#include "UsbEndpoint.h"
+#include "UsbHostMgr.h"
+
+class UsbHostMgr;
+class UsbEndpoint;
+
+class UsbDevice
+{
+protected:
+  UsbDevice( UsbHostMgr* pMgr, int hub, int port, int addr );
+  ~UsbDevice();
+
+  UsbErr enumerate();
+
+public: 
+  bool connected();
+  bool enumerated();
+  
+  int getPid();
+  int getVid();
+  
+  UsbErr getConfigurationDescriptor(int config, uint8_t** pBuf);
+  
+  UsbErr getInterfaceDescriptor(int config, int item, uint8_t** pBuf);
+  
+  UsbErr setConfiguration(int config);
+  
+
+  UsbErr controlSend(byte requestType, byte request, word value, word index, const byte* buf, int len);
+  UsbErr controlReceive(byte requestType, byte request, word value, word index, const byte* buf, int len);
+
+protected:
+  void fillControlBuf(byte requestType, byte request, word value, word index, int len);
+private:
+  friend class UsbEndpoint;
+  friend class UsbHostMgr;
+  
+  UsbEndpoint* m_pControlEp;
+  
+  UsbHostMgr* m_pMgr;
+  
+  bool m_connected;
+  bool m_enumerated;
+  
+  int m_hub;
+  int m_port;
+  int m_addr;
+  
+  int m_refs;
+  
+  uint16_t m_vid;
+  uint16_t m_pid;
+  
+  byte m_controlBuf[8];//8
+  byte m_controlDataBuf[/*128*/256];
+  
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/usb/UsbEndpoint.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/usb/UsbEndpoint.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,394 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "UsbEndpoint.h"
+
+#include "UsbDevice.h"
+
+#include "usb_mem.h"
+
+#include "netCfg.h"
+#if NET_USB
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+UsbEndpoint::UsbEndpoint( UsbDevice* pDevice, uint8_t ep, bool dir, UsbEndpointType type, uint16_t size, int addr /*= -1*/ ) : m_pDevice(pDevice), m_result(true), m_status((int)USBERR_OK), m_len(0), m_pBufStartPtr(NULL),
+m_pCbItem(NULL), m_pCbMeth(NULL), m_pNextEp(NULL)
+{
+  //Insert into Eps list
+  //FIXME: Assert that no USB interrupt is triggered meanwhile
+  if(m_pHeadEp)
+  {
+    m_pNextEp = m_pHeadEp;
+    m_pHeadEp = this;
+  }
+  else
+  {
+    m_pNextEp = NULL;
+    m_pHeadEp = this;
+  }  
+
+  m_pEd = (volatile HCED*)usb_get_ed();
+  
+  m_pTdHead = (volatile HCTD*)usb_get_td();
+  m_pTdTail = (volatile HCTD*)usb_get_td();
+  
+  //printf("\r\n--m_pEd = %p--\r\n", m_pEd);
+  DBG("m_pEd = %p\n", m_pEd);
+  DBG("m_pTdHead = %p\n", m_pTdHead);
+  DBG("m_pTdTail = %p\n", m_pTdTail);
+  
+  //Init Ed & Td
+  //printf("\r\n--Ep Init--\r\n");
+  memset((void*)m_pEd, 0, sizeof(HCED));
+  //printf("\r\n--Td Init--\r\n");
+
+  memset((void*)m_pTdHead, 0, sizeof(HCTD));
+  memset((void*)m_pTdTail, 0, sizeof(HCTD));
+  
+  if(addr == -1)
+    addr = pDevice->m_addr;
+  
+  //Setup Ed
+  //printf("\r\n--Ep Setup--\r\n");
+  m_pEd->Control =  addr        |      /* USB address           */
+  ((ep & 0x7F) << 7)            |      /* Endpoint address      */
+  (type!=USB_CONTROL?((dir?2:1) << 11):0)             |      /* direction : Out = 1, 2 = In */
+  (size << 16);     /* MaxPkt Size           */
+  
+  m_dir = dir;
+  m_setup = false;
+  m_type = type;
+  
+  m_pEd->TailTd = m_pEd->HeadTd = (uint32_t) m_pTdTail; //Empty TD list
+  
+  DBG("Before link\n");
+  
+  //printf("\r\n--Ep Reg--\r\n");
+  //Append Ed to Ed list
+  volatile HCED* prevEd;
+  switch( m_type )
+  {
+  case USB_CONTROL:
+    prevEd = (volatile HCED*) LPC_USB->HcControlHeadED;
+    break;
+  case USB_BULK:
+  default:
+    prevEd = (volatile HCED*) LPC_USB->HcBulkHeadED;
+    break;
+  }
+  
+  DBG("prevEd is %p\n", prevEd);
+  
+  if(prevEd)
+  {
+    DBG("prevEd set\n")
+  
+    while(prevEd->Next)
+    {
+      DBG("prevEd->Next = %08x\n", prevEd->Next);
+      prevEd = (volatile HCED*) prevEd->Next;
+    }
+    prevEd->Next = (uint32_t) m_pEd;
+  
+  }
+  else
+  {
+    switch( m_type )
+    {
+    case USB_CONTROL:
+      LPC_USB->HcControlHeadED = (uint32_t) m_pEd;
+      break;
+    case USB_BULK:
+    default:
+      LPC_USB->HcBulkHeadED = (uint32_t) m_pEd;
+      break;
+    }
+  }
+  
+  DBG("Ep init\n");
+}
+
+UsbEndpoint::~UsbEndpoint()
+{
+  //Remove from Eps list
+  //FIXME: Assert that no USB interrupt is triggered meanwhile
+  if(m_pHeadEp != this)
+  {
+    UsbEndpoint* prevEp = m_pHeadEp;
+    while(prevEp->m_pNextEp != this)
+      prevEp = prevEp->m_pNextEp;
+    prevEp->m_pNextEp = m_pNextEp;
+  }
+  else
+  {
+    m_pHeadEp = m_pNextEp;
+  }  
+  
+  m_pEd->Control |= ED_SKIP; //Skip this Ep in queue
+
+  //Remove from queue
+  volatile HCED* prevEd;
+  switch( m_type )
+  {
+  case USB_CONTROL:
+    prevEd = (volatile HCED*) LPC_USB->HcControlHeadED;
+    break;
+  case USB_BULK:
+  default:
+    prevEd = (volatile HCED*) LPC_USB->HcBulkHeadED;
+    break;
+  }
+  if( m_pEd == prevEd )
+  {
+    switch( m_type )
+    {
+    case USB_CONTROL:
+      LPC_USB->HcControlHeadED = m_pEd->Next;
+      break;
+    case USB_BULK:
+    default:
+      LPC_USB->HcBulkHeadED = m_pEd->Next;
+      break;
+    }
+    LPC_USB->HcBulkHeadED = m_pEd->Next;
+  }
+  else
+  {
+    while( prevEd->Next != (uint32_t) m_pEd )
+    {
+      prevEd = (volatile HCED*) prevEd->Next;
+    }
+    prevEd->Next = m_pEd->Next;
+  }
+  
+  //
+  usb_free_ed((volatile byte*)m_pEd);
+  
+  usb_free_td((volatile byte*)m_pTdHead);
+  usb_free_td((volatile byte*)m_pTdTail);
+}
+
+void UsbEndpoint::setNextToken(uint32_t token) //Only for control Eps
+{
+  switch(token)
+  {
+    case TD_SETUP:
+      m_dir = false;
+      m_setup = true;
+      break;
+    case TD_IN:
+      m_dir = true;
+      m_setup = false;
+      break;
+    case TD_OUT:
+      m_dir = false;
+      m_setup = false;
+      break;
+  }
+}
+
+UsbErr UsbEndpoint::transfer(volatile uint8_t* buf, uint32_t len)
+{
+  if(!m_result)
+    return USBERR_BUSY; //The previous trasnfer is not completed 
+    //FIXME: We should be able to queue the next transfer, still needs to be implemented
+  
+  if( !m_pDevice->connected() )
+    return USBERR_DISCONNECTED;
+  
+  m_result = false;
+  
+  volatile uint32_t token = (m_setup?TD_SETUP:(m_dir?TD_IN:TD_OUT));
+
+  volatile uint32_t td_toggle;
+  if (m_type == USB_CONTROL)
+  {
+    if (m_setup)
+    {
+      td_toggle = TD_TOGGLE_0;
+    }
+    else
+    {
+      td_toggle = TD_TOGGLE_1;
+    }
+  }
+  else
+  {
+    td_toggle = 0;
+  }
+
+  //Swap Tds
+  volatile HCTD* pTdSwap;
+  pTdSwap = m_pTdTail;
+  m_pTdTail = m_pTdHead;
+  m_pTdHead = pTdSwap;
+
+  m_pTdHead->Control = (TD_ROUNDING    |
+                       token           |
+                       TD_DELAY_INT(0) |//7
+                       td_toggle       |
+                       TD_CC);
+
+  m_pTdTail->Control = 0;
+  m_pTdHead->CurrBufPtr   = (uint32_t) buf;
+  m_pBufStartPtr = buf;
+  m_pTdTail->CurrBufPtr   = 0;
+  m_pTdHead->Next         = (uint32_t) m_pTdTail;
+  m_pTdTail->Next         = 0;
+  m_pTdHead->BufEnd       = (uint32_t)(buf + (len - 1));
+  m_pTdTail->BufEnd       = 0;
+  
+  m_pEd->HeadTd  = (uint32_t)m_pTdHead | ((m_pEd->HeadTd) & 0x00000002); //Carry bit
+  m_pEd->TailTd  = (uint32_t)m_pTdTail;
+  
+  //DBG("m_pEd->HeadTd = %08x\n", m_pEd->HeadTd);
+
+  if(m_type == USB_CONTROL)
+  {
+    LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_CLF;
+    LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_CLE; //Enable control list
+  }
+  else //USB_BULK
+  {
+    LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_BLF;
+    LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_BLE; //Enable bulk list
+  }
+  
+  //m_done = false;
+  m_len = len;
+
+  return USBERR_PROCESSING;
+ 
+}
+  
+int UsbEndpoint::status()
+{
+  if( !m_pDevice->connected() )
+  {
+    if(!m_result)
+      onCompletion();
+    m_result = true;
+    return (int)USBERR_DISCONNECTED;
+  }
+  else if( !m_result )
+  { 
+    return (int)USBERR_PROCESSING;
+  }
+  /*else if( m_done )
+  {
+    return (int)USBERR_OK;
+  }*/
+  else
+  {
+    return m_status;
+  }
+}
+
+void UsbEndpoint::updateAddr(int addr)
+{
+  DBG("m_pEd->Control = %08x\n", m_pEd->Control);
+  m_pEd->Control &= ~0x7F;
+  m_pEd->Control |= addr;
+  DBG("m_pEd->Control = %08x\n", m_pEd->Control);
+}
+
+void UsbEndpoint::updateSize(uint16_t size)
+{
+  DBG("m_pEd->Control = %08x\n", m_pEd->Control);
+  m_pEd->Control &= ~0x3FF0000;
+  m_pEd->Control |= (size << 16);
+  DBG("m_pEd->Control = %08x\n", m_pEd->Control);
+}
+
+#if 0 //For doc only
+template <class T>
+void UsbEndpoint::setOnCompletion( T* pCbItem, void (T::*pCbMeth)() )
+{
+  m_pCbItem = (CDummy*) pCbItem;
+  m_pCbMeth = (void (CDummy::*)()) pCbMeth;
+}
+#endif
+
+void UsbEndpoint::onCompletion()
+{
+  //DBG("Transfer completed\n");
+  if( m_pTdHead->Control >> 28  )
+  {
+    DBG("TD Failed with condition code %01x\n", m_pTdHead->Control >> 28 );
+    m_status = (int)USBERR_TDFAIL;
+  }
+  else if( m_pEd->HeadTd & 0x1 )
+  {
+    m_pEd->HeadTd = m_pEd->HeadTd & ~0x1;
+    DBG("\r\nHALTED!!\r\n");
+    m_status = (int)USBERR_HALTED;
+  }
+  else if( (m_pEd->HeadTd & ~0xF) == (uint32_t) m_pTdTail )
+  {
+    //Done
+    int len;
+    //DBG("m_pTdHead->CurrBufPtr = %08x, m_pBufStartPtr=%08x\n", m_pTdHead->CurrBufPtr, (uint32_t) m_pBufStartPtr);
+    if(m_pTdHead->CurrBufPtr)
+      len = m_pTdHead->CurrBufPtr - (uint32_t) m_pBufStartPtr;
+    else
+      len = m_len;
+    /*if(len == 0) //Packet transfered completely
+      len = m_len;*/
+    //m_done = true;
+    DBG("Transfered %d bytes\n", len);
+    m_status = len; 
+  }
+  else
+  {
+    DBG("Unknown error...\n");
+    m_status = (int)USBERR_ERROR;
+  }
+  m_result = true;
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)();
+}
+
+void UsbEndpoint::sOnCompletion(uint32_t pTd)
+{
+  if(!m_pHeadEp)
+      return;
+  do
+  {
+    //DBG("sOnCompletion (pTd = %08x)\n", pTd);
+    UsbEndpoint* pEp = m_pHeadEp;  
+    do
+    {
+      if((uint32_t)pEp->m_pTdHead == pTd)
+      {
+        pEp->onCompletion();
+        break;
+      }
+    } while(pEp = pEp->m_pNextEp);
+  } while( pTd = (uint32_t)( ((HCTD*)pTd)->Next ) ); //Go around the Done queue
+}
+
+UsbEndpoint* UsbEndpoint::m_pHeadEp = NULL;
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/usb/UsbEndpoint.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/usb/UsbEndpoint.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,103 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef USB_ENDPOINT_H
+#define USB_ENDPOINT_H
+
+#include "mbed.h"
+#include "UsbInc.h"
+
+class UsbDevice;
+
+enum UsbEndpointType
+{
+  USB_CONTROL,
+  USB_BULK
+//  USB_INT,
+//  USB_ISO
+};
+
+class UsbEndpoint
+{
+public:
+  UsbEndpoint( UsbDevice* pDevice, uint8_t ep, bool dir, UsbEndpointType type, uint16_t size, int addr = -1 );
+  ~UsbEndpoint();
+
+  void setNextToken(uint32_t token); //Only for control Eps
+  
+  UsbErr transfer(volatile uint8_t* buf, uint32_t len); 
+  
+  int status(); //return UsbErr or transfered len
+  
+  void updateAddr(int addr);
+  void updateSize(uint16_t size);
+  
+  //void setOnCompletion( void(*pCb)completed() );
+  class CDummy;
+  template <class T>
+  void setOnCompletion( T* pCbItem, void (T::*pCbMeth)() )
+  {
+    m_pCbItem = (CDummy*) pCbItem;
+    m_pCbMeth = (void (CDummy::*)()) pCbMeth;
+  }
+   
+//static void completed(){}
+
+protected:
+  void onCompletion();
+public:
+  static void sOnCompletion(uint32_t pTd);
+  
+private:
+  friend class UsbDevice;
+
+  UsbDevice* m_pDevice;
+  
+  bool m_dir;
+  bool m_setup;
+  UsbEndpointType m_type;
+  
+  //bool m_done;
+  volatile bool m_result;
+  volatile int m_status;
+  
+  volatile uint32_t m_len;
+  
+  volatile uint8_t* m_pBufStartPtr;
+
+  volatile HCED* m_pEd; //Ep descriptor
+  volatile HCTD* m_pTdHead; //Head trf descriptor
+  volatile HCTD* m_pTdTail; //Tail trf descriptor
+  
+  //static volatile HCED* m_pNextEd;
+  
+  CDummy* m_pCbItem;
+  void (CDummy::*m_pCbMeth)();
+  
+  
+  static UsbEndpoint* m_pHeadEp;
+  UsbEndpoint* m_pNextEp;
+  
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/usb/UsbHostMgr.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/usb/UsbHostMgr.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,367 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "UsbHostMgr.h"
+
+#include "usb_mem.h"
+
+#include "string.h" //For memcpy, memmove, memset
+
+#include "netCfg.h"
+#if NET_USB
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+// bits of the USB/OTG clock control register
+#define HOST_CLK_EN     (1<<0)
+#define DEV_CLK_EN      (1<<1)
+#define PORTSEL_CLK_EN  (1<<3)
+#define AHB_CLK_EN      (1<<4)
+
+// bits of the USB/OTG clock status register
+#define HOST_CLK_ON     (1<<0)
+#define DEV_CLK_ON      (1<<1)
+#define PORTSEL_CLK_ON  (1<<3)
+#define AHB_CLK_ON      (1<<4)
+
+// we need host clock, OTG/portsel clock and AHB clock
+#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
+
+static UsbHostMgr* pMgr = NULL;
+
+extern "C" void sUsbIrqhandler(void) __irq
+{
+  DBG("\n+Int\n");
+  if(pMgr)
+    pMgr->UsbIrqhandler();
+  DBG("\n-Int\n");
+  return;
+}
+
+UsbHostMgr::UsbHostMgr() : m_lpDevices()
+{
+  /*if(!pMgr)*/ //Assume singleton
+    pMgr = this;
+  usb_mem_init();
+  memset(m_lpDevices, NULL, sizeof(UsbDevice*) * USB_HOSTMGR_MAX_DEVS);
+  m_pHcca = (HCCA*) usb_get_hcca();
+  memset((void*)m_pHcca, 0, 0x100);
+  DBG("Host manager at %p\n", this);
+}
+
+UsbHostMgr::~UsbHostMgr()
+{
+  if(pMgr == this)
+    pMgr = NULL;
+}
+
+UsbErr UsbHostMgr::init() //Initialize host
+{
+  NVIC_DisableIRQ(USB_IRQn);                           /* Disable the USB interrupt source           */
+  
+  LPC_SC->PCONP       &= ~(1UL<<31); //Cut power
+  wait(1);
+  
+  
+  // turn on power for USB
+  LPC_SC->PCONP       |= (1UL<<31);
+  // Enable USB host clock, port selection and AHB clock
+  LPC_USB->USBClkCtrl |= CLOCK_MASK;
+  // Wait for clocks to become available
+  while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK)
+      ;
+  
+  // it seems the bits[0:1] mean the following
+  // 0: U1=device, U2=host
+  // 1: U1=host, U2=host
+  // 2: reserved
+  // 3: U1=host, U2=device
+  // NB: this register is only available if OTG clock (aka "port select") is enabled!!
+  // since we don't care about port 2, set just bit 0 to 1 (U1=host)
+  LPC_USB->OTGStCtrl |= 1;
+  
+  // now that we've configured the ports, we can turn off the portsel clock
+  LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
+  
+  // power pins are not connected on mbed, so we can skip them
+  /* P1[18] = USB_UP_LED, 01 */
+  /* P1[19] = /USB_PPWR,     10 */
+  /* P1[22] = USB_PWRD, 10 */
+  /* P1[27] = /USB_OVRCR, 10 */
+  /*LPC_PINCON->PINSEL3 &= ~((3<<4) | (3<<6) | (3<<12) | (3<<22));  
+  LPC_PINCON->PINSEL3 |=  ((1<<4)|(2<<6) | (2<<12) | (2<<22));   // 0x00802080
+  */
+
+  // configure USB D+/D- pins
+  /* P0[29] = USB_D+, 01 */
+  /* P0[30] = USB_D-, 01 */
+  LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));  
+  LPC_PINCON->PINSEL1 |=  ((1<<26)|(1<<28));     // 0x14000000
+      
+  DBG("Initializing Host Stack\n");
+  
+  wait_ms(100);                                   /* Wait 50 ms before apply reset              */
+  LPC_USB->HcControl       = 0;                       /* HARDWARE RESET                             */
+  LPC_USB->HcControlHeadED = 0;                       /* Initialize Control list head to Zero       */
+  LPC_USB->HcBulkHeadED    = 0;                       /* Initialize Bulk list head to Zero          */
+  
+                                                      /* SOFTWARE RESET                             */
+  LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
+  LPC_USB->HcFmInterval    = DEFAULT_FMINTERVAL;      /* Write Fm Interval and Largest Data Packet Counter */
+
+                                                      /* Put HC in operational state                */
+  LPC_USB->HcControl  = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
+  LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;            /* Set Global Power                           */
+  
+  LPC_USB->HcHCCA = (uint32_t)(m_pHcca);
+  LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;                   /* Clear Interrrupt Status                    */
+
+
+  LPC_USB->HcInterruptEnable  = OR_INTR_ENABLE_MIE |
+                       OR_INTR_ENABLE_WDH |
+                       OR_INTR_ENABLE_RHSC;
+
+  NVIC_SetPriority(USB_IRQn, 0);       /* highest priority */
+  /* Enable the USB Interrupt */
+  NVIC_SetVector(USB_IRQn, (uint32_t)(sUsbIrqhandler));
+  LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+  LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+  
+  /* Check for any connected devices */
+  if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS)  //Root device connected
+  {
+    //Device connected
+    wait(1);
+    DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1);
+    onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1)
+  }
+  
+  DBG("Enabling IRQ\n");
+  NVIC_EnableIRQ(USB_IRQn);
+  DBG("End of host stack initialization\n");
+  return USBERR_OK;
+}
+
+void UsbHostMgr::poll() //Enumerate connected devices, etc
+{
+  /* Check for any connected devices */
+  if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS)  //Root device connected
+  {
+    //Device connected
+    wait(1);
+    DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1);
+    onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1)
+  }
+  
+  for(int i = 0; i < devicesCount(); i++)
+  {
+    if( (m_lpDevices[i]->m_connected)
+    &&  !(m_lpDevices[i]->m_enumerated) )
+    {
+      m_lpDevices[i]->enumerate();
+      return;
+    }
+  }
+}
+
+int UsbHostMgr::devicesCount()
+{
+  int i;
+  for(i = 0; i < USB_HOSTMGR_MAX_DEVS; i++)
+  {
+    if (m_lpDevices[i] == NULL)
+      break;
+  }
+  return i;
+}
+
+UsbDevice* UsbHostMgr::getDevice(int item)
+{
+  UsbDevice* pDev = m_lpDevices[item];
+  if(!pDev)
+    return NULL;
+    
+  pDev->m_refs++;
+  return pDev;
+}
+
+void UsbHostMgr::releaseDevice(UsbDevice* pDev)
+{
+  pDev->m_refs--;
+  if(pDev->m_refs > 0)
+    return;
+  //If refs count = 0, delete
+  //Find & remove from list
+  int i;
+  for(i = 0; i < USB_HOSTMGR_MAX_DEVS; i++)
+  {
+    if (m_lpDevices[i] == pDev)
+      break;
+  }
+  if(i!=USB_HOSTMGR_MAX_DEVS)
+    memmove(&m_lpDevices[i], &m_lpDevices[i+1], sizeof(UsbDevice*) * (USB_HOSTMGR_MAX_DEVS - (i + 1))); //Safer than memcpy because of overlapping mem
+  m_lpDevices[USB_HOSTMGR_MAX_DEVS - 1] = NULL;
+  delete pDev;
+}
+
+void UsbHostMgr::UsbIrqhandler()
+{
+  uint32_t   int_status;
+  uint32_t   ie_status;
+  
+  int_status    = LPC_USB->HcInterruptStatus;                          /* Read Interrupt Status                */
+  ie_status     = LPC_USB->HcInterruptEnable;                          /* Read Interrupt enable status         */
+
+  if (!(int_status & ie_status))
+  {
+    return;
+  }
+  else
+  {
+    int_status = int_status & ie_status;
+    if (int_status & OR_INTR_STATUS_RHSC) /* Root hub status change interrupt     */
+    {
+      DBG("LPC_USB->HcRhPortStatus1 = %08x\n", LPC_USB->HcRhPortStatus1);
+      if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC)
+      {
+        if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE)
+        {
+            /*
+             * When DRWE is on, Connect Status Change
+             * means a remote wakeup event.
+            */
+            //HOST_RhscIntr = 1;// JUST SOMETHING FOR A BREAKPOINT
+        }
+        else
+        {
+          /*
+           * When DRWE is off, Connect Status Change
+           * is NOT a remote wakeup event
+          */
+          if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS)  //Root device connected
+          {
+            //Device connected
+            DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1);
+            onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1)
+          }
+          else //Root device disconnected
+          {
+            //Device disconnected
+            DBG("Device disconnected\n");
+            onUsbDeviceDisconnected(0, 1);
+          }
+          //TODO: HUBS
+        }
+        LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+      }
+      if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC)
+      {
+        LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+      }
+    }  
+    if (int_status & OR_INTR_STATUS_WDH) /* Writeback Done Head interrupt        */
+    {                  
+      //UsbEndpoint::sOnCompletion((LPC_USB->HccaDoneHead) & 0xFE);
+      if(m_pHcca->DoneHead)
+      {
+        UsbEndpoint::sOnCompletion(m_pHcca->DoneHead);
+        m_pHcca->DoneHead = 0;
+        LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
+        if(m_pHcca->DoneHead)
+          DBG("??????????????????????????????\n\n\n");
+      }
+      else
+      {
+        //Probably an error
+        int_status = LPC_USB->HcInterruptStatus;
+        DBG("HcInterruptStatus = %08x\n", int_status);
+        if (int_status & OR_INTR_STATUS_UE) //Unrecoverable error, disconnect devices and resume
+        {
+          onUsbDeviceDisconnected(0, 1);
+          LPC_USB->HcInterruptStatus = OR_INTR_STATUS_UE;
+          LPC_USB->HcCommandStatus = 0x01; //Host Controller Reset
+        }
+      }
+    }
+    LPC_USB->HcInterruptStatus = int_status; /* Clear interrupt status register      */
+  }
+  return;
+}
+
+void UsbHostMgr::onUsbDeviceConnected(int hub, int port)
+{
+  int item = devicesCount();
+  if( item == USB_HOSTMGR_MAX_DEVS )
+    return; //List full...
+  //Find a free address (not optimized, but not really important)
+  int i;
+  int addr = 1;
+  for(i = 0; i < item; i++)
+  {
+    addr = MAX( addr, m_lpDevices[i]->m_addr + 1 );
+  }
+  m_lpDevices[item] = new UsbDevice( this, hub, port, addr );
+  m_lpDevices[item]->m_connected = true;
+}
+
+void UsbHostMgr::onUsbDeviceDisconnected(int hub, int port)
+{
+  for(int i = 0; i < devicesCount(); i++)
+  {
+     if( (m_lpDevices[i]->m_hub == hub)
+     &&  (m_lpDevices[i]->m_port == port) )
+     {
+       m_lpDevices[i]->m_connected = false;
+       if(!m_lpDevices[i]->m_enumerated)
+       {
+         delete m_lpDevices[i];
+         m_lpDevices[i] = NULL;
+       }
+       return;
+     }
+  }
+}
+
+void UsbHostMgr::resetPort(int hub, int port)
+{
+  DBG("Resetting hub %d, port %d\n", hub, port);
+  if(hub == 0) //Root hub
+  {
+    wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset
+    DBG("Before loop\n");
+    while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS)
+      ;
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal
+    DBG("After loop\n");
+    wait_ms(200); /* Wait for 100 MS after port reset  */
+  }
+  else
+  {
+    //TODO: Hubs
+  }
+  DBG("Port reset OK\n");
+}
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/usb/UsbHostMgr.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/usb/UsbHostMgr.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,67 @@
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+//Assigns addresses to connected devices...
+
+#ifndef USB_HOSTMGR_H
+#define USB_HOSTMGR_H
+
+#include "mbed.h"
+#include "UsbInc.h"
+#include "UsbDevice.h"
+
+#define USB_HOSTMGR_MAX_DEVS 2 //2 devices max for now... will be more when hubs are supported
+
+class UsbDevice;
+
+class UsbHostMgr //[0-1] inst
+{
+public:
+  UsbHostMgr();
+  ~UsbHostMgr();
+  
+  UsbErr init(); //Initialize host
+  
+  void poll(); //Enumerate connected devices, etc
+  
+  int devicesCount();
+  
+  UsbDevice* getDevice(int item);
+  void releaseDevice(UsbDevice* pDev);
+  
+
+  void UsbIrqhandler();
+
+protected:  
+  void onUsbDeviceConnected(int hub, int port);
+  void onUsbDeviceDisconnected(int hub, int port);
+  
+  friend class UsbDevice;
+  void resetPort(int hub, int port);
+  
+private:
+/*  __align(8)*/ volatile HCCA* m_pHcca;
+  
+  UsbDevice* m_lpDevices[USB_HOSTMGR_MAX_DEVS]; 
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/usb/UsbInc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/usb/UsbInc.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,193 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef USB_INC_H
+#define USB_INC_H
+
+#include "mbed.h"
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+//typedef int32_t RC;
+
+typedef uint8_t byte;
+typedef uint16_t word;
+
+enum UsbErr
+{
+  __USBERR_MIN = -0xFFFF,
+  USBERR_DISCONNECTED,
+  USBERR_NOTFOUND,
+  USBERR_BADCONFIG,
+  USBERR_PROCESSING,
+  USBERR_HALTED, //Transfer on an ep is stalled
+  USBERR_BUSY,
+  USBERR_TDFAIL,
+  USBERR_ERROR,
+  USBERR_OK = 0
+};
+
+
+/* From NXP's USBHostLite stack's usbhost_lpc17xx.h */
+/* Only the types names have been changed to avoid unecessary typedefs */
+
+
+/*
+**************************************************************************************************************
+*                                                 NXP USB Host Stack
+*
+*                                     (c) Copyright 2008, NXP SemiConductors
+*                                     (c) Copyright 2008, OnChip  Technologies LLC
+*                                                 All Rights Reserved
+*
+*                                                  www.nxp.com
+*                                               www.onchiptech.com
+*
+* File           : usbhost_lpc17xx.h
+* Programmer(s)  : Ravikanth.P
+* Version        :
+*
+**************************************************************************************************************
+*/
+
+
+
+/*
+**************************************************************************************************************
+*                                  OHCI OPERATIONAL REGISTER FIELD DEFINITIONS
+**************************************************************************************************************
+*/
+
+                                            /* ------------------ HcControl Register ---------------------  */
+#define  OR_CONTROL_CLE                 0x00000010
+#define  OR_CONTROL_BLE                 0x00000020
+#define  OR_CONTROL_HCFS                0x000000C0
+#define  OR_CONTROL_HC_OPER             0x00000080
+                                            /* ----------------- HcCommandStatus Register ----------------- */
+#define  OR_CMD_STATUS_HCR              0x00000001
+#define  OR_CMD_STATUS_CLF              0x00000002
+#define  OR_CMD_STATUS_BLF              0x00000004
+                                            /* --------------- HcInterruptStatus Register ----------------- */
+#define  OR_INTR_STATUS_WDH             0x00000002
+#define  OR_INTR_STATUS_RHSC            0x00000040
+#define  OR_INTR_STATUS_UE              0x00000010
+                                            /* --------------- HcInterruptEnable Register ----------------- */
+#define  OR_INTR_ENABLE_WDH             0x00000002
+#define  OR_INTR_ENABLE_RHSC            0x00000040
+#define  OR_INTR_ENABLE_MIE             0x80000000
+                                            /* ---------------- HcRhDescriptorA Register ------------------ */
+#define  OR_RH_STATUS_LPSC              0x00010000
+#define  OR_RH_STATUS_DRWE              0x00008000
+                                            /* -------------- HcRhPortStatus[1:NDP] Register -------------- */
+#define  OR_RH_PORT_CCS                 0x00000001
+#define  OR_RH_PORT_PRS                 0x00000010
+#define  OR_RH_PORT_CSC                 0x00010000
+#define  OR_RH_PORT_PRSC                0x00100000
+
+
+/*
+**************************************************************************************************************
+*                                               FRAME INTERVAL
+**************************************************************************************************************
+*/
+
+#define  FI                     0x2EDF           /* 12000 bits per frame (-1)                               */
+#define  DEFAULT_FMINTERVAL     ((((6 * (FI - 210)) / 7) << 16) | FI)
+
+/*
+**************************************************************************************************************
+*                                       ENDPOINT DESCRIPTOR CONTROL FIELDS
+**************************************************************************************************************
+*/
+
+#define  ED_SKIP            (uint32_t) (0x00001000)        /* Skip this ep in queue                       */
+
+/*
+**************************************************************************************************************
+*                                       TRANSFER DESCRIPTOR CONTROL FIELDS
+**************************************************************************************************************
+*/
+
+#define  TD_ROUNDING        (uint32_t) (0x00040000)        /* Buffer Rounding                             */
+#define  TD_SETUP           (uint32_t)(0)                  /* Direction of Setup Packet                   */
+#define  TD_IN              (uint32_t)(0x00100000)         /* Direction In                                */
+#define  TD_OUT             (uint32_t)(0x00080000)         /* Direction Out                               */
+#define  TD_DELAY_INT(x)    (uint32_t)((x) << 21)          /* Delay Interrupt                             */
+#define  TD_TOGGLE_0        (uint32_t)(0x02000000)         /* Toggle 0                                    */
+#define  TD_TOGGLE_1        (uint32_t)(0x03000000)         /* Toggle 1                                    */
+#define  TD_CC              (uint32_t)(0xF0000000)         /* Completion Code                             */
+
+/*
+**************************************************************************************************************
+*                                       USB STANDARD REQUEST DEFINITIONS
+**************************************************************************************************************
+*/
+
+#define  USB_DESCRIPTOR_TYPE_DEVICE                     1
+#define  USB_DESCRIPTOR_TYPE_CONFIGURATION              2
+#define  USB_DESCRIPTOR_TYPE_INTERFACE                  4
+#define  USB_DESCRIPTOR_TYPE_ENDPOINT                   5
+                                                    /*  ----------- Control RequestType Fields  ----------- */
+#define  USB_DEVICE_TO_HOST         0x80
+#define  USB_HOST_TO_DEVICE         0x00
+#define  USB_REQUEST_TYPE_CLASS     0x20
+#define  USB_RECIPIENT_DEVICE       0x00
+#define  USB_RECIPIENT_INTERFACE    0x01
+                                                    /* -------------- USB Standard Requests  -------------- */
+#define  SET_ADDRESS                 5
+#define  GET_DESCRIPTOR              6
+#define  SET_CONFIGURATION           9
+#define  SET_INTERFACE              11
+
+/*
+**************************************************************************************************************
+*                                       TYPE DEFINITIONS
+**************************************************************************************************************
+*/
+
+typedef struct hcEd {                       /* ----------- HostController EndPoint Descriptor ------------- */
+    volatile  uint32_t  Control;              /* Endpoint descriptor control                              */
+    volatile  uint32_t  TailTd;               /* Physical address of tail in Transfer descriptor list     */
+    volatile  uint32_t  HeadTd;               /* Physcial address of head in Transfer descriptor list     */
+    volatile  uint32_t  Next;                 /* Physical address of next Endpoint descriptor             */
+} HCED;
+
+typedef struct hcTd {                       /* ------------ HostController Transfer Descriptor ------------ */
+    volatile  uint32_t  Control;              /* Transfer descriptor control                              */
+    volatile  uint32_t  CurrBufPtr;           /* Physical address of current buffer pointer               */
+    volatile  uint32_t  Next;                 /* Physical pointer to next Transfer Descriptor             */
+    volatile  uint32_t  BufEnd;               /* Physical address of end of buffer                        */
+} HCTD;
+
+typedef struct hcca {                       /* ----------- Host Controller Communication Area ------------  */
+    volatile  uint32_t  IntTable[32];         /* Interrupt Table                                          */
+    volatile  uint32_t  FrameNumber;          /* Frame Number                                             */
+    volatile  uint32_t  DoneHead;             /* Done Head                                                */
+    volatile  uint8_t  Reserved[116];        /* Reserved for future use                                  */
+    volatile  uint8_t  Unknown[4];           /* Unused                                                   */
+} HCCA;
+
+
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/usb/usb_mem.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/usb/usb_mem.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,108 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "usb_mem.h"
+
+#include "string.h" //For memcpy, memmove, memset
+
+#include "netCfg.h"
+#if NET_USB
+
+#define EDS_COUNT 4
+#define TDS_COUNT 8
+
+#define HCCA_SIZE 0x100
+#define ED_SIZE 0x10
+#define TD_SIZE 0x10
+
+#define TOTAL_SIZE (HCCA_SIZE + (EDS_COUNT*ED_SIZE) + (TDS_COUNT*TD_SIZE))
+
+
+static volatile __align(256) byte usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM1"),aligned));  //256 bytes aligned!
+
+static volatile byte* usb_hcca;  //256 bytes aligned!
+
+static volatile byte* usb_edBuf;  //4 bytes aligned!
+static volatile byte* usb_tdBuf;  //4 bytes aligned!
+
+static byte usb_edBufAlloc[EDS_COUNT] __attribute((section("AHBSRAM1"),aligned));
+static byte usb_tdBufAlloc[TDS_COUNT] __attribute((section("AHBSRAM1"),aligned));
+
+void usb_mem_init()
+{
+  usb_hcca = usb_buf;
+  usb_edBuf = usb_buf + HCCA_SIZE;
+  usb_tdBuf = usb_buf + HCCA_SIZE + (EDS_COUNT*ED_SIZE);
+  memset(usb_edBufAlloc, 0, EDS_COUNT);
+  memset(usb_tdBufAlloc, 0, TDS_COUNT);
+}
+
+volatile byte* usb_get_hcca()
+{
+  return usb_hcca;
+}
+
+volatile byte* usb_get_ed()
+{
+  int i;
+  for(i = 0; i < EDS_COUNT; i++)
+  {
+    if( !usb_edBufAlloc[i] )
+    {
+      usb_edBufAlloc[i] = 1;
+      return usb_edBuf + i*ED_SIZE;
+    }
+  }
+  return NULL; //Could not alloc ED
+}
+
+volatile byte* usb_get_td()
+{
+  int i;
+  for(i = 0; i < TDS_COUNT; i++)
+  {
+    if( !usb_tdBufAlloc[i] )
+    {
+      usb_tdBufAlloc[i] = 1;
+      return usb_tdBuf + i*TD_SIZE;
+    }
+  }
+  return NULL; //Could not alloc TD
+}
+
+void usb_free_ed(volatile byte* ed)
+{
+  int i;
+  i = (ed - usb_edBuf) / ED_SIZE;
+  usb_edBufAlloc[i] = 0;
+}
+
+void usb_free_td(volatile byte* td)
+{
+  int i;
+  i = (td - usb_tdBuf) / TD_SIZE;
+  usb_tdBufAlloc[i] = 0;
+}
+
+
+#endif
diff -r 000000000000 -r 350011bf8be7 drv/usb/usb_mem.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drv/usb/usb_mem.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,48 @@
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef USB_MEM_H
+#define USB_MEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned char byte;
+
+void usb_mem_init();
+
+volatile byte* usb_get_hcca();
+
+volatile byte* usb_get_ed();
+
+volatile byte* usb_get_td();
+
+void usb_free_ed(volatile byte* ed);
+
+void usb_free_td(volatile byte* td);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/eth/EthernetNetIf.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/eth/EthernetNetIf.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,188 @@
+#pragma diag_remark 1464
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "EthernetNetIf.h"
+
+#include "netif/etharp.h"
+#include "lwip/dhcp.h"
+#include "lwip/dns.h"
+#include "lwip/igmp.h"
+
+#include "drv/eth/eth_drv.h"
+#include "mbed.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#include "netCfg.h"
+#if NET_ETH
+
+EthernetNetIf::EthernetNetIf(const char* hostname) : LwipNetIf(), m_ethArpTimer(), m_dhcpCoarseTimer(), m_dhcpFineTimer(), m_igmpTimer(), m_pNetIf(NULL),
+m_netmask(255,255,255,255), m_gateway(), m_hostname(hostname)
+{
+  //m_hostname = NULL;
+  m_pNetIf = new netif;
+  m_useDhcp = true;
+  m_pDhcp = new dhcp;
+  m_setup = false;
+}
+
+EthernetNetIf::EthernetNetIf(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns) : LwipNetIf(), m_ethArpTimer(), m_dhcpCoarseTimer(), m_dhcpFineTimer(), m_igmpTimer(), m_pNetIf(NULL), m_hostname(NULL) //W/o DHCP
+{
+  m_hostname = NULL;
+  m_netmask = netmask;
+  m_gateway = gateway;
+  m_ip = ip;
+  m_pNetIf = new netif;
+  dns_setserver(0, &dns.getStruct());
+  m_useDhcp = false;
+  m_setup = false;
+}
+
+EthernetNetIf::~EthernetNetIf()
+{
+  if(m_pNetIf)
+  {
+    igmp_stop(m_pNetIf); //Stop IGMP processing
+    netif_set_down(m_pNetIf);
+    netif_remove(m_pNetIf);
+    delete m_pNetIf;
+    eth_free();
+  }
+  
+  if (m_pDhcp)
+    delete m_pDhcp;
+}
+  
+EthernetErr EthernetNetIf::setup(int timeout_ms /*= 15000*/)
+{
+  if (m_setup)
+  {
+    igmp_stop(m_pNetIf);
+    netif_set_down(m_pNetIf);
+    netif_remove(m_pNetIf);
+    delete m_pNetIf;
+    eth_free();
+    m_pNetIf = new netif;
+  }
+
+  LwipNetIf::init();
+  //m_ethArpTicker.attach_us(&etharp_tmr,  ARP_TMR_INTERVAL  * 1000); // = 5s in etharp.h
+  m_ethArpTimer.start();
+  if(m_useDhcp)
+  {
+    //m_dhcpCoarseTicker.attach(&dhcp_coarse_tmr, DHCP_COARSE_TIMER_SECS); // = 60s in dhcp.h
+    //m_dhcpFineTicker.attach_us(&dhcp_fine_tmr, DHCP_FINE_TIMER_MSECS * 1000); // = 500ms in dhcp.h
+    m_dhcpCoarseTimer.start();
+    m_dhcpFineTimer.start();
+  }
+  m_pNetIf->hwaddr_len = ETHARP_HWADDR_LEN; //6
+  eth_address((char *)m_pNetIf->hwaddr);
+  
+  DBG("HW Addr is : %02x:%02x:%02x:%02x:%02x:%02x.\n", 
+  m_pNetIf->hwaddr[0], m_pNetIf->hwaddr[1], m_pNetIf->hwaddr[2],
+  m_pNetIf->hwaddr[3], m_pNetIf->hwaddr[4], m_pNetIf->hwaddr[5]);
+
+  m_pNetIf = netif_add(m_pNetIf, &(m_ip.getStruct()), &(m_netmask.getStruct()), &(m_gateway.getStruct()), NULL, eth_init, ip_input);//ethernet_input);// ip_input);
+  m_pNetIf->hostname = (char *)m_hostname;
+  netif_set_default(m_pNetIf);
+  
+  //DBG("\r\nStarting DHCP.\r\n");
+  
+  if(m_useDhcp)
+  {
+    dhcp_set_struct(m_pNetIf, m_pDhcp);
+    dhcp_start(m_pNetIf);
+    DBG("DHCP Started, waiting for IP...\n");
+  }
+  else
+  {
+    netif_set_up(m_pNetIf);
+  }
+  
+  Timer timeout;
+  timeout.start();
+  while( !netif_is_up(m_pNetIf) ) //Wait until device is up
+  {
+    if(m_useDhcp)
+    {
+      if(m_dhcpFineTimer.read_ms()>=DHCP_FINE_TIMER_MSECS)
+      {
+        m_dhcpFineTimer.reset();
+        dhcp_fine_tmr();
+      }
+      if(m_dhcpCoarseTimer.read()>=DHCP_COARSE_TIMER_SECS)
+      {
+        m_dhcpCoarseTimer.reset();
+        dhcp_coarse_tmr();
+      }
+    }
+    poll();
+    if( timeout.read_ms() > timeout_ms )
+    {
+      //Abort
+      if(m_useDhcp)
+        dhcp_stop(m_pNetIf);
+      else
+        netif_set_down(m_pNetIf);
+      DBG("\r\nTimeout.\r\n");
+      m_setup = true;
+      return ETH_TIMEOUT;
+    }
+  }
+  
+  #if LWIP_IGMP
+  igmp_start(m_pNetIf); //Start IGMP processing
+  #endif
+  
+  m_ip = IpAddr(&(m_pNetIf->ip_addr));
+   
+  DBG("Connected, IP : %d.%d.%d.%d\n", m_ip[0], m_ip[1], m_ip[2], m_ip[3]);
+  
+  m_setup = true;
+  return ETH_OK;
+}
+
+void EthernetNetIf::poll()
+{
+  if(m_ethArpTimer.read_ms()>=ARP_TMR_INTERVAL)
+  {
+    m_ethArpTimer.reset();
+    etharp_tmr();
+  }
+  #if LWIP_IGMP
+  if(m_igmpTimer.read_ms()>=IGMP_TMR_INTERVAL)
+  {
+    m_igmpTimer.reset();
+    igmp_tmr();
+  }
+  #endif
+  LwipNetIf::poll();
+  eth_poll();
+}
+
+const char* EthernetNetIf::getHwAddr() const {
+    return (char*)m_pNetIf->hwaddr;
+}
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/eth/EthernetNetIf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/eth/EthernetNetIf.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,106 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/** \file
+Ethernet network interface header file
+*/
+
+#ifndef ETHERNETNETIF_H
+#define ETHERNETNETIF_H
+
+struct netif;
+
+#include "mbed.h"
+
+#include "if/lwip/LwipNetIf.h"
+#include "lwip/dhcp.h"
+
+///Ethernet network interface return codes
+enum EthernetErr
+{
+  __ETH_MIN = -0xFFFF,
+  ETH_TIMEOUT, ///<Timeout during setup
+  ETH_OK = 0 ///<Success
+};
+
+///Ethernet network interface
+/**
+This class provides Ethernet connectivity to the stack
+*/
+class EthernetNetIf : public LwipNetIf
+{
+public:
+  ///Instantiates the Interface and register it against the stack, DHCP will be used
+  /**
+  * An optional hostname can be specified which will be passed to the DHCP server.
+  * Examples without and with hostname specified:
+  *
+  * @code
+  * EthernetNetIf eth();
+  * @endcode
+  * @code
+  * EthernetNetIf eth("mbedSE");
+  * @endcode
+  */
+  EthernetNetIf(const char* hostname = NULL); //W/ DHCP
+
+  ///Instantiates the Interface and register it against the stack, DHCP will not be used
+  /**
+  IpAddr is a container class that can be constructed with either 4 bytes or no parameters for a null IP address.
+  */
+  EthernetNetIf(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns); //W/o DHCP
+  virtual ~EthernetNetIf();
+  
+  ///Brings the interface up
+  /**
+  Uses DHCP if necessary
+  @param timeout_ms : You can set the timeout parameter in milliseconds, if not it defaults to 15s
+  @return : ETH_OK on success or ETH_TIMEOUT on timeout
+  */
+  EthernetErr setup(int timeout_ms = 15000);
+
+  virtual void poll();
+  
+  ///Returns an array containing the hardware address
+  const char* getHwAddr() const;
+  
+private:
+  Timer m_ethArpTimer;
+  Timer m_dhcpCoarseTimer;
+  Timer m_dhcpFineTimer;
+  Timer m_igmpTimer;
+    
+  bool m_useDhcp;
+
+  netif* m_pNetIf;
+  
+  IpAddr m_netmask;
+  IpAddr m_gateway;
+  
+  const char* m_hostname;
+  dhcp* m_pDhcp;
+  bool m_setup;
+};
+
+#endif
+
diff -r 000000000000 -r 350011bf8be7 if/gprsmodule/GPRSModuleNetIf.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/gprsmodule/GPRSModuleNetIf.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,112 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "netCfg.h"
+#if NET_GPRS_MODULE
+
+#include "GPRSModuleNetIf.h"
+
+#define __DEBUG
+#include "dbg/dbg.h"
+
+GPRSModuleNetIf::GPRSModuleNetIf(PinName tx, PinName rx, int baud /*= 115200*/) : PPPNetIf(NULL), m_serial(tx, rx)
+{
+  PPPNetIf::m_pIf = new GPRSModem();
+  m_serial.baud(baud);
+}
+
+GPRSModuleNetIf::~GPRSModuleNetIf()
+{
+  delete PPPNetIf::m_pIf;
+}
+  
+PPPErr GPRSModuleNetIf::connect(const char* apn /*= NULL*/, const char* userId /*= NULL*/, const char* password /*= NULL*/) //Connect using GPRS
+{
+
+  DBG("Powering on module.\n")
+  if(!setOn()) //Could not power on module
+  {
+    DBG("Could not power on module.\n");
+    return PPP_MODEM;
+  }
+  
+  //wait(10); //Wait for module to init.
+
+  ATErr atErr;
+  for(int i=0; i<3; i++)
+  {
+    atErr = m_pIf->open(&m_serial); //3 tries
+    if(!atErr)
+      break;
+    DBG("Could not open AT If, trying again.\n");
+    wait(4);
+  }
+    
+  if(atErr)
+  {
+    setOff();
+    return PPP_MODEM;
+  }
+    
+  DBG("AT If opened.\n");
+
+  PPPErr pppErr;
+  for(int i=0; i<3; i++)
+  {  
+    DBG("Trying to connect.\n");
+    pppErr = PPPNetIf::GPRSConnect(apn, userId, password);
+    if(!pppErr)
+      break;
+    DBG("Could not connect.\n");
+    wait(4);
+  }
+  if(pppErr)
+  {
+    setOff();
+    return pppErr;
+  }
+    
+  DBG("Connected.\n");
+  
+  return PPP_OK;
+}
+
+PPPErr GPRSModuleNetIf::disconnect()
+{
+  DBG("Disconnecting...\n");
+  PPPErr pppErr = PPPNetIf::disconnect();
+  if(pppErr)
+    return pppErr;
+    
+  m_pIf->close();
+  
+  DBG("Powering off module.\n")
+  setOff(); //Power off module
+  
+  DBG("Off.\n")
+  
+  return PPP_OK;
+}
+  
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/gprsmodule/GPRSModuleNetIf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/gprsmodule/GPRSModuleNetIf.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,53 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef GPRSMODULENETIF_H
+#define GPRSMODULENETIF_H
+
+#include "mbed.h"
+
+#include "core/net.h"
+#include "if/ppp/PPPNetIf.h"
+
+#include "drv/gprs/GPRSModem.h"
+
+class GPRSModuleNetIf : protected PPPNetIf
+{
+public:
+  GPRSModuleNetIf(PinName tx, PinName rx, int baud = 115200); 
+  virtual ~GPRSModuleNetIf();
+  
+  PPPErr connect(const char* apn = NULL, const char* userId = NULL, const char* password = NULL); //Connect using GPRS
+  PPPErr disconnect();
+  
+protected:
+  virtual bool setOn() = 0; //True on success
+  virtual bool setOff() = 0; //True on success
+  
+private:
+  Serial m_serial;
+
+};
+
+#endif
+
diff -r 000000000000 -r 350011bf8be7 if/gprsmodule/HuaweiGTM900NetIf.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/gprsmodule/HuaweiGTM900NetIf.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,55 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "netCfg.h"
+#if NET_GPRS_MODULE
+
+#include "HuaweiGTM900NetIf.h"
+
+#define __DEBUG
+#include "dbg/dbg.h"
+
+HuaweiGTM900NetIf::HuaweiGTM900NetIf(PinName tx, PinName rx, int baud /*= 115200*/) : GPRSModuleNetIf(tx, rx, baud)
+{
+
+}
+
+HuaweiGTM900NetIf::~HuaweiGTM900NetIf()
+{
+
+}
+  
+bool HuaweiGTM900NetIf::setOn()
+{  
+  wait(5); //Wait for module to init.
+
+  return true;
+}
+
+bool HuaweiGTM900NetIf::setOff()
+{
+  return true;
+}
+  
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/gprsmodule/HuaweiGTM900NetIf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/gprsmodule/HuaweiGTM900NetIf.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,44 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef HUAWEIGTM900NETIF_H
+#define HUAWEIGTM900NETIF_H
+
+#include "mbed.h"
+
+#include "GPRSModuleNetIf.h"
+
+class HuaweiGTM900NetIf : public GPRSModuleNetIf
+{
+public:
+  HuaweiGTM900NetIf(PinName tx, PinName rx, int baud = 115200); 
+  virtual ~HuaweiGTM900NetIf();
+
+protected:
+  virtual bool setOn(); //True on success
+  virtual bool setOff(); //True on success  
+
+};
+
+#endif
+
diff -r 000000000000 -r 350011bf8be7 if/gprsmodule/TelitModuleNetIf.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/gprsmodule/TelitModuleNetIf.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,71 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "netCfg.h"
+#if NET_GPRS_MODULE
+
+#include "TelitModuleNetIf.h"
+
+#define __DEBUG
+#include "dbg/dbg.h"
+
+TelitModuleNetIf::TelitModuleNetIf(PinName tx, PinName rx, PinName pwrSetPin, PinName pwrMonPin, int baud /*= 115200*/) : GPRSModuleNetIf(tx, rx, baud), m_module(pwrSetPin, pwrMonPin)
+{
+
+}
+
+TelitModuleNetIf::~TelitModuleNetIf()
+{
+
+}
+  
+bool TelitModuleNetIf::setOn()
+{
+  if(m_module.isOn())
+  {
+    DBG("Resetting module...\n");
+    m_module.off(); //Reset module if needed
+  }
+  
+  wait(4);
+
+  DBG("Powering on module.\n")
+  if(!m_module.on()) //Could not power on module
+  {
+    DBG("Could not power on module.\n");
+    return false;
+  }
+  
+  wait(10); //Wait for module to init.
+
+  return true;
+}
+
+bool TelitModuleNetIf::setOff()
+{
+  DBG("Powering off module.\n")
+  return m_module.off(); //Power off module
+}
+  
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/gprsmodule/TelitModuleNetIf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/gprsmodule/TelitModuleNetIf.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,49 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef TELITMODULENETIF_H
+#define TELITMODULENETIF_H
+
+#include "mbed.h"
+
+#include "GPRSModuleNetIf.h"
+
+#include "drv/gprsmodule/TelitModule.h"
+
+class TelitModuleNetIf : public GPRSModuleNetIf
+{
+public:
+  TelitModuleNetIf(PinName tx, PinName rx, PinName pwrSetPin, PinName pwrMonPin, int baud = 115200); 
+  virtual ~TelitModuleNetIf();
+
+protected:
+  virtual bool setOn(); //True on success
+  virtual bool setOff(); //True on success  
+  
+private:
+  TelitModule m_module;
+
+};
+
+#endif
+
diff -r 000000000000 -r 350011bf8be7 if/lwip/LwipNetIf.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/lwip/LwipNetIf.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,98 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "LwipNetIf.h"
+#include "lwip/init.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/dns.h"
+
+#include "lwipNetTcpSocket.h"
+#include "lwipNetUdpSocket.h"
+#include "lwipNetDnsRequest.h"
+
+#include "netCfg.h"
+#if NET_LWIP_STACK
+
+//See doc/rawapi.txt for details
+
+LwipNetIf::LwipNetIf() : NetIf(), m_tcpTimer(), m_dnsTimer(), m_init(false)
+{  
+
+}
+
+
+LwipNetIf::~LwipNetIf()
+{
+
+}
+
+void LwipNetIf::init()
+{
+  if(m_init)
+    return;
+  m_init=true;
+  lwip_init(); //init lwip, see init.c for details
+  
+  //Setup Clocks
+  m_tcpTimer.start();
+  m_dnsTimer.start();
+  //m_tcpTicker.attach_us( tcp_tmr, TCP_TMR_INTERVAL * 1000 ); //TCP_TMR_INTERVAL = 250 ms in tcp_impl.h
+  //m_dnsTicker.attach_us( dns_tmr, DNS_TMR_INTERVAL * 1000 ); //DNS_TMR_INTERVAL = 1000 ms in dns.h
+}
+
+NetTcpSocket* LwipNetIf::tcpSocket()  //Create a new tcp socket
+{
+  return new LwipNetTcpSocket();
+}
+
+NetUdpSocket* LwipNetIf::udpSocket()  //Create a new udp socket
+{
+  return new LwipNetUdpSocket();
+}
+
+NetDnsRequest* LwipNetIf::dnsRequest(const char* hostname) //Create a new NetDnsRequest object
+{
+  return new LwipNetDnsRequest(hostname);
+}
+
+NetDnsRequest* LwipNetIf::dnsRequest(Host* pHost) //Create a new NetDnsRequest object
+{
+  return new LwipNetDnsRequest(pHost);
+}
+
+void LwipNetIf::poll()
+{
+  if(m_init && m_tcpTimer.read_ms() >= TCP_TMR_INTERVAL)
+  {
+    m_tcpTimer.reset();
+    tcp_tmr(); //Poll LwIP
+  }
+  if(m_init && m_dnsTimer.read_ms() >= DNS_TMR_INTERVAL)
+  {
+    m_dnsTimer.reset();
+    dns_tmr();
+  }
+  //Do some stuff...
+}
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/lwip/LwipNetIf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/lwip/LwipNetIf.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,62 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef LWIPNETIF_H
+#define LWIPNETIF_H
+
+//class Ticker;
+#include "mbed.h"
+
+#define NET_LWIP_STACK 1
+#include "core/net.h"
+#include "if/net/netif.h"
+/*
+#include "lwipNetTcpSocket.h"
+#include "lwipNetUdpSocket.h"
+#include "lwipNetDnsRequest.h"
+*/
+
+class LwipNetIf : public NetIf
+{
+public:
+  LwipNetIf();
+  virtual ~LwipNetIf();
+  
+  void init();
+
+  virtual NetTcpSocket* tcpSocket();  //Create a new tcp socket
+  virtual NetUdpSocket* udpSocket();  //Create a new udp socket
+  virtual NetDnsRequest* dnsRequest(const char* hostname); //Create a new NetDnsRequest object
+  virtual NetDnsRequest* dnsRequest(Host* pHost); //Create a new NetDnsRequest object
+
+  virtual void poll();
+
+private:
+  Timer m_tcpTimer;
+  Timer m_dnsTimer;
+  
+  bool m_init;
+
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/lwip/lwipNetDnsRequest.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/lwip/lwipNetDnsRequest.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,152 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "lwipNetDnsRequest.h"
+#include "lwip/err.h" //err_t, ERR_xxx
+#include "lwip/dns.h"
+
+#include "netCfg.h"
+#if NET_LWIP_STACK
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+LwipNetDnsRequest::LwipNetDnsRequest(const char* hostname) : NetDnsRequest(hostname), m_state(LWIPNETDNS_START), m_cbFired(false), m_closing(false)
+{
+  DBG("New LwipNetDnsRequest %p\n", this);
+}
+
+LwipNetDnsRequest::LwipNetDnsRequest(Host* pHost) : NetDnsRequest(pHost), m_state(LWIPNETDNS_START), m_cbFired(false), m_closing(false)
+{
+  DBG("New LwipNetDnsRequest %p\n", this);
+}
+
+LwipNetDnsRequest::~LwipNetDnsRequest()
+{
+  DBG("LwipNetDnsRequest %p destroyed\n", this);
+}
+
+/*
+Main useful function here (see lwip/dns.h):
+err_t          dns_gethostbyname(const char *hostname, ip_addr_t *addr,
+                                 dns_found_callback found, void *callback_arg);
+*/
+
+//Execute request & return OK if found, NOTFOUND or ERROR on error, or PROCESSING if the request has not completed yet
+void LwipNetDnsRequest::poll()
+{
+  err_t  err;
+  switch(m_state)
+  {
+  case LWIPNETDNS_START: //First req, let's call dns_gethostbyname
+    ip_addr_t ipStruct;
+    err = dns_gethostbyname(m_hostname, &ipStruct, LwipNetDnsRequest::sFoundCb, (void*) this );
+    if( err == ERR_OK )
+    {
+      m_ip = IpAddr(&ipStruct);
+      m_state = LWIPNETDNS_OK;
+      DBG("DNS: Ip found in cache.\n");
+    }
+    else if( err == ERR_INPROGRESS)
+    {
+      DBG("DNS: Processing.\n");
+      m_state = LWIPNETDNS_PROCESSING;
+    }
+    else //Likely ERR_VAL
+    {
+      DBG("DNS: Error on init.\n");
+      m_state = LWIPNETDNS_ERROR;
+    }
+    break;
+  case LWIPNETDNS_PROCESSING:
+    break; //Nothing to do, DNS is polled on interrupt
+  case LWIPNETDNS_OK:
+    if(!m_cbFired)
+    {
+      DBG("DNS: Ip found.\n");
+      m_cbFired = true;
+      onReply(NETDNS_FOUND); //Raise callback
+    }
+    break;
+  case LWIPNETDNS_NOTFOUND:
+    if(!m_cbFired)
+    {
+      DBG("DNS: could not be resolved.\n");
+      m_cbFired = true;
+      onReply(NETDNS_NOTFOUND); //Raise callback
+    }  
+    break;  
+  case LWIPNETDNS_ERROR:
+  default:
+    if(!m_cbFired)
+    {
+      DBG("DNS: Error.\n");
+      m_cbFired = true;
+      onReply(NETDNS_ERROR); //Raise callback
+    }  
+    break; 
+  }
+  if(m_closing && (m_state!=LWIPNETDNS_PROCESSING)) //Check wether the closure has been reqd
+  {
+    DBG("LwipNetDnsRequest: Closing in poll()\n");
+    NetDnsRequest::close();
+  }
+}
+
+void LwipNetDnsRequest::close()
+{
+  DBG("LwipNetDnsRequest: Close req\n");
+  if(m_state!=LWIPNETDNS_PROCESSING)
+  {
+    DBG("LwipNetDnsRequest: Closing in close()\n");
+    NetDnsRequest::close();
+  }
+  else //Cannot close rightaway, waiting for callback from underlying layer
+  {
+    m_closing = true;
+  }
+}
+
+void LwipNetDnsRequest::foundCb(const char *name, ip_addr_t *ipaddr)
+{
+  if( ipaddr == NULL )
+  {
+    DBG("LwipNetDnsRequest: Callback: Name not found\n");
+    m_state = LWIPNETDNS_NOTFOUND;
+    return;
+  }
+  DBG("LwipNetDnsRequest: Callback: Resolved\n");
+  m_ip = IpAddr(ipaddr);
+  m_state = LWIPNETDNS_OK;
+}
+
+
+void LwipNetDnsRequest::sFoundCb(const char *name, ip_addr_t *ipaddr, void *arg)
+{
+  DBG("LwipNetDnsRequest: Static callback\n");
+  LwipNetDnsRequest* pMe = (LwipNetDnsRequest*) arg;
+  return pMe->foundCb( name, ipaddr );
+}
+
+#endif
+
diff -r 000000000000 -r 350011bf8be7 if/lwip/lwipNetDnsRequest.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/lwip/lwipNetDnsRequest.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,67 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef LWIPNETDNSREQUEST_H
+#define LWIPNETDNSREQUEST_H
+
+#define NET_LWIP_STACK 1
+#include "if/net/netdnsrequest.h"
+
+//struct ip_addr_t;
+#include "lwip/ip_addr.h"
+
+class LwipNetDnsRequest : public NetDnsRequest
+{
+public:
+  LwipNetDnsRequest(const char* hostname);
+  LwipNetDnsRequest(Host* pHost);
+  virtual ~LwipNetDnsRequest();
+
+  //Execute request & return OK if found, NOTFOUND or ERROR on error, or PROCESSING if the request has not completed yet
+  virtual void poll();
+  
+  virtual void close();
+
+protected:
+  void foundCb(const char *name, ip_addr_t *ipaddr);
+  
+private:
+  enum LwipNetDnsState
+  {
+    LWIPNETDNS_START,
+    LWIPNETDNS_PROCESSING, //Req has not completed
+    LWIPNETDNS_NOTFOUND,
+    LWIPNETDNS_ERROR,
+    LWIPNETDNS_OK
+  };
+
+  LwipNetDnsState m_state;
+  bool m_cbFired;
+  
+  //Static callbacks : Transforms into a C++ callback
+  static void sFoundCb(const char *name, ip_addr_t *ipaddr, void *arg);
+  
+  bool m_closing;
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/lwip/lwipNetTcpSocket.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/lwip/lwipNetTcpSocket.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,456 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "lwipNetTcpSocket.h"
+#include "lwip/tcp.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#include "netCfg.h"
+#if NET_LWIP_STACK
+
+LwipNetTcpSocket::LwipNetTcpSocket(tcp_pcb* pPcb /*= NULL*/) : NetTcpSocket(), m_pPcb(pPcb), m_lpInNetTcpSocket(), //Passes a pcb if already created (by an accept req for instance), in that case transfers ownership
+m_pReadPbuf(NULL)
+{
+  DBG("New NetTcpSocket %p\n", (void*)this);
+  if(!m_pPcb)
+  {
+    m_pPcb = tcp_new();
+    DBG("Creating new PCB %p\n", m_pPcb);
+  }
+  if(m_pPcb)
+  {
+    //Setup callbacks
+    tcp_arg( (tcp_pcb*) m_pPcb, (void*) this ); //this will be passed to each static callback
+    
+    tcp_recv( (tcp_pcb*) m_pPcb, LwipNetTcpSocket::sRecvCb );
+    tcp_sent((tcp_pcb*) m_pPcb, LwipNetTcpSocket::sSentCb );
+    tcp_err( (tcp_pcb*) m_pPcb, LwipNetTcpSocket::sErrCb );
+    //Connected callback is defined in connect()
+    //Accept callback is defined in listen()
+    DBG("NetTcpSocket created.\n");
+  }
+}
+
+LwipNetTcpSocket::~LwipNetTcpSocket()
+{
+/*  if(m_pPcb)
+    tcp_close( (tcp_pcb*) m_pPcb); //Disconnect & free pcb*/
+  close();
+}
+  
+NetTcpSocketErr LwipNetTcpSocket::bind(const Host& me)
+{
+  if(!m_pPcb)
+    return NETTCPSOCKET_MEM; //NetTcpSocket was not properly initialised, should destroy it & retry
+    
+  err_t err = tcp_bind( (tcp_pcb*) m_pPcb, IP_ADDR_ANY, me.getPort()); //IP_ADDR_ANY : Bind the connection to all local addresses
+  if(err)
+    return NETTCPSOCKET_INUSE;
+    
+  return NETTCPSOCKET_OK;
+}
+
+NetTcpSocketErr LwipNetTcpSocket::listen()
+{
+  if(!m_pPcb)
+    return NETTCPSOCKET_MEM; //NetTcpSocket was not properly initialised, should destroy it & retry
+/*
+  From doc/rawapi.txt :
+  
+  The tcp_listen() function returns a new connection identifier, and
+  the one passed as an argument to the function will be
+  deallocated. The reason for this behavior is that less memory is
+  needed for a connection that is listening, so tcp_listen() will
+  reclaim the memory needed for the original connection and allocate a
+  new smaller memory block for the listening connection.
+*/
+
+//  tcp_pcb* pNewPcb = tcp_listen(m_pPcb);
+  tcp_pcb* pNewPcb = tcp_listen_with_backlog((tcp_pcb*)m_pPcb, 5);
+  if( !pNewPcb ) //Not enough memory to create the listening pcb
+    return NETTCPSOCKET_MEM;
+
+  m_pPcb = pNewPcb;
+  
+  tcp_accept( (tcp_pcb*) m_pPcb, LwipNetTcpSocket::sAcceptCb );
+
+  return NETTCPSOCKET_OK;
+}
+
+NetTcpSocketErr LwipNetTcpSocket::connect(const Host& host)
+{
+  if(!m_pPcb)
+    return NETTCPSOCKET_MEM; //NetTcpSocket was not properly initialised, should destroy it & retry
+  
+  ip_addr_t ip = host.getIp().getStruct();
+  err_t err = tcp_connect( (tcp_pcb*) m_pPcb, &ip, host.getPort(), LwipNetTcpSocket::sConnectedCb );
+  
+  if(err)
+    return NETTCPSOCKET_MEM;
+    
+  return NETTCPSOCKET_OK;
+}
+
+NetTcpSocketErr LwipNetTcpSocket::accept(Host* pClient, NetTcpSocket** ppNewNetTcpSocket)
+{
+  if( !m_pPcb ) //Pcb doesn't exist (anymore)
+    return NETTCPSOCKET_MEM;
+  //Dequeue a connection
+  //if( m_lpInPcb.empty() )
+  if( m_lpInNetTcpSocket.empty() )
+    return NETTCPSOCKET_EMPTY;
+  
+  tcp_accepted( ((tcp_pcb*) m_pPcb) ); //Should fire proper events //WARN: m_pPcb is the GOOD param here (and not pInPcb)
+  
+/*  tcp_pcb* pInPcb = m_lpInPcb.front();
+  m_lpInPcb.pop();*/
+  
+  if( (m_lpInNetTcpSocket.front()) == NULL )
+  {
+    m_lpInNetTcpSocket.pop();
+    return NETTCPSOCKET_RST;
+  }
+  
+  if( (m_lpInNetTcpSocket.front())->m_closed )
+  {
+    Net::releaseTcpSocket(m_lpInNetTcpSocket.front());
+    m_lpInNetTcpSocket.pop();
+    return NETTCPSOCKET_RST;
+  }
+  
+  ip_addr_t* ip = (ip_addr_t*) &( (m_lpInNetTcpSocket.front()->m_pPcb)->remote_ip);
+  
+  *ppNewNetTcpSocket = m_lpInNetTcpSocket.front();
+  *pClient = Host(
+    IpAddr( 
+      ip
+    ), 
+    m_lpInNetTcpSocket.front()->m_pPcb->remote_port 
+  );
+  m_lpInNetTcpSocket.pop();
+//  *pClient = Host( IpAddr(pInPcb->remote_ip), pInPcb->remote_port );
+  
+  //Return a new socket
+ // *ppNewNetTcpSocket = (NetTcpSocket*) new LwipNetTcpSocket(pInPcb);
+
+  //tcp_accepted( ((tcp_pcb*) m_pPcb) ); //Should fire proper events //WARN: m_pPcb is the GOOD param here (and not pInPcb)
+  
+/*  if(*ppNewNetTcpSocket == NULL)
+  {
+    DBG("Not enough mem, socket dropped in LwipNetTcpSocket::accept.\n");
+    tcp_abort(pInPcb);
+  }*/
+  
+  return NETTCPSOCKET_OK;
+}
+
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+int /*if < 0 : NetTcpSocketErr*/ LwipNetTcpSocket::send(const char* buf, int len)
+{
+  if( !m_pPcb ) //Pcb doesn't exist (anymore)
+    return NETTCPSOCKET_MEM;
+  int outLen = MIN( len, tcp_sndbuf( (tcp_pcb*) m_pPcb) ); 
+  //tcp_sndbuf() returns the number of bytes available in the output queue, so never go above it
+  err_t err = tcp_write( (tcp_pcb*) m_pPcb, (void*) buf, outLen, TCP_WRITE_FLAG_COPY );
+  //Flags are TCP_WRITE_FLAG_COPY & TCP_WRITE_FLAG_MORE (see tcp_out.c) :
+  //If TCP_WRITE_FLAG_MORE is not set ask client to push buffered data to app
+  if(err)
+  {
+    switch( err )
+    {
+    case ERR_CONN:
+      return (int) NETTCPSOCKET_SETUP; //Not connected properly
+    case ERR_ARG:
+      return (int) NETTCPSOCKET_SETUP; //Wrong args ! (like buf pointing to NULL)
+    case ERR_MEM:
+    default:
+      return (int) NETTCPSOCKET_MEM; //Not enough memory
+    }
+  }
+  return outLen;
+}
+
+int /*if < 0 : NetTcpSocketErr*/ LwipNetTcpSocket::recv(char* buf, int len)
+{
+  if( !m_pPcb ) //Pcb doesn't exist (anymore)
+    return NETTCPSOCKET_MEM;
+  int inLen = 0;
+  int cpyLen = 0;
+  
+  static int rmgLen = 0; 
+  //Contains the remaining len in this pbuf
+  
+  if( !m_pReadPbuf )
+  {
+    rmgLen = 0;
+    return 0;
+  }
+  
+  if ( !rmgLen ) //We did not know m_pReadPbuf->len last time we called this fn
+  {
+    rmgLen = m_pReadPbuf->len;
+  }
+  
+  while ( inLen < len )
+  {
+    cpyLen = MIN( (len - inLen), rmgLen ); //Remaining len to copy, remaining len in THIS pbuf
+    memcpy((void*)buf, (void*)((char*)(m_pReadPbuf->payload) + (m_pReadPbuf->len - rmgLen)), cpyLen);
+    inLen += cpyLen;
+    buf += cpyLen;
+    
+    rmgLen = rmgLen - cpyLen; //Update rmgLen
+    
+    if( rmgLen > 0 )
+    {
+      //We did not read this pbuf completely, so let's save it's pos & return
+      break;
+    }
+    
+    if(m_pReadPbuf->next)
+    {
+      pbuf* pNextPBuf = m_pReadPbuf->next;
+      m_pReadPbuf->next = NULL; //So that it is not freed as well
+      //We get the reference to pNextPBuf from m_pReadPbuf
+      pbuf_free((pbuf*)m_pReadPbuf);
+      m_pReadPbuf = pNextPBuf;
+      rmgLen = m_pReadPbuf->len;
+    }
+    else
+    {
+      pbuf_free((pbuf*)m_pReadPbuf);
+      m_pReadPbuf = NULL;
+      rmgLen = 0;
+      break; //No more data to read
+    }
+    
+  }
+  
+  //tcp_recved(m_pPcb, inLen); //Acknowledge the reception
+  
+  return inLen;
+}
+
+NetTcpSocketErr LwipNetTcpSocket::close()
+{
+  //DBG("LwipNetTcpSocket::close() : Closing...\n");
+
+  if(m_closed)
+    return NETTCPSOCKET_OK; //Already being closed
+  m_closed = true;
+  
+  if( !m_pPcb ) //Pcb doesn't exist (anymore)
+    return NETTCPSOCKET_MEM;
+    
+  //Cleanup incoming data
+  cleanUp();
+ 
+  if( !!tcp_close( (tcp_pcb*) m_pPcb) )
+  {
+    DBG("LwipNetTcpSocket::close() could not close properly, abort.\n");
+    tcp_abort( (tcp_pcb*) m_pPcb);
+    m_pPcb = NULL;
+    return NETTCPSOCKET_MEM;
+  }
+  
+  DBG("LwipNetTcpSocket::close() : connection closed successfully.\n");
+  
+  m_pPcb = NULL;
+  return NETTCPSOCKET_OK;
+}
+
+NetTcpSocketErr LwipNetTcpSocket::poll()
+{
+  NetTcpSocket::flushEvents();
+  return NETTCPSOCKET_OK;
+}
+
+// Callbacks events
+
+err_t LwipNetTcpSocket::acceptCb(struct tcp_pcb *newpcb, err_t err)
+{
+  if(err)
+  {
+    DBG("Error %d in LwipNetTcpSocket::acceptCb.\n", err);
+    return err;
+  }
+  //FIXME: MEM Errs
+  //m_lpInPcb.push(newpcb); //Add connection to the queue
+  LwipNetTcpSocket* pNewNetTcpSocket = new LwipNetTcpSocket(newpcb);
+  
+  if(pNewNetTcpSocket == NULL)
+  {
+    DBG("Not enough mem, socket dropped in LwipNetTcpSocket::acceptCb.\n");
+    tcp_abort(newpcb);
+    return ERR_ABRT;
+  }
+  
+  pNewNetTcpSocket->m_refs++;
+  m_lpInNetTcpSocket.push( pNewNetTcpSocket );
+  
+ // tcp_accepted(newpcb);
+ // tcp_accepted( m_pPcb ); //Should fire proper events //WARN: m_pPcb is the GOOD param here (and not pInPcb)
+  queueEvent(NETTCPSOCKET_ACCEPT);
+  return ERR_OK;
+}
+
+err_t LwipNetTcpSocket::connectedCb(struct tcp_pcb *tpcb, err_t err)
+{
+  queueEvent(NETTCPSOCKET_CONNECTED);
+  return ERR_OK;
+}
+
+void LwipNetTcpSocket::errCb(err_t err)
+{
+  DBG("NetTcpSocket %p - Error %d in LwipNetTcpSocket::errCb.\n", (void*)this, err);
+  //WARN: At this point, m_pPcb has been freed by lwIP
+  m_pPcb = NULL;
+  //These errors are fatal, discard all events queued before so that the errors are handled first
+  discardEvents();
+  m_closed = true;
+  cleanUp();
+  if( err == ERR_ABRT)
+    queueEvent(NETTCPSOCKET_CONABRT);
+  else //if( err == ERR_RST)
+    queueEvent(NETTCPSOCKET_CONRST);
+}
+  
+err_t LwipNetTcpSocket::sentCb(tcp_pcb* tpcb, u16_t len)
+{
+//  DBG("%d bytes ACKed by host.\n", len);
+  queueEvent(NETTCPSOCKET_WRITEABLE);
+  return ERR_OK;
+}
+
+err_t LwipNetTcpSocket::recvCb(tcp_pcb* tpcb, pbuf *p, err_t err)
+{
+  //Store pbuf ptr
+ // DBG("Receive CB with err = %d & len = %d.\n", err, p->tot_len);
+//  tcp_recved( (tcp_pcb*) m_pPcb, p->tot_len); //Acknowledge the reception
+  
+  if(err)
+  {
+    queueEvent(NETTCPSOCKET_ERROR);
+    return ERR_OK; //FIXME: More robust error handling there
+  }
+  else if(!p)
+  {
+    DBG("NetTcpSocket %p - Connection closed by remote host (LwipNetTcpSocket::recvCb).\n", (void*)this);
+    //Buf is NULL, that means that the connection has been closed by remote host
+    
+    //FIX: 27/05/2010: We do not want to deallocate the socket while some data might still be readable
+    //REMOVED:   close();
+ 
+    //However we do not want to close the socket yet
+ 
+    queueEvent(NETTCPSOCKET_DISCONNECTED);
+    return ERR_OK; 
+  }
+  
+  //We asserted that p is a valid pointer
+
+  //New data processing
+  tcp_recved( tpcb, p->tot_len); //Acknowledge the reception
+  if(!m_pReadPbuf)
+  {
+    m_pReadPbuf = p;
+    queueEvent(NETTCPSOCKET_READABLE);
+  }
+  else
+  {
+    pbuf_cat((pbuf*)m_pReadPbuf, p); //m_pReadPbuf is not empty, tail p to it and drop our ref
+    //No need to queue an event in that case since the read buf has not been processed yet
+  }
+  return ERR_OK;
+}
+
+
+void LwipNetTcpSocket::cleanUp() //Flush input buffer
+{
+  //Ensure that further error won't be followed to this inst (which can be destroyed)
+  if( m_pPcb )
+  {
+    tcp_arg( (tcp_pcb*) m_pPcb, (void*) NULL );
+    tcp_recv( (tcp_pcb*) m_pPcb, NULL );
+    tcp_sent((tcp_pcb*) m_pPcb, NULL );
+    tcp_err( (tcp_pcb*) m_pPcb, NULL );
+  }
+  
+  if( m_pReadPbuf )
+  {
+    DBG("Deallocating unread data.\n");
+    pbuf_free((pbuf*)m_pReadPbuf); //Free all unread data
+    m_pReadPbuf = NULL;
+    recv(NULL,0); //Update recv ptr position
+  }
+}
+
+// Static callbacks from LwIp
+
+err_t LwipNetTcpSocket::sAcceptCb(void *arg, struct tcp_pcb *newpcb, err_t err)
+{
+  LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
+  return pMe->acceptCb( newpcb, err );
+}
+
+err_t LwipNetTcpSocket::sConnectedCb(void *arg, struct tcp_pcb *tpcb, err_t err)
+{
+  LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
+  return pMe->connectedCb( tpcb, err );
+}
+
+void LwipNetTcpSocket::sErrCb(void *arg, err_t err)
+{
+  if( !arg )
+  {
+    DBG("NetTcpSocket - Error %d in LwipNetTcpSocket::sErrCb.\n", err);
+    return; //The socket has been destroyed, discard error
+  }
+  LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
+  return pMe->errCb( err );
+}
+  
+err_t LwipNetTcpSocket::sSentCb(void *arg, struct tcp_pcb *tpcb, u16_t len)
+{
+  LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
+  return pMe->sentCb( tpcb, len );
+}
+
+err_t LwipNetTcpSocket::sRecvCb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
+{
+  if( tpcb->flags & TF_RXCLOSED )
+  {
+    //The Pcb is in a closing state
+    //Discard that data here since we might have destroyed the corresponding socket object
+    tcp_recved( tpcb, p->tot_len);
+    pbuf_free( p );    
+    return ERR_OK;
+  }
+  LwipNetTcpSocket* pMe = (LwipNetTcpSocket*) arg;
+  return pMe->recvCb( tpcb, p, err );
+}
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/lwip/lwipNetTcpSocket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/lwip/lwipNetTcpSocket.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,90 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef LWIPNETTCPSOCKET_H
+#define LWIPNETTCPSOCKET_H
+
+#define NET_LWIP_STACK 1
+#include "if/net/nettcpsocket.h"
+#include "LwipNetIf.h"
+
+#include "stdint.h"
+
+//Implements NetTcpSockets over lwIP raw API
+
+struct tcp_pcb; //Represents a Tcp Connection, "Protocol Control Block", see rawapi.txt & tcp.h
+struct pbuf; //Lwip Buffer Container
+
+typedef signed char err_t;
+typedef uint16_t u16_t;
+
+class LwipNetTcpSocket: public NetTcpSocket
+{
+public:
+  LwipNetTcpSocket(tcp_pcb* pPcb = NULL); //Passes a pcb if already created (by an accept req for instance), in that case transfers ownership
+  virtual ~LwipNetTcpSocket();
+  
+  virtual NetTcpSocketErr bind(const Host& me);
+  virtual NetTcpSocketErr listen();
+  virtual NetTcpSocketErr connect(const Host& host);
+  virtual NetTcpSocketErr accept(Host* pClient, NetTcpSocket** ppNewNetTcpSocket);
+  
+  virtual int /*if < 0 : NetTcpSocketErr*/ send(const char* buf, int len);
+  virtual int /*if < 0 : NetTcpSocketErr*/ recv(char* buf, int len);
+
+  virtual NetTcpSocketErr close();
+
+  virtual NetTcpSocketErr poll();
+  
+protected:
+  volatile tcp_pcb* m_pPcb;
+  
+  //Events callbacks from lwIp
+  err_t acceptCb(tcp_pcb* newpcb, err_t err);
+  err_t connectedCb(tcp_pcb* tpcb, err_t err);
+  
+  void errCb(err_t err);
+  
+  err_t sentCb(tcp_pcb* tpcb, u16_t len);
+  err_t recvCb(tcp_pcb* tpcb, pbuf *p, err_t err);
+  
+private:
+  void cleanUp(); //Flush input buffer
+
+//  queue<tcp_pcb*> m_lpInPcb; //Incoming connections that have not been accepted yet
+  queue<LwipNetTcpSocket*> m_lpInNetTcpSocket; //Incoming connections that have not been accepted yet
+  
+  volatile pbuf* m_pReadPbuf; //Ptr to read buffer
+  
+  //Static callbacks : Transforms into a C++ callback
+  static err_t sAcceptCb(void *arg, struct tcp_pcb *newpcb, err_t err);
+  static err_t sConnectedCb(void *arg, struct tcp_pcb *tpcb, err_t err);
+  
+  static void sErrCb(void *arg, err_t err);
+  
+  static err_t sSentCb(void *arg, struct tcp_pcb *tpcb, u16_t len);
+  static err_t sRecvCb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
+  
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/lwip/lwipNetUdpSocket.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/lwip/lwipNetUdpSocket.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,265 @@
+#pragma diag_remark 1464
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "lwip/ip_addr.h"
+#include "lwipNetUdpSocket.h"
+#include "lwip/udp.h"
+#include "lwip/igmp.h"
+
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#include "netCfg.h"
+#if NET_LWIP_STACK
+
+LwipNetUdpSocket::LwipNetUdpSocket(udp_pcb* pPcb /*= NULL*/) : NetUdpSocket(), m_pPcb(pPcb), m_lInPkt(), m_multicastGroup() //Passes a pcb if already created (by an accept req for instance), in that case transfers ownership
+{
+  DBG("New LwipNetUdpSocket %p (pPCb=%p)\n", (void*)this, (void*) pPcb);
+  if(!m_pPcb)
+    m_pPcb = udp_new();
+  if(m_pPcb)
+  {
+    //Setup callback
+    udp_recv( (udp_pcb*) m_pPcb, LwipNetUdpSocket::sRecvCb, (void*) this );
+  }
+}
+
+LwipNetUdpSocket::~LwipNetUdpSocket()
+{
+  close();
+}
+  
+NetUdpSocketErr LwipNetUdpSocket::bind(const Host& me)
+{
+  err_t err;
+  
+  if(!m_pPcb)
+    return NETUDPSOCKET_MEM; //NetUdpSocket was not properly initialised, should destroy it & retry
+   
+  #if LWIP_IGMP //Multicast support enabled
+  if(me.getIp().isMulticast())
+  {
+    DBG("This is a multicast addr, joining multicast group\n");
+    m_multicastGroup = me.getIp();
+    err = igmp_joingroup(IP_ADDR_ANY, &(m_multicastGroup.getStruct()));
+    if(err)
+      return NETUDPSOCKET_IF; //Could not find or create group
+  }
+  #endif
+
+  err = udp_bind( (udp_pcb*) m_pPcb, IP_ADDR_ANY, me.getPort()); //IP_ADDR_ANY : Bind the connection to all local addresses
+  if(err)
+    return NETUDPSOCKET_INUSE;
+
+  //Setup callback
+  udp_recv( (udp_pcb*) m_pPcb, LwipNetUdpSocket::sRecvCb, (void*) this );
+    
+  return NETUDPSOCKET_OK;
+}
+
+#define MAX(a,b) ((a>b)?a:b)
+#define MIN(a,b) ((a<b)?a:b)
+
+int /*if < 0 : NetUdpSocketErr*/ LwipNetUdpSocket::sendto(const char* buf, int len, Host* pHost)
+{
+  if( !m_pPcb ) //Pcb doesn't exist (anymore)
+    return NETUDPSOCKET_MEM;
+  pbuf* p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_POOL);
+  if( !p )
+    return NETUDPSOCKET_MEM;
+  char* pBuf = (char*) buf;
+  pbuf* q = p; 
+  do
+  {
+    memcpy (q->payload, (void*)pBuf, q->len);  
+    pBuf += q->len;
+    q = q->next;
+  } while(q != NULL);
+
+  err_t err = udp_sendto( (udp_pcb*) m_pPcb, p, &(pHost->getIp().getStruct()), pHost->getPort() );
+  pbuf_free( p );
+  if(err)
+    return NETUDPSOCKET_SETUP; //Connection problem
+  DBG("%d bytes sent in UDP Socket.\n", len);
+  return len;
+}
+
+int /*if < 0 : NetUdpSocketErr*/ LwipNetUdpSocket::recvfrom(char* buf, int len, Host* pHost)
+{
+  if( !m_pPcb ) //Pcb doesn't exist (anymore)
+    return NETUDPSOCKET_MEM;
+  int inLen = 0;
+  int cpyLen = 0;
+  
+  static int rmgLen = 0; 
+  //Contains the remaining len in this pbuf
+  
+  if( m_lInPkt.empty() )
+    return 0;
+    
+  pbuf* pBuf = (pbuf*) m_lInPkt.front().pBuf;
+  
+  if(pHost)
+    *pHost = Host( IpAddr(&m_lInPkt.front().addr), m_lInPkt.front().port );
+  
+  if( !pBuf )
+  {
+    rmgLen = 0;
+    return 0;
+  }
+  
+  if ( !rmgLen ) //We did not know m_pReadPbuf->len last time we called this fn
+  {
+    rmgLen = pBuf->len;
+  }
+  
+  while ( inLen < len )
+  {
+    cpyLen = MIN( (len - inLen), rmgLen ); //Remaining len to copy, remaining len in THIS pbuf
+    memcpy((void*)buf, (void*)((char*)(pBuf->payload) + (pBuf->len - rmgLen)), cpyLen);
+    inLen += cpyLen;
+    buf += cpyLen;
+    
+    rmgLen = rmgLen - cpyLen; //Update rmgLen
+    
+    if( rmgLen > 0 )
+    {
+      //We did not read this pbuf completely, so let's save it's pos & return
+      break;
+    }
+    
+    if(pBuf->next)
+    {
+      pbuf* pNextPBuf = pBuf->next;
+      pBuf->next = NULL; //So that it is not freed as well
+      //We get the reference to pNextPBuf from m_pReadPbuf
+      pbuf_free((pbuf*)pBuf);
+      pBuf = pNextPBuf;
+      rmgLen = pBuf->len;
+    }
+    else
+    {
+      pbuf_free((pbuf*)pBuf);
+      pBuf = NULL;
+      rmgLen = 0;
+      m_lInPkt.pop_front();
+      break; //No more data to read
+    } 
+  }
+  
+  return inLen;
+}
+
+NetUdpSocketErr LwipNetUdpSocket::close()
+{
+  DBG("LwipNetUdpSocket::close() : Closing...\n");
+
+  if(m_closed)
+    return NETUDPSOCKET_OK; //Already being closed
+  m_closed = true;
+  
+  if( !m_pPcb ) //Pcb doesn't exist (anymore)
+    return NETUDPSOCKET_MEM;
+    
+  DBG("LwipNetUdpSocket::close() : Cleanup...\n");
+    
+  //Cleanup incoming data
+  cleanUp();
+  
+
+  DBG("LwipNetUdpSocket::close() : removing m_pPcb...\n");
+  udp_remove( (udp_pcb*) m_pPcb);
+    
+  m_pPcb = NULL;
+  return NETUDPSOCKET_OK;
+}
+
+NetUdpSocketErr LwipNetUdpSocket::poll()
+{
+  NetUdpSocket::flushEvents();
+  return NETUDPSOCKET_OK;
+}
+
+// Callbacks events
+
+void LwipNetUdpSocket::recvCb(udp_pcb* pcb, struct pbuf* p, ip_addr_t* addr, u16_t port)
+{
+  DBG(" Packet of length %d arrived in UDP Socket.\n", p->tot_len);
+  list<InPacket>::iterator it;
+  for ( it = m_lInPkt.begin(); it != m_lInPkt.end(); it++ )
+  {
+    if( ip_addr_cmp((&((*it).addr)), addr) && ((*it).port == port) )
+    {
+      //Let's tail this packet to the previous one
+      pbuf_cat((pbuf*)((*it).pBuf), p);
+      //No need to queue an event in that case since the read buf has not been processed yet
+      return;
+    }
+  }
+
+  //New host, add a packet to the queue
+  InPacket pkt;
+  pkt.pBuf = p;
+  pkt.addr = *addr;
+  pkt.port = port;
+  m_lInPkt.push_back(pkt);
+  
+  queueEvent(NETUDPSOCKET_READABLE);
+}
+
+void LwipNetUdpSocket::cleanUp() //Flush input buffer
+{
+  //Ensure that further error won't be followed to this inst (which can be destroyed)
+  if( m_pPcb )
+  {
+    udp_recv( (udp_pcb*) m_pPcb, NULL, (void*) NULL );
+  }
+  
+  //Leaving multicast group(Ok because LwIP has a refscount for multicast group)
+  #if LWIP_IGMP //Multicast support enabled
+  if(m_multicastGroup.isMulticast())
+  {
+    igmp_leavegroup(IP_ADDR_ANY, &(m_multicastGroup.getStruct()));
+    m_multicastGroup = IpAddr();
+  }
+  #endif
+  
+  list<InPacket>::iterator it;
+  for ( it = m_lInPkt.begin(); it != m_lInPkt.end(); it++ )
+  {
+    //Free buf
+    pbuf_free((pbuf*)((*it).pBuf));
+  } 
+  m_lInPkt.clear();
+}
+
+// Static callback from LwIp
+
+void LwipNetUdpSocket::sRecvCb(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+  LwipNetUdpSocket* pMe = (LwipNetUdpSocket*) arg;
+  return pMe->recvCb( pcb, p, addr, port );
+}
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/lwip/lwipNetUdpSocket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/lwip/lwipNetUdpSocket.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,84 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef LWIPNETUDPSOCKET_H
+#define LWIPNETUDPSOCKET_H
+
+#define NET_LWIP_STACK 1
+//#include "lwip/ip_addr.h"
+#include "if/net/netudpsocket.h"
+#include "LwipNetIf.h"
+
+#include "stdint.h"
+
+#include <list>
+using std::list;
+
+//Implements NetUdpSockets over lwIP raw API
+
+struct udp_pcb; //Represents a Udp Connection, "Protocol Control Block", see rawapi.txt & udp.h
+struct pbuf; //Lwip Buffer Container
+typedef struct ip_addr ip_addr_t;
+
+//typedef signed char err_t;
+typedef uint16_t u16_t;
+
+class LwipNetUdpSocket: public NetUdpSocket
+{
+public:
+  LwipNetUdpSocket(udp_pcb* pPcb = NULL); //Passes a pcb if already created (by an accept req for instance), in that case transfers ownership
+  virtual ~LwipNetUdpSocket();
+  
+  virtual NetUdpSocketErr bind(const Host& me);
+  
+  virtual int /*if < 0 : NetUdpSocketErr*/ sendto(const char* buf, int len, Host* pHost);
+  virtual int /*if < 0 : NetUdpSocketErr*/ recvfrom(char* buf, int len, Host* pHost);
+
+  virtual NetUdpSocketErr close();
+
+  virtual NetUdpSocketErr poll();
+  
+protected:
+  volatile udp_pcb* m_pPcb;
+  
+  //Event callback from lwIp
+  void recvCb(udp_pcb* pcb, struct pbuf* p, ip_addr_t* addr, u16_t port);
+  
+private:
+  void cleanUp(); //Flush input buffer
+  struct InPacket
+  {
+    volatile pbuf* pBuf;
+    ip_addr_t addr;
+    u16_t port;
+  };
+  
+  list<InPacket> m_lInPkt;
+  IpAddr m_multicastGroup;
+  
+  //Static callback : Transforms into a C++ callback
+  static void sRecvCb(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
+  
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/net/netdnsrequest.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/net/netdnsrequest.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,66 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "netdnsrequest.h"
+#include <string.h>
+
+NetDnsRequest::NetDnsRequest(const char* hostname) : NetService(), m_ip(0,0,0,0), m_pCbItem(NULL), m_pCbMeth(NULL), m_pHost(NULL), m_closed(false)
+{
+  m_hostname = new char[strlen(hostname)+1];
+  strcpy( m_hostname, hostname );
+}
+
+NetDnsRequest::NetDnsRequest(Host* pHost)  : NetService(), m_ip(0,0,0,0), m_pCbItem(NULL), m_pCbMeth(NULL), m_closed(false)
+{
+  m_hostname = (char*) pHost->getName();
+  m_pHost = pHost;
+}
+
+NetDnsRequest::~NetDnsRequest()
+{
+  close();
+}
+   
+void NetDnsRequest::getResult(IpAddr* pIp)
+{
+  if( pIp != NULL )
+    *pIp = m_ip;
+}
+
+void NetDnsRequest::close()
+{
+  if(m_closed)
+    return;
+  m_closed = true;
+  if( !m_pHost )
+    delete[] m_hostname;
+  NetService::close();
+}
+  
+void NetDnsRequest::onReply(NetDnsReply reply) //Must be called by impl when the request completes
+{
+  if( m_pHost )
+    m_pHost->setIp(m_ip);
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)(reply);
+}
diff -r 000000000000 -r 350011bf8be7 if/net/netdnsrequest.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/net/netdnsrequest.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,84 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef NETDNSREQUEST_H
+#define NETDNSREQUEST_H
+
+//class Socket;
+class Host;
+//class NetService;
+class NetDnsRequest;
+
+#include "netservice.h"
+#include "ipaddr.h"
+#include "host.h"
+
+enum NetDnsReply
+{
+  NETDNS_PRTCL,
+  NETDNS_NOTFOUND, //Hostname is unknown
+  NETDNS_ERROR, //Problem with DNS Service
+  //...
+  NETDNS_FOUND,
+};
+
+class NetDnsRequest : public NetService
+{
+public:
+  NetDnsRequest(const char* hostname);
+  NetDnsRequest(Host* pHost);
+  virtual ~NetDnsRequest();
+  
+  class CDummy;
+  template<class T> 
+  //Linker bug : Must be defined here :(
+  void setOnReply( T* pItem, void (T::*pMethod)(NetDnsReply) )
+  {
+    m_pCbItem = (CDummy*) pItem;
+    m_pCbMeth = (void (CDummy::*)(NetDnsReply)) pMethod;
+  }
+  
+  //Execute request & return OK if found, NOTFOUND or ERROR on error, or PROCESSING if the request has not completed yet
+ // virtual DnsErr pollState() = 0;
+  virtual void poll() = 0; //NetService fn
+  
+  void getResult(IpAddr* pIp);
+  
+  virtual void close();
+  
+protected:
+  void onReply(NetDnsReply reply); //Must be called by impl when the request completes
+  
+  IpAddr m_ip;
+  char* m_hostname;
+
+private:  
+  CDummy* m_pCbItem;
+  void (CDummy::*m_pCbMeth)(NetDnsReply);
+  
+  Host* m_pHost;
+  
+  bool m_closed;
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/net/netif.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/net/netif.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,43 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "core/host.h"
+#include "netif.h"
+#include "core/net.h"
+
+NetIf::NetIf() : m_ip(0,0,0,0)
+{
+  Net::registerIf(this);
+  //Assuming that we only have one if
+  Net::setDefaultIf(this);
+}
+
+NetIf::~NetIf()
+{
+  Net::unregisterIf(this);
+}
+
+IpAddr NetIf::getIp() const
+{
+  return m_ip;
+}
diff -r 000000000000 -r 350011bf8be7 if/net/netif.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/net/netif.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,64 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef NETIF_H
+#define NETIF_H
+
+#include "core/ipaddr.h"
+/*
+#include "nettcpsocket.h"
+#include "netudpsocket.h"
+#include "netdnsrequest.h"
+*/
+class NetTcpSocket;
+class NetUdpSocket;
+class NetDnsRequest;
+
+#if 0
+enum NetifEvent
+{
+  NETIF_CONNECTED, //Connected, can create & use sockets now
+  NETIF_DNSREPLY,
+  NETIF_DISCONNECTED
+};
+#endif
+
+class NetIf
+{
+public:
+  NetIf();
+  virtual ~NetIf();
+  virtual NetTcpSocket* tcpSocket() = 0; //Create a new tcp socket
+  virtual NetUdpSocket* udpSocket() = 0; //Create a new udp socket
+  virtual void poll() = 0;
+  virtual NetDnsRequest* dnsRequest(const char* hostname) = 0; //Create a new NetDnsRequest object
+  virtual NetDnsRequest* dnsRequest(Host* pHost) = 0; //Create a new NetDnsRequest object
+  
+  //!Returns the IP of the interface once it's connected
+  IpAddr getIp() const;
+  
+protected:
+  IpAddr m_ip;
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/net/nettcpsocket.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/net/nettcpsocket.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,82 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "nettcpsocket.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+NetTcpSocket::NetTcpSocket() : m_host(), m_client(), m_refs(0), m_closed(false), m_removed(false), m_pCbItem(NULL), m_pCbMeth(NULL), m_events()
+{
+  Net::registerNetTcpSocket(this);
+}
+
+NetTcpSocket::~NetTcpSocket() //close()
+{
+  Net::unregisterNetTcpSocket(this);
+}
+  
+   
+//Callbacks
+#ifdef __LINKER_BUG_SOLVED__
+void NetTcpSocket::setOnEvent()
+{
+  m_pCbItem = (CDummy*) pItem;
+  m_pCbMeth = (void (CDummy::*)(NetTcpSocketEvent)) pMethod;
+}
+#endif
+
+void NetTcpSocket::resetOnEvent()
+{
+  m_pCbItem = NULL;
+  m_pCbMeth = NULL;
+}
+
+void NetTcpSocket::queueEvent(NetTcpSocketEvent e)
+{
+  m_events.push(e);
+}
+
+void NetTcpSocket::discardEvents()
+{
+  while( !m_events.empty() )
+  {
+    m_events.pop();
+  }
+}
+
+void NetTcpSocket::flushEvents() //To be called during polling
+{ 
+  while( !m_events.empty() )
+  {
+    onEvent(m_events.front());
+    m_events.pop();
+  }
+}
+
+void NetTcpSocket::onEvent(NetTcpSocketEvent e) //To be called during polling
+{
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)(e);
+}
+
diff -r 000000000000 -r 350011bf8be7 if/net/nettcpsocket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/net/nettcpsocket.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,118 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef NETTCPSOCKET_H
+#define NETTCPSOCKET_H
+
+#include "net.h"
+#include "host.h"
+
+#include <queue>
+using std::queue;
+
+//Implements a Berkeley-like socket if
+//Can be interfaced either to lwip or a Telit module
+
+enum NetTcpSocketErr
+{
+  __NETTCPSOCKET_MIN = -0xFFFF,
+  NETTCPSOCKET_SETUP, //NetTcpSocket not properly configured
+  NETTCPSOCKET_TIMEOUT,
+  NETTCPSOCKET_IF, //If has problems
+  NETTCPSOCKET_MEM, //Not enough mem
+  NETTCPSOCKET_INUSE, //If/Port is in use
+  NETTCPSOCKET_EMPTY, //Connections queue is empty
+  NETTCPSOCKET_RST, // Connection was reset by remote host
+//...
+  NETTCPSOCKET_OK = 0
+};
+
+enum NetTcpSocketEvent
+{
+  NETTCPSOCKET_CONNECTED, //Connected to host, must call accept() if we were listening
+  NETTCPSOCKET_ACCEPT,  //Connected to client
+  NETTCPSOCKET_READABLE, //Data in buf
+  NETTCPSOCKET_WRITEABLE, //Can write data to buf
+  NETTCPSOCKET_CONTIMEOUT,
+  NETTCPSOCKET_CONRST,
+  NETTCPSOCKET_CONABRT,
+  NETTCPSOCKET_ERROR,
+  NETTCPSOCKET_DISCONNECTED
+};
+
+
+class NetTcpSocket
+{
+public:
+  NetTcpSocket();
+  virtual ~NetTcpSocket(); //close()
+  
+  virtual NetTcpSocketErr bind(const Host& me) = 0;
+  virtual NetTcpSocketErr listen() = 0;
+  virtual NetTcpSocketErr connect(const Host& host) = 0;
+  virtual NetTcpSocketErr accept(Host* pClient, NetTcpSocket** ppNewNetTcpSocket) = 0;
+  
+  virtual int /*if < 0 : NetTcpSocketErr*/ send(const char* buf, int len) = 0;
+  virtual int /*if < 0 : NetTcpSocketErr*/ recv(char* buf, int len) = 0;
+
+  virtual NetTcpSocketErr close() = 0;
+
+  virtual NetTcpSocketErr poll() = 0;
+  
+  class CDummy;
+  //Callbacks
+  template<class T> 
+  //Linker bug : Must be defined here :(
+  void setOnEvent( T* pItem, void (T::*pMethod)(NetTcpSocketEvent) )
+  {
+    m_pCbItem = (CDummy*) pItem;
+    m_pCbMeth = (void (CDummy::*)(NetTcpSocketEvent)) pMethod;
+  }
+  
+  void resetOnEvent(); //Disable callback
+
+protected:
+  void queueEvent(NetTcpSocketEvent e);
+  void discardEvents();  
+  void flushEvents(); //to be called during polling
+
+  Host m_host;
+  Host m_client;
+  
+  friend class Net;
+  int m_refs;
+
+  bool m_closed;
+  bool m_removed;
+  
+private:
+  //We do not want to execute user code in interrupt routines, so we queue events until the server is polled
+  //If we port this to a multithreaded OS, we could avoid this (however some functions here are not thread-safe, so beware ;) )
+  void onEvent(NetTcpSocketEvent e); //To be called on poll
+  CDummy* m_pCbItem;
+  void (CDummy::*m_pCbMeth)(NetTcpSocketEvent);
+  queue<NetTcpSocketEvent> m_events;
+
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/net/netudpsocket.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/net/netudpsocket.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,82 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "netudpsocket.h"
+
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+NetUdpSocket::NetUdpSocket() : m_host(), m_client(), m_refs(0), m_closed(false), m_removed(false), m_pCbItem(NULL), m_pCbMeth(NULL), m_events()
+{
+  Net::registerNetUdpSocket(this);
+}
+
+NetUdpSocket::~NetUdpSocket() //close()
+{
+  Net::unregisterNetUdpSocket(this);
+}
+  
+   
+//Callbacks
+#if 0 //Just for info
+void NetUdpSocket::setOnEvent()
+{
+  m_pCbItem = (CDummy*) pItem;
+  m_pCbMeth = (void (CDummy::*)(NetUdpSocketEvent)) pMethod;
+}
+#endif
+
+void NetUdpSocket::resetOnEvent()
+{
+  m_pCbItem = NULL;
+  m_pCbMeth = NULL;
+}
+
+void NetUdpSocket::queueEvent(NetUdpSocketEvent e)
+{
+  m_events.push(e);
+}
+
+void NetUdpSocket::discardEvents()
+{
+  while( !m_events.empty() )
+  {
+    m_events.pop();
+  }
+}
+
+void NetUdpSocket::flushEvents() //To be called during polling
+{ 
+  while( !m_events.empty() )
+  {
+    onEvent(m_events.front());
+    m_events.pop();
+  }
+}
+
+void NetUdpSocket::onEvent(NetUdpSocketEvent e) //To be called during polling
+{
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)(e);
+}
+
diff -r 000000000000 -r 350011bf8be7 if/net/netudpsocket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/net/netudpsocket.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,106 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef NETUDPSOCKET_H
+#define NETUDPSOCKET_H
+
+#include "net.h"
+#include "host.h"
+
+#include <queue>
+using std::queue;
+
+//Implements a Berkeley-like socket if
+//Can be interfaced either to lwip or a Telit module
+
+enum NetUdpSocketErr
+{
+  __NETUDPSOCKET_MIN = -0xFFFF,
+  NETUDPSOCKET_SETUP, //NetUdpSocket not properly configured
+  NETUDPSOCKET_IF, //If has problems
+  NETUDPSOCKET_MEM, //Not enough mem
+  NETUDPSOCKET_INUSE, //If/Port is in use
+//...
+  NETUDPSOCKET_OK = 0
+};
+
+enum NetUdpSocketEvent //Only one lonely event here... but who knows, maybe some day there'll be another one!
+{
+  NETUDPSOCKET_READABLE, //Data in buf
+};
+
+
+class NetUdpSocket
+{
+public:
+  NetUdpSocket();
+  virtual ~NetUdpSocket(); //close()
+  
+  virtual NetUdpSocketErr bind(const Host& me) = 0;
+  
+  virtual int /*if < 0 : NetUdpSocketErr*/ sendto(const char* buf, int len, Host* pHost) = 0;
+  virtual int /*if < 0 : NetUdpSocketErr*/ recvfrom(char* buf, int len, Host* pHost) = 0;
+
+  /* TODO NTH : printf / scanf helpers that call send/recv */
+
+  virtual NetUdpSocketErr close() = 0;
+
+  virtual NetUdpSocketErr poll() = 0;
+  
+  class CDummy;
+  //Callbacks
+  template<class T> 
+  //Linker bug : Must be defined here :(
+  void setOnEvent( T* pItem, void (T::*pMethod)(NetUdpSocketEvent) )
+  {
+    m_pCbItem = (CDummy*) pItem;
+    m_pCbMeth = (void (CDummy::*)(NetUdpSocketEvent)) pMethod;
+  }
+  
+  void resetOnEvent(); //Disable callback
+
+protected:
+  void queueEvent(NetUdpSocketEvent e);
+  void discardEvents();  
+  void flushEvents(); //to be called during polling
+
+  Host m_host;
+  Host m_client;
+  
+  friend class Net;
+  int m_refs;
+
+  bool m_closed;
+  bool m_removed;
+  
+private:
+  //We do not want to execute user code in interrupt routines, so we queue events until the server is polled
+  //If we port this to a multithreaded OS, we could avoid this (however some functions here are not thread-safe, so beware ;) )
+  void onEvent(NetUdpSocketEvent e); //To be called on poll
+  CDummy* m_pCbItem;
+  void (CDummy::*m_pCbMeth)(NetUdpSocketEvent);
+  queue<NetUdpSocketEvent> m_events;
+
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/ppp/PPPNetIf.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/ppp/PPPNetIf.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,224 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "PPPNetIf.h"
+#include "mbed.h"
+#include "ppp/ppp.h"
+#include "lwip/init.h"
+#include "lwip/sio.h"
+
+#define __DEBUG
+#include "dbg/dbg.h"
+
+#include "netCfg.h"
+#if NET_PPP
+
+#define PPP_TIMEOUT 60000
+
+#define BUF_SIZE 256
+
+PPPNetIf::PPPNetIf(GPRSModem* pIf) : LwipNetIf(), m_pIf(pIf),/* m_open(false),*/ m_connected(false), m_status(PPP_DISCONNECTED), m_fd(0) //, m_id(0)
+{
+  //FIXME: Check static refcount
+  m_buf = new uint8_t[BUF_SIZE];
+}
+
+PPPNetIf::~PPPNetIf()
+{
+  delete[] m_buf;
+}
+
+#if 0
+PPPErr PPPNetIf::open(Serial* pSerial)
+{
+  GPRSErr err = m_pIf->open(pSerial);
+  if(err)
+    return PPP_MODEM;
+  m_open = true;
+  #if 0
+  m_id = sioMgr::registerSerialIf(this);
+  if(!m_id)
+  {
+    close();
+    return PPP_CLOSED;
+  }
+  #endif
+  return PPP_OK;
+}
+#endif
+
+
+PPPErr PPPNetIf::GPRSConnect(const char* apn, const char* userId, const char* password) //Connect using GPRS
+{
+  LwipNetIf::init();
+  pppInit();
+  //TODO: Tell ATIf that we get ownership of the serial port
+    
+  GPRSErr gprsErr;
+  gprsErr = m_pIf->connect(apn);
+  if(gprsErr)
+    return PPP_NETWORK;
+    
+  DBG("PPPNetIf: If Connected.\n");
+
+  if( userId == NULL )
+    pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
+  else
+    pppSetAuth(PPPAUTHTYPE_PAP, userId, password); //TODO: Allow CHAP as well
+    
+  DBG("PPPNetIf: Set Auth.\n");
+  
+  //wait(1.);
+  
+  //m_pIf->flushBuffer(); //Flush buffer before passing serial port to PPP
+  
+  m_status = PPP_CONNECTING;
+  DBG("m_pIf = %p\n", m_pIf);
+  int res = pppOverSerialOpen((void*)m_pIf, sPppCallback, (void*)this);
+  DBG("PPP connected\n");
+  if(res<0)
+  {
+    disconnect();
+    return PPP_PROTOCOL;
+  }
+  
+  DBG("PPPNetIf: PPP Started with res = %d.\n", res);
+  
+  m_fd = res;
+  m_connected = true;
+  Timer t;
+  t.start();
+  while( m_status == PPP_CONNECTING ) //Wait for callback
+  {
+    poll();
+    if(t.read_ms()>PPP_TIMEOUT)
+    {
+      DBG("PPPNetIf: Timeout.\n");  
+      disconnect();
+      return PPP_PROTOCOL;
+    }
+  }
+  
+  DBG("PPPNetIf: Callback returned.\n");
+  
+  if( m_status == PPP_DISCONNECTED )
+  {
+    disconnect();
+    return PPP_PROTOCOL;
+  }
+  
+  return PPP_OK;
+
+}
+
+PPPErr PPPNetIf::ATConnect(const char* number) //Connect using a "classic" voice modem or GSM
+{
+  //TODO: IMPL
+  return PPP_MODEM;
+}
+
+PPPErr PPPNetIf::disconnect()
+{
+  if(m_fd)
+    pppClose(m_fd); //0 if ok, else should gen a WARN
+  m_connected = false;
+  
+  m_pIf->flushBuffer();
+  m_pIf->printf("+++\r\n");
+  wait(.5);
+  m_pIf->flushBuffer();
+  
+  GPRSErr gprsErr;  
+  gprsErr = m_pIf->disconnect();
+  if(gprsErr)
+    return PPP_NETWORK;
+    
+  return PPP_OK;
+}
+
+#if 0
+PPPErr PPPNetIf::close()
+{
+  GPRSErr err = m_pIf->close();
+  if(err)
+    return PPP_MODEM;
+  m_open = false;
+  return PPP_OK;
+}
+#endif
+
+
+#if 0
+//We have to use :
+
+/** Pass received raw characters to PPPoS to be decoded. This function is
+ * thread-safe and can be called from a dedicated RX-thread or from a main-loop.
+ *
+ * @param pd PPP descriptor index, returned by pppOpen()
+ * @param data received data
+ * @param len length of received data
+ */
+void
+pppos_input(int pd, u_char* data, int len)
+{
+  pppInProc(&pppControl[pd].rx, data, len);
+}
+#endif
+
+void PPPNetIf::poll()
+{
+  if(!m_connected)
+    return;
+  LwipNetIf::poll();
+  //static u8_t buf[128];
+  int len;
+  do
+  {
+    len = sio_tryread((sio_fd_t) m_pIf, m_buf, BUF_SIZE);
+    if(len > 0)
+      pppos_input(m_fd, m_buf, len);
+  } while(len>0);
+}
+
+//Link Callback
+void PPPNetIf::pppCallback(int errCode, void *arg)
+{
+  switch ( errCode )
+  {
+    //No error
+    case PPPERR_NONE:
+      {
+        struct ppp_addrs* addrs = (struct ppp_addrs*) arg;
+        m_ip = IpAddr(&(addrs->our_ipaddr)); //Set IP
+      }
+      m_status = PPP_CONNECTED;
+      break;
+    default:
+      //Disconnected
+      DBG("PPPNetIf: Callback errCode = %d.\n", errCode);
+      m_status = PPP_DISCONNECTED;
+    break;
+  }
+}
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/ppp/PPPNetIf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/ppp/PPPNetIf.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,100 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/** \file
+PPP Generic network interface header file
+*/
+
+//This is a backend for PPP, using lwIP
+
+#ifndef PPPNETIF_H
+#define PPPNETIF_H
+
+#include "mbed.h"
+
+//For now, only a GPRS Modem is supported, 
+//but we could easily split this class into a base class + two derived classes
+// (PPP over GPRS + PPP over Serial Modem)
+#include "drv/gprs/GPRSModem.h"
+#include "if/lwip/LwipNetIf.h"
+
+///PPP connection error codes
+enum PPPErr
+{
+  __PPP_MIN = -0xFFFF,
+  PPP_MODEM, ///<AT error returned
+  PPP_NETWORK, ///<Network is down
+  PPP_PROTOCOL, ///<PPP Protocol error
+  PPP_CLOSED, ///<Connection is closed
+  PPP_OK = 0 ///<Success
+};
+
+enum PPPStatus
+{
+  PPP_CONNECTING,
+  PPP_CONNECTED,
+  PPP_DISCONNECTED,
+};
+
+class PPPNetIf : public LwipNetIf
+{
+public:
+  PPPNetIf(GPRSModem* pIf);
+  virtual ~PPPNetIf();
+  
+  #if 0
+  PPPErr open(Serial* pSerial);
+  #endif
+  
+  PPPErr GPRSConnect(const char* apn, const char* userId, const char* password); //Connect using GPRS
+  PPPErr ATConnect(const char* number); //Connect using a "classic" voice modem or GSM
+  
+  virtual void poll();
+  
+  PPPErr disconnect();
+  
+  #if 0
+  PPPErr close();
+  #endif
+  
+protected:
+  GPRSModem* m_pIf;
+  
+private:
+  void pppCallback(int errCode, void *arg);
+  
+  static void sPppCallback(void *ctx, int errCode, void *arg) //Callback from ppp.c
+  { return ((PPPNetIf*)ctx)->pppCallback(errCode, arg); }
+  
+  bool m_connected;
+  /*bool m_open;*/
+  volatile PPPStatus m_status;
+  volatile int m_fd; //PPP Session descriptor
+  
+  //int m_id;
+  
+  uint8_t* m_buf;
+
+};
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/umtsstick/UMTSStickNetIf.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/umtsstick/UMTSStickNetIf.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,92 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "netCfg.h"
+#if NET_UMTS
+
+#include "UMTSStickNetIf.h"
+
+#define __DEBUG
+#include "dbg/dbg.h"
+
+UMTSStickNetIf::UMTSStickNetIf() : PPPNetIf(NULL), m_umtsStick(), m_pUsbSerial(NULL)
+{
+  PPPNetIf::m_pIf = new GPRSModem();
+}
+
+UMTSStickNetIf::~UMTSStickNetIf()
+{
+  delete PPPNetIf::m_pIf;
+  if(m_pUsbSerial)
+    delete m_pUsbSerial;
+}
+  
+UMTSStickErr UMTSStickNetIf::setup() //UMTSStickErr is from /drv/umtsstick/UMTSStick.h
+{
+  return m_umtsStick.getSerial(&m_pUsbSerial);
+}
+
+PPPErr UMTSStickNetIf::connect(const char* apn /*= NULL*/, const char* userId /*= NULL*/, const char* password /*= NULL*/) //Connect using GPRS
+{
+  if(!m_pUsbSerial)
+    return PPP_MODEM;
+
+  ATErr atErr;
+  for(int i=0; i<3; i++)
+  {
+    atErr = m_pIf->open(m_pUsbSerial); //3 tries
+    if(!atErr)
+      break;
+    wait(4);
+  }
+    
+  if(atErr)
+    return PPP_MODEM;
+
+  PPPErr pppErr;
+  for(int i=0; i<3; i++)
+  {  
+    pppErr = PPPNetIf::GPRSConnect(apn, userId, password);
+    if(!pppErr)
+      break;
+    wait(4);
+  }
+  if(pppErr)
+    return pppErr;
+  
+  return PPP_OK;
+}
+
+PPPErr UMTSStickNetIf::disconnect()
+{
+  PPPErr pppErr = PPPNetIf::disconnect();
+  if(pppErr)
+    return pppErr;
+    
+  m_pIf->close();
+  
+  return PPP_OK;
+}
+  
+
+#endif
diff -r 000000000000 -r 350011bf8be7 if/umtsstick/UMTSStickNetIf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/if/umtsstick/UMTSStickNetIf.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,80 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/** \file
+UMTS Stick network interface header file
+*/
+
+#ifndef UMTSSTICKNETIF_H
+#define UMTSSTICKNETIF_H
+
+#include "mbed.h"
+
+#include "core/net.h"
+#include "if/ppp/PPPNetIf.h"
+
+#include "drv/umtsstick/UMTSStick.h"
+
+///UMTS Stick network interface
+/**
+This class provides connectivity to the stack using a 3G (or LTE etc...) stick
+Plug it to your USB host using two Pull-down resistors on the D+/D- lines
+*/
+class UMTSStickNetIf : public LwipNetIf, protected PPPNetIf
+{
+public:
+  ///Instantiates the Interface and register it against the stack
+  UMTSStickNetIf(); 
+  virtual ~UMTSStickNetIf();
+  
+  ///Tries to connect to the stick
+  /**
+  This method tries to obtain a virtual serial port interface from the stick
+  It waits for a stick to be connected, switches it from CDFS to virtual serial port mode if needed,
+  and obtains a virtual serial port from it
+  @return : A negative error code on error or 0 on success
+  */
+  UMTSStickErr setup(); //UMTSStickErr is from /drv/umtsstick/UMTSStick.h
+  
+  ///Establishes a PPP connection
+  /**
+  This method opens an AT interface on the serial interface, initializes and configures the stick,
+  then opens a PPP connection and authenticates with the parameters
+  \param apn : APN of the interface, if NULL uses the SIM default value
+  \param userId : user with which to authenticate during the PPP connection, if NULL does not authenticate
+  \param password : associated password
+  @return : A negative error code on error or 0 on success
+  */
+  PPPErr connect(const char* apn = NULL, const char* userId = NULL, const char* password = NULL); //Connect using GPRS
+  
+  ///Disconnects the PPP connection
+  PPPErr disconnect();
+  
+private:
+  UMTSStick m_umtsStick;
+  UsbSerial* m_pUsbSerial;
+
+};
+
+#endif
+
diff -r 000000000000 -r 350011bf8be7 lwip/arch/cc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/arch/cc.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,62 @@
+/*
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_ARCH_CC_H__
+#define __LWIP_ARCH_CC_H__
+
+#define LITTLE_ENDIAN 1234
+
+#define BYTE_ORDER  LITTLE_ENDIAN
+
+typedef unsigned char   u8_t;
+typedef signed char     s8_t;
+typedef unsigned short  u16_t;
+typedef signed short    s16_t;
+typedef unsigned int    u32_t;
+typedef signed int      s32_t;
+typedef unsigned int    mem_ptr_t;
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#include <stdlib.h>
+#define LWIP_RAND rand
+
+#define LWIP_PLATFORM_DIAG(x) DBG x
+#define LWIP_PLATFORM_ASSERT(x) DBG(x)
+
+#define LWIP_PROVIDE_ERRNO
+
+#define U16_F "hu"
+#define S16_F "hd"
+#define X16_F "hx"
+#define U32_F "lu"
+#define S32_F "ld"
+#define X32_F "lx"
+
+#if 0 
+/*Create compilation problems, and according to http://www.mail-archive.com/lwip-users@nongnu.org/msg06786.html, 
+lwIP uses packed structures, so packing the field is not really a good idea ;) */
+#define PACK_STRUCT_FIELD(x) __packed x
+#else 
+#define PACK_STRUCT_FIELD(x)    x
+#endif
+
+#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_BEGIN __packed
+#define PACK_STRUCT_END
+
+#define LWIP_CHKSUM_ALGORITHM 3
+
+
+#endif /* __LWIP_ARCH_CC_H__ */
diff -r 000000000000 -r 350011bf8be7 lwip/arch/perf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/arch/perf.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,23 @@
+/*
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_ARCH_PERF_H__
+#define __LWIP_ARCH_PERF_H__
+
+#define PERF_START
+#define PERF_STOP(x)
+
+#define perf_init(fname)
+
+#if 0
+#ifdef __cplusplus
+inline
+#endif
+void perf_init(char *fname) {
+  return;  
+}
+#endif
+
+
+#endif /* __LWIP_ARCH_PERF_H__ */
diff -r 000000000000 -r 350011bf8be7 lwip/arch/sys_arch.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/arch/sys_arch.cpp	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,70 @@
+#include "sys_arch.h"
+#include "mbed.h"
+//DG 2010
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __COMPLEX_AND_BUGGUY_HANDLING__
+static Timer* pTmr = NULL;
+
+void sys_init(void)
+{
+  //Start Timer
+  pTmr = new Timer();
+  pTmr->start();
+}
+
+u32_t sys_jiffies(void) /* since power up. */
+{
+  return (u32_t) (pTmr->read_ms()/10); //In /10ms units
+}
+
+u32_t sys_now(void)
+{
+  return (u32_t) pTmr->read_ms(); //In /ms units
+}
+#elif0
+void sys_init(void)
+{
+
+}
+
+u32_t sys_jiffies(void) /* since power up. */
+{
+  static int count = 0;
+  return ++count;
+}
+
+u32_t sys_now(void)
+{
+  return (u32_t) time(NULL);
+}
+#else
+static Timer* pTmr = NULL;
+
+void sys_init(void)
+{
+  //Start Timer
+  pTmr = new Timer();
+  pTmr->start();
+}
+
+u32_t sys_jiffies(void) /* since power up. */
+{
+  static int count = 0;
+  return ++count;
+  //return (u32_t) (pTmr->read_us());
+}
+
+u32_t sys_now(void)
+{
+  return (u32_t) (pTmr->read_ms()); //In /ms units
+}
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
diff -r 000000000000 -r 350011bf8be7 lwip/arch/sys_arch.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/arch/sys_arch.h	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,27 @@
+/*
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_SYS_ARCH_H__
+#define __LWIP_SYS_ARCH_H__
+
+typedef unsigned int u32_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//DG 2010
+void sys_init(void); /* To be called first */
+u32_t sys_jiffies(void); /* since power up. */
+
+/** Returns the current time in milliseconds,
+ * may be the same as sys_jiffies or at least based on it. */
+u32_t sys_now(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __LWIP_ARCH_CC_H__ */
diff -r 000000000000 -r 350011bf8be7 lwip/core/def.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/def.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,108 @@
+/**
+ * @file
+ * Common functions used throughout the stack.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Simon Goldschmidt
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/def.h"
+
+/**
+ * These are reference implementations of the byte swapping functions.
+ * Again with the aim of being simple, correct and fully portable.
+ * Byte swapping is the second thing you would want to optimize. You will
+ * need to port it to your architecture and in your cc.h:
+ * 
+ * #define LWIP_PLATFORM_BYTESWAP 1
+ * #define LWIP_PLATFORM_HTONS(x) <your_htons>
+ * #define LWIP_PLATFORM_HTONL(x) <your_htonl>
+ *
+ * Note ntohs() and ntohl() are merely references to the htonx counterparts.
+ */
+
+#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
+
+/**
+ * Convert an u16_t from host- to network byte order.
+ *
+ * @param n u16_t in host byte order
+ * @return n in network byte order
+ */
+u16_t
+lwip_htons(u16_t n)
+{
+  return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
+}
+
+/**
+ * Convert an u16_t from network- to host byte order.
+ *
+ * @param n u16_t in network byte order
+ * @return n in host byte order
+ */
+u16_t
+lwip_ntohs(u16_t n)
+{
+  return lwip_htons(n);
+}
+
+/**
+ * Convert an u32_t from host- to network byte order.
+ *
+ * @param n u32_t in host byte order
+ * @return n in network byte order
+ */
+u32_t
+lwip_htonl(u32_t n)
+{
+  return ((n & 0xff) << 24) |
+    ((n & 0xff00) << 8) |
+    ((n & 0xff0000UL) >> 8) |
+    ((n & 0xff000000UL) >> 24);
+}
+
+/**
+ * Convert an u32_t from network- to host byte order.
+ *
+ * @param n u32_t in network byte order
+ * @return n in host byte order
+ */
+u32_t
+lwip_ntohl(u32_t n)
+{
+  return lwip_htonl(n);
+}
+
+#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
diff -r 000000000000 -r 350011bf8be7 lwip/core/dhcp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/dhcp.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,1725 @@
+/**
+ * @file
+ * Dynamic Host Configuration Protocol client
+ *
+ */
+
+/*
+ *
+ * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.
+ * 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.
+ *
+ * This file is a contribution to the lwIP TCP/IP stack.
+ * The Swedish Institute of Computer Science and Adam Dunkels
+ * are specifically granted permission to redistribute this
+ * source code.
+ *
+ * Author: Leon Woestenberg <leon.woestenberg@gmx.net>
+ *
+ * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform
+ * with RFC 2131 and RFC 2132.
+ *
+ * TODO:
+ * - Support for interfaces other than Ethernet (SLIP, PPP, ...)
+ *
+ * Please coordinate changes and requests with Leon Woestenberg
+ * <leon.woestenberg@gmx.net>
+ *
+ * Integration with your code:
+ *
+ * In lwip/dhcp.h
+ * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)
+ * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)
+ *
+ * Then have your application call dhcp_coarse_tmr() and
+ * dhcp_fine_tmr() on the defined intervals.
+ *
+ * dhcp_start(struct netif *netif);
+ * starts a DHCP client instance which configures the interface by
+ * obtaining an IP address lease and maintaining it.
+ *
+ * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)
+ * to remove the DHCP client.
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/stats.h"
+#include "lwip/mem.h"
+#include "lwip/udp.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/def.h"
+#include "lwip/sys.h"
+#include "lwip/dhcp.h"
+#include "lwip/autoip.h"
+#include "lwip/dns.h"
+#include "netif/etharp.h"
+
+#include <string.h>
+
+/** Default for DHCP_GLOBAL_XID is 0xABCD0000
+ * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g.
+ *  #define DHCP_GLOBAL_XID_HEADER "stdlib.h"
+ *  #define DHCP_GLOBAL_XID rand()
+ */
+#ifdef DHCP_GLOBAL_XID_HEADER
+#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */
+#endif
+
+/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU
+ * MTU is checked to be big enough in dhcp_start */
+#define DHCP_MAX_MSG_LEN(netif)        (netif->mtu)
+#define DHCP_MAX_MSG_LEN_MIN_REQUIRED  576
+/** Minimum length for reply before packet is parsed */
+#define DHCP_MIN_REPLY_LEN             44
+
+#define REBOOT_TRIES 2
+
+/** Option handling: options are parsed in dhcp_parse_reply
+ * and saved in an array where other functions can load them from.
+ * This might be moved into the struct dhcp (not necessarily since
+ * lwIP is single-threaded and the array is only used while in recv
+ * callback). */
+#define DHCP_OPTION_IDX_OVERLOAD    0
+#define DHCP_OPTION_IDX_MSG_TYPE    1
+#define DHCP_OPTION_IDX_SERVER_ID   2
+#define DHCP_OPTION_IDX_LEASE_TIME  3
+#define DHCP_OPTION_IDX_T1          4
+#define DHCP_OPTION_IDX_T2          5
+#define DHCP_OPTION_IDX_SUBNET_MASK 6
+#define DHCP_OPTION_IDX_ROUTER      7
+#define DHCP_OPTION_IDX_DNS_SERVER	8
+#define DHCP_OPTION_IDX_MAX         (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
+
+/** Holds the decoded option values, only valid while in dhcp_recv.
+    @todo: move this into struct dhcp? */
+u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX];
+/** Holds a flag which option was received and is contained in dhcp_rx_options_val,
+    only valid while in dhcp_recv.
+    @todo: move this into struct dhcp? */
+u8_t  dhcp_rx_options_given[DHCP_OPTION_IDX_MAX];
+
+#define dhcp_option_given(dhcp, idx)          (dhcp_rx_options_given[idx] != 0)
+#define dhcp_got_option(dhcp, idx)            (dhcp_rx_options_given[idx] = 1)
+#define dhcp_clear_option(dhcp, idx)          (dhcp_rx_options_given[idx] = 0)
+#define dhcp_clear_all_options(dhcp)          (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given)))
+#define dhcp_get_option_value(dhcp, idx)      (dhcp_rx_options_val[idx])
+#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val))
+
+
+/* DHCP client state machine functions */
+static err_t dhcp_discover(struct netif *netif);
+static err_t dhcp_select(struct netif *netif);
+static void dhcp_bind(struct netif *netif);
+#if DHCP_DOES_ARP_CHECK
+static err_t dhcp_decline(struct netif *netif);
+#endif /* DHCP_DOES_ARP_CHECK */
+static err_t dhcp_rebind(struct netif *netif);
+static err_t dhcp_reboot(struct netif *netif);
+static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);
+
+/* receive, unfold, parse and free incoming messages */
+static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
+
+/* set the DHCP timers */
+static void dhcp_timeout(struct netif *netif);
+static void dhcp_t1_timeout(struct netif *netif);
+static void dhcp_t2_timeout(struct netif *netif);
+
+/* build outgoing messages */
+/* create a DHCP message, fill in common headers */
+static err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type);
+/* free a DHCP request */
+static void dhcp_delete_msg(struct dhcp *dhcp);
+/* add a DHCP option (type, then length in bytes) */
+static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);
+/* add option values */
+static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);
+static void dhcp_option_short(struct dhcp *dhcp, u16_t value);
+static void dhcp_option_long(struct dhcp *dhcp, u32_t value);
+/* always add the DHCP options trailer to end and pad */
+static void dhcp_option_trailer(struct dhcp *dhcp);
+
+/**
+ * Back-off the DHCP client (because of a received NAK response).
+ *
+ * Back-off the DHCP client because of a received NAK. Receiving a
+ * NAK means the client asked for something non-sensible, for
+ * example when it tries to renew a lease obtained on another network.
+ *
+ * We clear any existing set IP address and restart DHCP negotiation
+ * afresh (as per RFC2131 3.2.3).
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_handle_nak(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", 
+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+  /* Set the interface down since the address must no longer be used, as per RFC2131 */
+  netif_set_down(netif);
+  /* remove IP address from interface */
+  netif_set_ipaddr(netif, IP_ADDR_ANY);
+  netif_set_gw(netif, IP_ADDR_ANY);
+  netif_set_netmask(netif, IP_ADDR_ANY); 
+  /* Change to a defined state */
+  dhcp_set_state(dhcp, DHCP_BACKING_OFF);
+  /* We can immediately restart discovery */
+  dhcp_discover(netif);
+}
+
+#if DHCP_DOES_ARP_CHECK
+/**
+ * Checks if the offered IP address is already in use.
+ *
+ * It does so by sending an ARP request for the offered address and
+ * entering CHECKING state. If no ARP reply is received within a small
+ * interval, the address is assumed to be free for use by us.
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_check(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  err_t result;
+  u16_t msecs;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
+    (s16_t)netif->name[1]));
+  dhcp_set_state(dhcp, DHCP_CHECKING);
+  /* create an ARP query for the offered IP address, expecting that no host
+     responds, as the IP address should not be in use. */
+  result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);
+  if (result != ERR_OK) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n"));
+  }
+  dhcp->tries++;
+  msecs = 500;
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));
+}
+#endif /* DHCP_DOES_ARP_CHECK */
+
+/**
+ * Remember the configuration offered by a DHCP server.
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_handle_offer(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+  /* obtain the server address */
+  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) {
+    ip4_addr_set_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID)));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n",
+      ip4_addr_get_u32(&dhcp->server_ip_addr)));
+    /* remember offered address */
+    ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr);
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n",
+      ip4_addr_get_u32(&dhcp->offered_ip_addr)));
+
+    dhcp_select(netif);
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void*)netif));
+  }
+}
+
+/**
+ * Select a DHCP server offer out of all offers.
+ *
+ * Simply select the first offer received.
+ *
+ * @param netif the netif under DHCP control
+ * @return lwIP specific error (see error.h)
+ */
+static err_t
+dhcp_select(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  err_t result;
+  u16_t msecs;
+
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+  dhcp_set_state(dhcp, DHCP_REQUESTING);
+
+  /* create and initialize the DHCP message header */
+  result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
+  if (result == ERR_OK) {
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
+
+    /* MUST request the offered IP address */
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+    dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
+
+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
+    dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->server_ip_addr)));
+
+    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
+    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
+    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
+    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
+    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
+
+#if LWIP_NETIF_HOSTNAME
+    if (netif->hostname != NULL) {
+      const char *p = (const char*)netif->hostname;
+      u8_t namelen = (u8_t)strlen(p);
+      if (namelen > 0) {
+        LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
+        dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
+        while (*p) {
+          dhcp_option_byte(dhcp, *p++);
+        }
+      }
+    }
+#endif /* LWIP_NETIF_HOSTNAME */
+
+    dhcp_option_trailer(dhcp);
+    /* shrink the pbuf to the actual content length */
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+    /* send broadcast to any DHCP server */
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+    dhcp_delete_msg(dhcp);
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n"));
+  }
+  dhcp->tries++;
+  msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));
+  return result;
+}
+
+/**
+ * The DHCP timer that checks for lease renewal/rebind timeouts.
+ */
+void
+dhcp_coarse_tmr()
+{
+  struct netif *netif = netif_list;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n"));
+  /* iterate through all network interfaces */
+  while (netif != NULL) {
+    /* only act on DHCP configured interfaces */
+    if (netif->dhcp != NULL) {
+      /* timer is active (non zero), and triggers (zeroes) now? */
+      if (netif->dhcp->t2_timeout-- == 1) {
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));
+        /* this clients' rebind timeout triggered */
+        dhcp_t2_timeout(netif);
+      /* timer is active (non zero), and triggers (zeroes) now */
+      } else if (netif->dhcp->t1_timeout-- == 1) {
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));
+        /* this clients' renewal timeout triggered */
+        dhcp_t1_timeout(netif);
+      }
+    }
+    /* proceed to next netif */
+    netif = netif->next;
+  }
+}
+
+/**
+ * DHCP transaction timeout handling
+ *
+ * A DHCP server is expected to respond within a short period of time.
+ * This timer checks whether an outstanding DHCP request is timed out.
+ */
+void
+dhcp_fine_tmr()
+{
+  struct netif *netif = netif_list;
+  /* loop through netif's */
+  while (netif != NULL) {
+    /* only act on DHCP configured interfaces */
+    if (netif->dhcp != NULL) {
+      /* timer is active (non zero), and is about to trigger now */      
+      if (netif->dhcp->request_timeout > 1) {
+        netif->dhcp->request_timeout--;
+      }
+      else if (netif->dhcp->request_timeout == 1) {
+        netif->dhcp->request_timeout--;
+        /* { netif->dhcp->request_timeout == 0 } */
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
+        /* this client's request timeout triggered */
+        dhcp_timeout(netif);
+      }
+    }
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+}
+
+/**
+ * A DHCP negotiation transaction, or ARP request, has timed out.
+ *
+ * The timer that was started with the DHCP or ARP request has
+ * timed out, indicating no response was received in time.
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_timeout(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n"));
+  /* back-off period has passed, or server selection timed out */
+  if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
+    dhcp_discover(netif);
+  /* receiving the requested lease timed out */
+  } else if (dhcp->state == DHCP_REQUESTING) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));
+    if (dhcp->tries <= 5) {
+      dhcp_select(netif);
+    } else {
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));
+      dhcp_release(netif);
+      dhcp_discover(netif);
+    }
+#if DHCP_DOES_ARP_CHECK
+  /* received no ARP reply for the offered address (which is good) */
+  } else if (dhcp->state == DHCP_CHECKING) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));
+    if (dhcp->tries <= 1) {
+      dhcp_check(netif);
+    /* no ARP replies on the offered address,
+       looks like the IP address is indeed free */
+    } else {
+      /* bind the interface to the offered address */
+      dhcp_bind(netif);
+    }
+#endif /* DHCP_DOES_ARP_CHECK */
+  }
+  /* did not get response to renew request? */
+  else if (dhcp->state == DHCP_RENEWING) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));
+    /* just retry renewal */
+    /* note that the rebind timer will eventually time-out if renew does not work */
+    dhcp_renew(netif);
+  /* did not get response to rebind request? */
+  } else if (dhcp->state == DHCP_REBINDING) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));
+    if (dhcp->tries <= 8) {
+      dhcp_rebind(netif);
+    } else {
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));
+      dhcp_release(netif);
+      dhcp_discover(netif);
+    }
+  } else if (dhcp->state == DHCP_REBOOTING) {
+    if (dhcp->tries < REBOOT_TRIES) {
+      dhcp_reboot(netif);
+    } else {
+      dhcp_discover(netif);
+    }
+  }
+}
+
+/**
+ * The renewal period has timed out.
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_t1_timeout(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));
+  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) ||
+      (dhcp->state == DHCP_RENEWING)) {
+    /* just retry to renew - note that the rebind timer (t2) will
+     * eventually time-out if renew tries fail. */
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+                ("dhcp_t1_timeout(): must renew\n"));
+    /* This slightly different to RFC2131: DHCPREQUEST will be sent from state
+       DHCP_RENEWING, not DHCP_BOUND */
+    dhcp_renew(netif);
+  }
+}
+
+/**
+ * The rebind period has timed out.
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_t2_timeout(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n"));
+  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) ||
+      (dhcp->state == DHCP_RENEWING)) {
+    /* just retry to rebind */
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+                ("dhcp_t2_timeout(): must rebind\n"));
+    /* This slightly different to RFC2131: DHCPREQUEST will be sent from state
+       DHCP_REBINDING, not DHCP_BOUND */
+    dhcp_rebind(netif);
+  }
+}
+
+/**
+ * Handle a DHCP ACK packet
+ *
+ * @param netif the netif under DHCP control
+ */
+static void
+dhcp_handle_ack(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+#if LWIP_DNS
+  u8_t n;
+#endif /* LWIP_DNS */
+
+  /* clear options we might not get from the ACK */
+  ip_addr_set_zero(&dhcp->offered_sn_mask);
+  ip_addr_set_zero(&dhcp->offered_gw_addr);
+#if LWIP_DHCP_BOOTP_FILE
+  ip_addr_set_zero(&dhcp->offered_si_addr);
+#endif /* LWIP_DHCP_BOOTP_FILE */
+
+  /* lease time given? */
+  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) {
+    /* remember offered lease time */
+    dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME);
+  }
+  /* renewal period given? */
+  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) {
+    /* remember given renewal period */
+    dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1);
+  } else {
+    /* calculate safe periods for renewal */
+    dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
+  }
+
+  /* renewal period given? */
+  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) {
+    /* remember given rebind period */
+    dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2);
+  } else {
+    /* calculate safe periods for rebinding */
+    dhcp->offered_t2_rebind = dhcp->offered_t0_lease;
+  }
+
+  /* (y)our internet address */
+  ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr);
+
+#if LWIP_DHCP_BOOTP_FILE
+  /* copy boot server address,
+     boot file name copied in dhcp_parse_reply if not overloaded */
+  ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr);
+#endif /* LWIP_DHCP_BOOTP_FILE */
+
+  /* subnet mask given? */
+  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) {
+    /* remember given subnet mask */
+    ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)));
+    dhcp->subnet_mask_given = 1;
+  } else {
+    dhcp->subnet_mask_given = 0;
+  }
+
+  /* gateway router */
+  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) {
+    ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER)));
+  }
+  
+#if LWIP_DNS
+  /* DNS servers */
+  n = 0;
+  while(dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n) && (n < DNS_MAX_SERVERS)) {
+    ip_addr_t dns_addr;
+    ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
+    dns_setserver(n, &dns_addr);
+    n++;
+  }
+#endif /* LWIP_DNS */
+}
+
+/** Set a statically allocated struct dhcp to work with.
+ * Using this prevents dhcp_start to allocate it using mem_malloc.
+ *
+ * @param netif the netif for which to set the struct dhcp
+ * @param dhcp (uninitialised) dhcp struct allocated by the application
+ */
+void
+dhcp_set_struct(struct netif *netif, struct dhcp *dhcp)
+{
+  LWIP_ASSERT("netif != NULL", netif != NULL);
+  LWIP_ASSERT("dhcp != NULL", dhcp != NULL);
+  LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL);
+
+  /* clear data structure */
+  memset(dhcp, 0, sizeof(struct dhcp));
+  /* dhcp_set_state(&dhcp, DHCP_OFF); */
+  netif->dhcp = dhcp;
+}
+
+/**
+ * Start DHCP negotiation for a network interface.
+ *
+ * If no DHCP client instance was attached to this interface,
+ * a new client is created first. If a DHCP client instance
+ * was already present, it restarts negotiation.
+ *
+ * @param netif The lwIP network interface
+ * @return lwIP error code
+ * - ERR_OK - No error
+ * - ERR_MEM - Out of memory
+ */
+err_t
+dhcp_start(struct netif *netif)
+{
+  struct dhcp *dhcp;
+  err_t result = ERR_OK;
+
+  LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
+  dhcp = netif->dhcp;
+  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));
+  /* Remove the flag that says this netif is handled by DHCP,
+     it is set when we succeeded starting. */
+  netif->flags &= ~NETIF_FLAG_DHCP;
+
+  /* check hwtype of the netif */
+  if ((netif->flags & NETIF_FLAG_ETHARP) == 0) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): No ETHARP netif\n"));
+    return ERR_ARG;
+  }
+
+  /* check MTU of the netif */
+  if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n"));
+    return ERR_MEM;
+  }
+
+  /* no DHCP client attached yet? */
+  if (dhcp == NULL) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
+    dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));
+    if (dhcp == NULL) {
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
+      return ERR_MEM;
+    }
+    /* store this dhcp client in the netif */
+    netif->dhcp = dhcp;
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
+  /* already has DHCP client attached */
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n"));
+    if (dhcp->pcb != NULL) {
+      udp_remove(dhcp->pcb);
+    }
+    LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL);
+    LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL );
+  }
+    
+  /* clear data structure */
+  memset(dhcp, 0, sizeof(struct dhcp));
+  /* dhcp_set_state(&dhcp, DHCP_OFF); */
+  /* allocate UDP PCB */
+  dhcp->pcb = udp_new();
+  if (dhcp->pcb == NULL) {
+    LWIP_DEBUGF(DHCP_DEBUG  | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
+    return ERR_MEM;
+  }
+  dhcp->pcb->so_options |= SOF_BROADCAST;
+  /* set up local and remote port for the pcb */
+  udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
+  udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
+  /* set up the recv callback and argument */
+  udp_recv(dhcp->pcb, dhcp_recv, netif);
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
+  /* (re)start the DHCP negotiation */
+  result = dhcp_discover(netif);
+  if (result != ERR_OK) {
+    /* free resources allocated above */
+    dhcp_stop(netif);
+    return ERR_MEM;
+  }
+  /* Set the flag that says this netif is handled by DHCP. */
+  netif->flags |= NETIF_FLAG_DHCP;
+  return result;
+}
+
+/**
+ * Inform a DHCP server of our manual configuration.
+ *
+ * This informs DHCP servers of our fixed IP address configuration
+ * by sending an INFORM message. It does not involve DHCP address
+ * configuration, it is just here to be nice to the network.
+ *
+ * @param netif The lwIP network interface
+ */
+void
+dhcp_inform(struct netif *netif)
+{
+  struct dhcp dhcp;
+  err_t result = ERR_OK;
+  struct udp_pcb *pcb;
+
+  LWIP_ERROR("netif != NULL", (netif != NULL), return;);
+
+  memset(&dhcp, 0, sizeof(struct dhcp));
+  dhcp_set_state(&dhcp, DHCP_INFORM);
+
+  if ((netif->dhcp != NULL) && (netif->dhcp->pcb != NULL)) {
+    /* re-use existing pcb */
+    pcb = netif->dhcp->pcb;
+  } else {
+    pcb = udp_new();
+    if (pcb == NULL) {
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb"));
+      return;
+    }
+    dhcp.pcb = pcb;
+    dhcp.pcb->so_options |= SOF_BROADCAST;
+    udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
+  }
+  /* create and initialize the DHCP message header */
+  result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM);
+  if (result == ERR_OK) {
+    dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+    dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif));
+
+    dhcp_option_trailer(&dhcp);
+
+    pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len);
+
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));
+    udp_sendto_if(pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+    dhcp_delete_msg(&dhcp);
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n"));
+  }
+
+  if (dhcp.pcb != NULL) {
+    /* otherwise, the existing pcb was used */
+    udp_remove(dhcp.pcb);
+  }
+}
+
+/** Handle a possible change in the network configuration.
+ *
+ * This enters the REBOOTING state to verify that the currently bound
+ * address is still valid.
+ */
+void
+dhcp_network_changed(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  if (!dhcp)
+    return;
+  switch (dhcp->state) {
+  case DHCP_REBINDING:
+  case DHCP_RENEWING:
+  case DHCP_BOUND:
+  case DHCP_REBOOTING:
+    netif_set_down(netif);
+    dhcp->tries = 0;
+    dhcp_reboot(netif);
+    break;
+  case DHCP_OFF:
+    /* stay off */
+    break;
+  default:
+    dhcp->tries = 0;
+#if LWIP_DHCP_AUTOIP_COOP
+    dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
+#endif /* LWIP_DHCP_AUTOIP_COOP */
+    dhcp_discover(netif);
+    break;
+  }
+}
+
+#if DHCP_DOES_ARP_CHECK
+/**
+ * Match an ARP reply with the offered IP address.
+ *
+ * @param netif the network interface on which the reply was received
+ * @param addr The IP address we received a reply from
+ */
+void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr)
+{
+  LWIP_ERROR("netif != NULL", (netif != NULL), return;);
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n"));
+  /* is a DHCP client doing an ARP check? */
+  if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n",
+      ip4_addr_get_u32(addr)));
+    /* did a host respond with the address we
+       were offered by the DHCP server? */
+    if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {
+      /* we will not accept the offered address */
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
+        ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
+      dhcp_decline(netif);
+    }
+  }
+}
+
+/**
+ * Decline an offered lease.
+ *
+ * Tell the DHCP server we do not accept the offered address.
+ * One reason to decline the lease is when we find out the address
+ * is already in use by another host (through ARP).
+ *
+ * @param netif the netif under DHCP control
+ */
+static err_t
+dhcp_decline(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  err_t result = ERR_OK;
+  u16_t msecs;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n"));
+  dhcp_set_state(dhcp, DHCP_BACKING_OFF);
+  /* create and initialize the DHCP message header */
+  result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE);
+  if (result == ERR_OK) {
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+    dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
+
+    dhcp_option_trailer(dhcp);
+    /* resize pbuf to reflect true size of options */
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+    /* per section 4.4.4, broadcast DECLINE messages */
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+    dhcp_delete_msg(dhcp);
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("dhcp_decline: could not allocate DHCP request\n"));
+  }
+  dhcp->tries++;
+  msecs = 10*1000;
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));
+  return result;
+}
+#endif /* DHCP_DOES_ARP_CHECK */
+
+
+/**
+ * Start the DHCP process, discover a DHCP server.
+ *
+ * @param netif the netif under DHCP control
+ */
+static err_t
+dhcp_discover(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  err_t result = ERR_OK;
+  u16_t msecs;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n"));
+  ip_addr_set_any(&dhcp->offered_ip_addr);
+  dhcp_set_state(dhcp, DHCP_SELECTING);
+  /* create and initialize the DHCP message header */
+  result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER);
+  if (result == ERR_OK) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n"));
+
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
+
+    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
+    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
+    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
+    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
+    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
+
+    dhcp_option_trailer(dhcp);
+
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n"));
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
+    dhcp_delete_msg(dhcp);
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n"));
+  }
+  dhcp->tries++;
+#if LWIP_DHCP_AUTOIP_COOP
+  if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && 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 < 6 ? 1 << dhcp->tries : 60) * 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));
+  return result;
+}
+
+
+/**
+ * Bind the interface to the offered IP address.
+ *
+ * @param netif network interface to bind to the offered address
+ */
+static void
+dhcp_bind(struct netif *netif)
+{
+  u32_t timeout;
+  struct dhcp *dhcp;
+  ip_addr_t sn_mask, gw_addr;
+  LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);
+  dhcp = netif->dhcp;
+  LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
+
+  /* temporary DHCP lease? */
+  if (dhcp->offered_t1_renew != 0xffffffffUL) {
+    /* set renewal period timer */
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));
+    timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
+    if(timeout > 0xffff) {
+      timeout = 0xffff;
+    }
+    dhcp->t1_timeout = (u16_t)timeout;
+    if (dhcp->t1_timeout == 0) {
+      dhcp->t1_timeout = 1;
+    }
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));
+  }
+  /* set renewal period timer */
+  if (dhcp->offered_t2_rebind != 0xffffffffUL) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));
+    timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
+    if(timeout > 0xffff) {
+      timeout = 0xffff;
+    }
+    dhcp->t2_timeout = (u16_t)timeout;
+    if (dhcp->t2_timeout == 0) {
+      dhcp->t2_timeout = 1;
+    }
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));
+  }
+
+  if (dhcp->subnet_mask_given) {
+    /* copy offered network mask */
+    ip_addr_copy(sn_mask, dhcp->offered_sn_mask);
+  } else {
+    /* subnet mask not given, choose a safe subnet mask given the network class */
+    u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr);
+    if (first_octet <= 127) {
+      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000));
+    } else if (first_octet >= 192) {
+      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00));
+    } else {
+      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000));
+    }
+  }
+
+  ip_addr_copy(gw_addr, dhcp->offered_gw_addr);
+  /* gateway address not given? */
+  if (ip_addr_isany(&gw_addr)) {
+    /* copy network address */
+    ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask);
+    /* use first host address on network as gateway */
+    ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001));
+  }
+
+#if LWIP_DHCP_AUTOIP_COOP
+  if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
+    autoip_stop(netif);
+    dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
+  }
+#endif /* LWIP_DHCP_AUTOIP_COOP */
+
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n",
+    ip4_addr_get_u32(&dhcp->offered_ip_addr)));
+  netif_set_ipaddr(netif, &dhcp->offered_ip_addr);
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n",
+    ip4_addr_get_u32(&sn_mask)));
+  netif_set_netmask(netif, &sn_mask);
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n",
+    ip4_addr_get_u32(&gw_addr)));
+  netif_set_gw(netif, &gw_addr);
+  /* bring the interface up */
+  netif_set_up(netif);
+  /* netif is now bound to DHCP leased address */
+  dhcp_set_state(dhcp, DHCP_BOUND);
+}
+
+/**
+ * Renew an existing DHCP lease at the involved DHCP server.
+ *
+ * @param netif network interface which must renew its lease
+ */
+err_t
+dhcp_renew(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  err_t result;
+  u16_t msecs;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n"));
+  dhcp_set_state(dhcp, DHCP_RENEWING);
+
+  /* create and initialize the DHCP message header */
+  result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
+  if (result == ERR_OK) {
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
+
+#if LWIP_NETIF_HOSTNAME
+    if (netif->hostname != NULL) {
+      const char *p = (const char*)netif->hostname;
+      u8_t namelen = (u8_t)strlen(p);
+      if (namelen > 0) {
+        LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
+        dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
+        while (*p) {
+          dhcp_option_byte(dhcp, *p++);
+        }
+      }
+    }
+#endif /* LWIP_NETIF_HOSTNAME */
+
+#if 0
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
+#endif
+
+#if 0
+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
+#endif
+    /* append DHCP message trailer */
+    dhcp_option_trailer(dhcp);
+
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
+    dhcp_delete_msg(dhcp);
+
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n"));
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n"));
+  }
+  dhcp->tries++;
+  /* back-off on retries, but to a maximum of 20 seconds */
+  msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 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_renew(): set request timeout %"U16_F" msecs\n", msecs));
+  return result;
+}
+
+/**
+ * Rebind with a DHCP server for an existing DHCP lease.
+ *
+ * @param netif network interface which must rebind with a DHCP server
+ */
+static err_t
+dhcp_rebind(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  err_t result;
+  u16_t msecs;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n"));
+  dhcp_set_state(dhcp, DHCP_REBINDING);
+
+  /* create and initialize the DHCP message header */
+  result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
+  if (result == ERR_OK) {
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
+
+#if LWIP_NETIF_HOSTNAME
+    if (netif->hostname != NULL) {
+      const char *p = (const char*)netif->hostname;
+      u8_t namelen = (u8_t)strlen(p);
+      if (namelen > 0) {
+        LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
+        dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
+        while (*p) {
+          dhcp_option_byte(dhcp, *p++);
+        }
+      }
+    }
+#endif /* LWIP_NETIF_HOSTNAME */
+
+#if 0
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
+
+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
+#endif
+
+    dhcp_option_trailer(dhcp);
+
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+    /* broadcast to server */
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+    dhcp_delete_msg(dhcp);
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n"));
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n"));
+  }
+  dhcp->tries++;
+  msecs = dhcp->tries < 10 ? dhcp->tries * 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_rebind(): set request timeout %"U16_F" msecs\n", msecs));
+  return result;
+}
+
+/**
+ * Enter REBOOTING state to verify an existing lease
+ *
+ * @param netif network interface which must reboot
+ */
+static err_t
+dhcp_reboot(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  err_t result;
+  u16_t msecs;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n"));
+  dhcp_set_state(dhcp, DHCP_REBOOTING);
+
+  /* create and initialize the DHCP message header */
+  result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
+  if (result == ERR_OK) {
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
+    dhcp_option_short(dhcp, 576);
+
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
+    dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
+
+    dhcp_option_trailer(dhcp);
+
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+    /* broadcast to server */
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
+    dhcp_delete_msg(dhcp);
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n"));
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n"));
+  }
+  dhcp->tries++;
+  msecs = dhcp->tries < 10 ? dhcp->tries * 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_reboot(): set request timeout %"U16_F" msecs\n", msecs));
+  return result;
+}
+
+
+/**
+ * Release a DHCP lease.
+ *
+ * @param netif network interface which must release its lease
+ */
+err_t
+dhcp_release(struct netif *netif)
+{
+  struct dhcp *dhcp = netif->dhcp;
+  err_t result;
+  u16_t msecs;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n"));
+
+  /* idle DHCP client */
+  dhcp_set_state(dhcp, DHCP_OFF);
+  /* clean old DHCP offer */
+  ip_addr_set_zero(&dhcp->server_ip_addr);
+  ip_addr_set_zero(&dhcp->offered_ip_addr);
+  ip_addr_set_zero(&dhcp->offered_sn_mask);
+  ip_addr_set_zero(&dhcp->offered_gw_addr);
+#if LWIP_DHCP_BOOTP_FILE
+  ip_addr_set_zero(&dhcp->offered_si_addr);
+#endif /* LWIP_DHCP_BOOTP_FILE */
+  dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;
+  
+  /* create and initialize the DHCP message header */
+  result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE);
+  if (result == ERR_OK) {
+    dhcp_option_trailer(dhcp);
+
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
+
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
+    dhcp_delete_msg(dhcp);
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));
+  } else {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n"));
+  }
+  dhcp->tries++;
+  msecs = dhcp->tries < 10 ? dhcp->tries * 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_release(): set request timeout %"U16_F" msecs\n", msecs));
+  /* bring the interface down */
+  netif_set_down(netif);
+  /* remove IP address from interface */
+  netif_set_ipaddr(netif, IP_ADDR_ANY);
+  netif_set_gw(netif, IP_ADDR_ANY);
+  netif_set_netmask(netif, IP_ADDR_ANY);
+  
+  return result;
+}
+
+/**
+ * Remove the DHCP client from the interface.
+ *
+ * @param netif The network interface to stop DHCP on
+ */
+void
+dhcp_stop(struct netif *netif)
+{
+  struct dhcp *dhcp;
+  LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);
+  dhcp = netif->dhcp;
+  /* Remove the flag that says this netif is handled by DHCP. */
+  netif->flags &= ~NETIF_FLAG_DHCP;
+
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n"));
+  /* netif is DHCP configured? */
+  if (dhcp != NULL) {
+#if LWIP_DHCP_AUTOIP_COOP
+    if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
+      autoip_stop(netif);
+      dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
+    }
+#endif /* LWIP_DHCP_AUTOIP_COOP */
+
+    if (dhcp->pcb != NULL) {
+      udp_remove(dhcp->pcb);
+      dhcp->pcb = NULL;
+    }
+    LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL);
+    dhcp_set_state(dhcp, DHCP_OFF);
+  }
+}
+
+/*
+ * Set the DHCP state of a DHCP client.
+ *
+ * If the state changed, reset the number of tries.
+ */
+static void
+dhcp_set_state(struct dhcp *dhcp, u8_t new_state)
+{
+  if (new_state != dhcp->state) {
+    dhcp->state = new_state;
+    dhcp->tries = 0;
+    dhcp->request_timeout = 0;
+  }
+}
+
+/*
+ * Concatenate an option type and length field to the outgoing
+ * DHCP message.
+ *
+ */
+static void
+dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)
+{
+  LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN);
+  dhcp->msg_out->options[dhcp->options_out_len++] = option_type;
+  dhcp->msg_out->options[dhcp->options_out_len++] = option_len;
+}
+/*
+ * Concatenate a single byte to the outgoing DHCP message.
+ *
+ */
+static void
+dhcp_option_byte(struct dhcp *dhcp, u8_t value)
+{
+  LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);
+  dhcp->msg_out->options[dhcp->options_out_len++] = value;
+}
+
+static void
+dhcp_option_short(struct dhcp *dhcp, u16_t value)
+{
+  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN);
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8);
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU);
+}
+
+static void
+dhcp_option_long(struct dhcp *dhcp, u32_t value)
+{
+  LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN);
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24);
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16);
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8);
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL));
+}
+
+/**
+ * Extract the DHCP message and the DHCP options.
+ *
+ * Extract the DHCP message and the DHCP options, each into a contiguous
+ * piece of memory. As a DHCP message is variable sized by its options,
+ * and also allows overriding some fields for options, the easy approach
+ * is to first unfold the options into a conitguous piece of memory, and
+ * use that further on.
+ *
+ */
+static err_t
+dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p)
+{
+  u8_t *options;
+  u16_t offset;
+  u16_t offset_max;
+  u16_t options_idx;
+  u16_t options_idx_max;
+  struct pbuf *q;
+  int parse_file_as_options = 0;
+  int parse_sname_as_options = 0;
+
+  /* clear received options */
+  dhcp_clear_all_options(dhcp);
+  /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */
+  if (p->len < DHCP_SNAME_OFS) {
+    return ERR_BUF;
+  }
+  dhcp->msg_in = (struct dhcp_msg *)p->payload;
+#if LWIP_DHCP_BOOTP_FILE
+  /* clear boot file name */
+  dhcp->boot_file_name[0] = 0;
+#endif /* LWIP_DHCP_BOOTP_FILE */
+
+  /* parse options */
+
+  /* start with options field */
+  options_idx = DHCP_OPTIONS_OFS;
+  /* parse options to the end of the received packet */
+  options_idx_max = p->tot_len;
+again:
+  q = p;
+  while((q != NULL) && (options_idx >= q->len)) {
+    options_idx -= q->len;
+    options_idx_max -= q->len;
+    q = q->next;
+  }
+  if (q == NULL) {
+    return ERR_BUF;
+  }
+  offset = options_idx;
+  offset_max = options_idx_max;
+  options = (u8_t*)q->payload;
+  /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
+  while((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) {
+    u8_t op = options[offset];
+    u8_t len;
+    u8_t decode_len = 0;
+    int decode_idx = -1;
+    u16_t val_offset = offset + 2;
+    /* len byte might be in the next pbuf */
+    if (offset + 1 < q->len) {
+      len = options[offset + 1];
+    } else {
+      len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0);
+    }
+    /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */
+    decode_len = len;
+    switch(op) {
+      /* case(DHCP_OPTION_END): handled above */
+      case(DHCP_OPTION_PAD):
+        /* special option: no len encoded */
+        decode_len = len = 0;
+        /* will be increased below */
+        offset--;
+        break;
+      case(DHCP_OPTION_SUBNET_MASK):
+        LWIP_ASSERT("len == 4", len == 4);
+        decode_idx = DHCP_OPTION_IDX_SUBNET_MASK;
+        break;
+      case(DHCP_OPTION_ROUTER):
+        decode_len = 4; /* only copy the first given router */
+        LWIP_ASSERT("len >= decode_len", len >= decode_len);
+        decode_idx = DHCP_OPTION_IDX_ROUTER;
+        break;
+      case(DHCP_OPTION_DNS_SERVER):
+        /* special case: there might be more than one server */
+        LWIP_ASSERT("len % 4 == 0", len % 4 == 0);
+        /* limit number of DNS servers */
+        decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
+        LWIP_ASSERT("len >= decode_len", len >= decode_len);
+        decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
+        break;
+      case(DHCP_OPTION_LEASE_TIME):
+        LWIP_ASSERT("len == 4", len == 4);
+        decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
+        break;
+      case(DHCP_OPTION_OVERLOAD):
+        LWIP_ASSERT("len == 1", len == 1);
+        decode_idx = DHCP_OPTION_IDX_OVERLOAD;
+        break;
+      case(DHCP_OPTION_MESSAGE_TYPE):
+        LWIP_ASSERT("len == 1", len == 1);
+        decode_idx = DHCP_OPTION_IDX_MSG_TYPE;
+        break;
+      case(DHCP_OPTION_SERVER_ID):
+        LWIP_ASSERT("len == 4", len == 4);
+        decode_idx = DHCP_OPTION_IDX_SERVER_ID;
+        break;
+      case(DHCP_OPTION_T1):
+        LWIP_ASSERT("len == 4", len == 4);
+        decode_idx = DHCP_OPTION_IDX_T1;
+        break;
+      case(DHCP_OPTION_T2):
+        LWIP_ASSERT("len == 4", len == 4);
+        decode_idx = DHCP_OPTION_IDX_T2;
+        break;
+      default:
+        decode_len = 0;
+        LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op));
+        break;
+    }
+    offset += len + 2;
+    if (decode_len > 0) {
+      u32_t value = 0;
+      u16_t copy_len;
+decode_next:
+      LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);
+      LWIP_ASSERT("option already decoded", !dhcp_option_given(dhcp, decode_idx));
+      copy_len = LWIP_MIN(decode_len, 4);
+      pbuf_copy_partial(q, &value, copy_len, val_offset);
+      if (decode_len > 4) {
+        /* decode more than one u32_t */
+        LWIP_ASSERT("decode_len % 4 == 0", decode_len % 4 == 0);
+        dhcp_got_option(dhcp, decode_idx);
+        dhcp_set_option_value(dhcp, decode_idx, htonl(value));
+        decode_len -= 4;
+        val_offset += 4;
+        decode_idx++;
+        goto decode_next;
+      } else if (decode_len == 4) {
+        value = ntohl(value);
+      } else {
+        LWIP_ASSERT("invalid decode_len", decode_len == 1);
+        value = ((u8_t*)&value)[0];
+      }
+      dhcp_got_option(dhcp, decode_idx);
+      dhcp_set_option_value(dhcp, decode_idx, value);
+    }
+    if (offset >= q->len) {
+      offset -= q->len;
+      offset_max -= q->len;
+      q = q->next;
+      options = (u8_t*)q->payload;
+    }
+  }
+  /* is this an overloaded message? */
+  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) {
+    u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD);
+    dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD);
+    if (overload == DHCP_OVERLOAD_FILE) {
+      parse_file_as_options = 1;
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n"));
+    } else if (overload == DHCP_OVERLOAD_SNAME) {
+      parse_sname_as_options = 1;
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n"));
+    } else if (overload == DHCP_OVERLOAD_SNAME_FILE) {
+      parse_sname_as_options = 1;
+      parse_file_as_options = 1;
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n"));
+    } else {
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload));
+    }
+#if LWIP_DHCP_BOOTP_FILE
+    if (!parse_file_as_options) {
+      /* only do this for ACK messages */
+      if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) &&
+        (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK))
+      /* copy bootp file name, don't care for sname (server hostname) */
+      pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS);
+      /* make sure the string is really NULL-terminated */
+      dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0;
+    }
+#endif /* LWIP_DHCP_BOOTP_FILE */
+  }
+  if (parse_file_as_options) {
+    /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */
+    parse_file_as_options = 0;
+    options_idx = DHCP_FILE_OFS;
+    options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN;
+    goto again;
+  } else if (parse_sname_as_options) {
+    parse_sname_as_options = 0;
+    options_idx = DHCP_SNAME_OFS;
+    options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN;
+    goto again;
+  }
+  return ERR_OK;
+}
+
+/**
+ * If an incoming DHCP message is in response to us, then trigger the state machine
+ */
+static void
+dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+  struct netif *netif = (struct netif *)arg;
+  struct dhcp *dhcp = netif->dhcp;
+  struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
+  u8_t msg_type;
+  u8_t i;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
+    ip4_addr1_16(addr), ip4_addr2_16(addr), ip4_addr3_16(addr), ip4_addr4_16(addr), port));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
+  /* prevent warnings about unused arguments */
+  LWIP_UNUSED_ARG(pcb);
+  LWIP_UNUSED_ARG(addr);
+  LWIP_UNUSED_ARG(port);
+
+  LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL);
+
+  if (p->len < DHCP_MIN_REPLY_LEN) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n"));
+    goto free_pbuf_and_return;
+  }
+
+  if (reply_msg->op != DHCP_BOOTREPLY) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
+    goto free_pbuf_and_return;
+  }
+  /* iterate through hardware address and match against DHCP message */
+  for (i = 0; i < netif->hwaddr_len; i++) {
+    if (netif->hwaddr[i] != reply_msg->chaddr[i]) {
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
+        ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
+        (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));
+      goto free_pbuf_and_return;
+    }
+  }
+  /* match transaction ID against what we expected */
+  if (ntohl(reply_msg->xid) != dhcp->xid) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
+      ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
+    goto free_pbuf_and_return;
+  }
+  /* option fields could be unfold? */
+  if (dhcp_parse_reply(dhcp, p) != ERR_OK) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("problem unfolding DHCP message - too short on memory?\n"));
+    goto free_pbuf_and_return;
+  }
+
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
+  /* obtain pointer to DHCP message type */
+  if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
+    goto free_pbuf_and_return;
+  }
+
+  /* read DHCP message type */
+  msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE);
+  /* message type is DHCP ACK? */
+  if (msg_type == DHCP_ACK) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n"));
+    /* in requesting state? */
+    if (dhcp->state == DHCP_REQUESTING) {
+      dhcp_handle_ack(netif);
+#if DHCP_DOES_ARP_CHECK
+      /* check if the acknowledged lease address is already in use */
+      dhcp_check(netif);
+#else
+      /* bind interface to the acknowledged lease address */
+      dhcp_bind(netif);
+#endif
+    }
+    /* already bound to the given lease address? */
+    else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {
+      dhcp_bind(netif);
+    }
+  }
+  /* received a DHCP_NAK in appropriate state? */
+  else if ((msg_type == DHCP_NAK) &&
+    ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||
+     (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n"));
+    dhcp_handle_nak(netif);
+  }
+  /* received a DHCP_OFFER in DHCP_SELECTING state? */
+  else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
+    dhcp->request_timeout = 0;
+    /* remember offered lease */
+    dhcp_handle_offer(netif);
+  }
+free_pbuf_and_return:
+  dhcp->msg_in = NULL;
+  pbuf_free(p);
+}
+
+/**
+ * Create a DHCP request, fill in common headers
+ *
+ * @param netif the netif under DHCP control
+ * @param dhcp dhcp control struct
+ * @param message_type message type of the request
+ */
+static err_t
+dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
+{
+  u16_t i;
+#ifndef DHCP_GLOBAL_XID
+  /** default global transaction identifier starting value (easy to match
+   *  with a packet analyser). We simply increment for each new request.
+   *  Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one
+   *  at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
+  static u32_t xid = 0xABCD0000;
+#else
+  static u32_t xid;
+  static u8_t xid_initialised = 0;
+  if (!xid_initialised) {
+    xid = DHCP_GLOBAL_XID;
+    xid_initialised = !xid_initialised;
+  }
+#endif
+  LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG;);
+  LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);
+  LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL);
+  LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
+  dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
+  if (dhcp->p_out == NULL) {
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("dhcp_create_msg(): could not allocate pbuf\n"));
+    return ERR_MEM;
+  }
+  LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg",
+           (dhcp->p_out->len >= sizeof(struct dhcp_msg)));
+
+  /* reuse transaction identifier in retransmissions */
+  if (dhcp->tries == 0) {
+      xid++;
+  }
+  dhcp->xid = xid;
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
+              ("transaction id xid(%"X32_F")\n", xid));
+
+  dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
+
+  dhcp->msg_out->op = DHCP_BOOTREQUEST;
+  /* TODO: make link layer independent */
+  dhcp->msg_out->htype = DHCP_HTYPE_ETH;
+  dhcp->msg_out->hlen = netif->hwaddr_len;
+  dhcp->msg_out->hops = 0;
+  dhcp->msg_out->xid = htonl(dhcp->xid);
+  dhcp->msg_out->secs = 0;
+  /* we don't need the broadcast flag since we can receive unicast traffic
+     before being fully configured! */
+  dhcp->msg_out->flags = 0;
+  ip_addr_set_zero(&dhcp->msg_out->ciaddr);
+  /* set ciaddr to netif->ip_addr based on message_type and state */
+  if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) ||
+      ((message_type == DHCP_REQUEST) && /* DHCP_BOUND not used for sending! */
+       ((dhcp->state==DHCP_RENEWING) || dhcp->state==DHCP_REBINDING))) {
+    ip_addr_copy(dhcp->msg_out->ciaddr, netif->ip_addr);
+  }
+  ip_addr_set_zero(&dhcp->msg_out->yiaddr);
+  ip_addr_set_zero(&dhcp->msg_out->siaddr);
+  ip_addr_set_zero(&dhcp->msg_out->giaddr);
+  for (i = 0; i < DHCP_CHADDR_LEN; i++) {
+    /* copy netif hardware address, pad with zeroes */
+    dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;
+  }
+  for (i = 0; i < DHCP_SNAME_LEN; i++) {
+    dhcp->msg_out->sname[i] = 0;
+  }
+  for (i = 0; i < DHCP_FILE_LEN; i++) {
+    dhcp->msg_out->file[i] = 0;
+  }
+  dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
+  dhcp->options_out_len = 0;
+  /* fill options field with an incrementing array (for debugging purposes) */
+  for (i = 0; i < DHCP_OPTIONS_LEN; i++) {
+    dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */
+  }
+  /* Add option MESSAGE_TYPE */
+  dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
+  dhcp_option_byte(dhcp, message_type);
+  return ERR_OK;
+}
+
+/**
+ * Free previously allocated memory used to send a DHCP request.
+ *
+ * @param dhcp the dhcp struct to free the request from
+ */
+static void
+dhcp_delete_msg(struct dhcp *dhcp)
+{
+  LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;);
+  LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);
+  LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);
+  if (dhcp->p_out != NULL) {
+    pbuf_free(dhcp->p_out);
+  }
+  dhcp->p_out = NULL;
+  dhcp->msg_out = NULL;
+}
+
+/**
+ * Add a DHCP message trailer
+ *
+ * Adds the END option to the DHCP message, and if
+ * necessary, up to three padding bytes.
+ *
+ * @param dhcp DHCP state structure
+ */
+static void
+dhcp_option_trailer(struct dhcp *dhcp)
+{
+  LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;);
+  LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);
+  LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
+  dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
+  /* packet is too small, or not 4 byte aligned? */
+  while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
+    /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */
+    LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
+    /* add a fill/padding byte */
+    dhcp->msg_out->options[dhcp->options_out_len++] = 0;
+  }
+}
+
+#endif /* LWIP_DHCP */
diff -r 000000000000 -r 350011bf8be7 lwip/core/dns.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/dns.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,969 @@
+/**
+ * @file
+ * DNS - host name to IP address resolver.
+ *
+ */
+
+/**
+
+ * This file implements a DNS host name to IP address resolver.
+
+ * Port to lwIP from uIP
+ * by Jim Pettinato April 2007
+
+ * uIP version Copyright (c) 2002-2003, Adam Dunkels.
+ * 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.
+ *
+ *
+ * DNS.C
+ *
+ * The lwIP DNS resolver functions are used to lookup a host name and
+ * map it to a numerical IP address. It maintains a list of resolved
+ * hostnames that can be queried with the dns_lookup() function.
+ * New hostnames can be resolved using the dns_query() function.
+ *
+ * The lwIP version of the resolver also adds a non-blocking version of
+ * gethostbyname() that will work with a raw API application. This function
+ * checks for an IP address string first and converts it if it is valid.
+ * gethostbyname() then does a dns_lookup() to see if the name is 
+ * already in the table. If so, the IP is returned. If not, a query is 
+ * issued and the function returns with a ERR_INPROGRESS status. The app
+ * using the dns client must then go into a waiting state.
+ *
+ * Once a hostname has been resolved (or found to be non-existent),
+ * the resolver code calls a specified callback function (which 
+ * must be implemented by the module that uses the resolver).
+ */
+
+/*-----------------------------------------------------------------------------
+ * RFC 1035 - Domain names - implementation and specification
+ * RFC 2181 - Clarifications to the DNS Specification
+ *----------------------------------------------------------------------------*/
+
+/** @todo: define good default values (rfc compliance) */
+/** @todo: improve answer parsing, more checkings... */
+/** @todo: check RFC1035 - 7.3. Processing responses */
+
+/*-----------------------------------------------------------------------------
+ * Includes
+ *----------------------------------------------------------------------------*/
+
+#include "lwip/opt.h"
+
+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/udp.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/dns.h"
+
+#include <string.h>
+
+/** DNS server IP address */
+#ifndef DNS_SERVER_ADDRESS
+#define DNS_SERVER_ADDRESS(ipaddr)        (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
+#endif
+
+/** DNS server port address */
+#ifndef DNS_SERVER_PORT
+#define DNS_SERVER_PORT           53
+#endif
+
+/** DNS maximum number of retries when asking for a name, before "timeout". */
+#ifndef DNS_MAX_RETRIES
+#define DNS_MAX_RETRIES           4
+#endif
+
+/** DNS resource record max. TTL (one week as default) */
+#ifndef DNS_MAX_TTL
+#define DNS_MAX_TTL               604800
+#endif
+
+/* DNS protocol flags */
+#define DNS_FLAG1_RESPONSE        0x80
+#define DNS_FLAG1_OPCODE_STATUS   0x10
+#define DNS_FLAG1_OPCODE_INVERSE  0x08
+#define DNS_FLAG1_OPCODE_STANDARD 0x00
+#define DNS_FLAG1_AUTHORATIVE     0x04
+#define DNS_FLAG1_TRUNC           0x02
+#define DNS_FLAG1_RD              0x01
+#define DNS_FLAG2_RA              0x80
+#define DNS_FLAG2_ERR_MASK        0x0f
+#define DNS_FLAG2_ERR_NONE        0x00
+#define DNS_FLAG2_ERR_NAME        0x03
+
+/* DNS protocol states */
+#define DNS_STATE_UNUSED          0
+#define DNS_STATE_NEW             1
+#define DNS_STATE_ASKING          2
+#define DNS_STATE_DONE            3
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+/** DNS message header */
+struct dns_hdr {
+  PACK_STRUCT_FIELD(u16_t id);
+  PACK_STRUCT_FIELD(u8_t flags1);
+  PACK_STRUCT_FIELD(u8_t flags2);
+  PACK_STRUCT_FIELD(u16_t numquestions);
+  PACK_STRUCT_FIELD(u16_t numanswers);
+  PACK_STRUCT_FIELD(u16_t numauthrr);
+  PACK_STRUCT_FIELD(u16_t numextrarr);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+#define SIZEOF_DNS_HDR 12
+
+/** DNS query message structure.
+    No packing needed: only used locally on the stack. */
+struct dns_query {
+  /* DNS query record starts with either a domain name or a pointer
+     to a name already present somewhere in the packet. */
+  u16_t type;
+  u16_t cls;
+};
+#define SIZEOF_DNS_QUERY 4
+
+/** DNS answer message structure.
+    No packing needed: only used locally on the stack. */
+struct dns_answer {
+  /* DNS answer record starts with either a domain name or a pointer
+     to a name already present somewhere in the packet. */
+  u16_t type;
+  u16_t cls;
+  u32_t ttl;
+  u16_t len;
+};
+#define SIZEOF_DNS_ANSWER 10
+
+/** DNS table entry */
+struct dns_table_entry {
+  u8_t  state;
+  u8_t  numdns;
+  u8_t  tmr;
+  u8_t  retries;
+  u8_t  seqno;
+  u8_t  err;
+  u32_t ttl;
+  char name[DNS_MAX_NAME_LENGTH];
+  ip_addr_t ipaddr;
+  /* pointer to callback on DNS query done */
+  dns_found_callback found;
+  void *arg;
+};
+
+#if DNS_LOCAL_HOSTLIST
+
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+/** Local host-list. For hostnames in this list, no
+ *  external name resolution is performed */
+static struct local_hostlist_entry *local_hostlist_dynamic;
+#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+
+/** Defining this allows the local_hostlist_static to be placed in a different
+ * linker section (e.g. FLASH) */
+#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
+#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
+#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
+/** Defining this allows the local_hostlist_static to be placed in a different
+ * linker section (e.g. FLASH) */
+#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
+#define DNS_LOCAL_HOSTLIST_STORAGE_POST
+#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
+DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
+  DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
+
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+
+static void dns_init_local();
+#endif /* DNS_LOCAL_HOSTLIST */
+
+
+/* forward declarations */
+static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
+static void dns_check_entries(void);
+
+/*-----------------------------------------------------------------------------
+ * Globales
+ *----------------------------------------------------------------------------*/
+
+/* DNS variables */
+static struct udp_pcb        *dns_pcb;
+static u8_t                   dns_seqno;
+static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
+static ip_addr_t              dns_servers[DNS_MAX_SERVERS];
+/** Contiguous buffer for processing responses */
+static u8_t                   dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
+static u8_t*                  dns_payload;
+
+/**
+ * Initialize the resolver: set up the UDP pcb and configure the default server
+ * (DNS_SERVER_ADDRESS).
+ */
+void
+dns_init()
+{
+  ip_addr_t dnsserver;
+
+  dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
+  
+  /* initialize default DNS server address */
+  DNS_SERVER_ADDRESS(&dnsserver);
+
+  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
+
+  /* if dns client not yet initialized... */
+  if (dns_pcb == NULL) {
+    dns_pcb = udp_new();
+
+    if (dns_pcb != NULL) {
+      /* initialize DNS table not needed (initialized to zero since it is a
+       * global variable) */
+      LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
+        DNS_STATE_UNUSED == 0);
+
+      /* initialize DNS client */
+      udp_bind(dns_pcb, IP_ADDR_ANY, 0);
+      udp_recv(dns_pcb, dns_recv, NULL);
+
+      /* initialize default DNS primary server */
+      dns_setserver(0, &dnsserver);
+    }
+  }
+#if DNS_LOCAL_HOSTLIST
+  dns_init_local();
+#endif
+}
+
+/**
+ * Initialize one of the DNS servers.
+ *
+ * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
+ * @param dnsserver IP address of the DNS server to set
+ */
+void
+dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
+{
+  if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
+      (dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
+    dns_servers[numdns] = (*dnsserver);
+  }
+}
+
+/**
+ * Obtain one of the currently configured DNS server.
+ *
+ * @param numdns the index of the DNS server
+ * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
+ *         server has not been configured.
+ */
+ip_addr_t
+dns_getserver(u8_t numdns)
+{
+  if (numdns < DNS_MAX_SERVERS) {
+    return dns_servers[numdns];
+  } else {
+    return *IP_ADDR_ANY;
+  }
+}
+
+/**
+ * The DNS resolver client timer - handle retries and timeouts and should
+ * be called every DNS_TMR_INTERVAL milliseconds (every second by default).
+ */
+void
+dns_tmr(void)
+{
+  if (dns_pcb != NULL) {
+    LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
+    dns_check_entries();
+  }
+}
+
+#if DNS_LOCAL_HOSTLIST
+static void
+dns_init_local()
+{
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
+  int i;
+  struct local_hostlist_entry *entry;
+  /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
+  struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
+  size_t namelen;
+  for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
+    struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
+    LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
+    namelen = strlen(init_entry->name);
+    LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
+    entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
+    LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
+    if (entry != NULL) {
+      entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
+      MEMCPY((char*)entry->name, init_entry->name, namelen);
+      ((char*)entry->name)[namelen] = 0;
+      entry->addr = init_entry->addr;
+      entry->next = local_hostlist_dynamic;
+      local_hostlist_dynamic = entry;
+    }
+  }
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
+}
+
+/**
+ * Scans the local host-list for a hostname.
+ *
+ * @param hostname Hostname to look for in the local host-list
+ * @return The first IP address for the hostname in the local host-list or
+ *         IPADDR_NONE if not found.
+ */
+static u32_t
+dns_lookup_local(const char *hostname)
+{
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+  struct local_hostlist_entry *entry = local_hostlist_dynamic;
+  while(entry != NULL) {
+    if(strcmp(entry->name, hostname) == 0) {
+      return ip4_addr_get_u32(&entry->addr);
+    }
+    entry = entry->next;
+  }
+#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+  int i;
+  for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
+    if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
+      return ip4_addr_get_u32(&local_hostlist_static[i].addr);
+    }
+  }
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+  return IPADDR_NONE;
+}
+
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+/** Remove all entries from the local host-list for a specific hostname
+ * and/or IP addess
+ *
+ * @param hostname hostname for which entries shall be removed from the local
+ *                 host-list
+ * @param addr address for which entries shall be removed from the local host-list
+ * @return the number of removed entries
+ */
+int
+dns_local_removehost(const char *hostname, const ip_addr_t *addr)
+{
+  int removed = 0;
+  struct local_hostlist_entry *entry = local_hostlist_dynamic;
+  struct local_hostlist_entry *last_entry = NULL;
+  while (entry != NULL) {
+    if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
+        ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
+      struct local_hostlist_entry *free_entry;
+      if (last_entry != NULL) {
+        last_entry->next = entry->next;
+      } else {
+        local_hostlist_dynamic = entry->next;
+      }
+      free_entry = entry;
+      entry = entry->next;
+      memp_free(MEMP_LOCALHOSTLIST, free_entry);
+      removed++;
+    } else {
+      last_entry = entry;
+      entry = entry->next;
+    }
+  }
+  return removed;
+}
+
+/**
+ * Add a hostname/IP address pair to the local host-list.
+ * Duplicates are not checked.
+ *
+ * @param hostname hostname of the new entry
+ * @param addr IP address of the new entry
+ * @return ERR_OK if succeeded or ERR_MEM on memory error
+ */
+err_t
+dns_local_addhost(const char *hostname, const ip_addr_t *addr)
+{
+  struct local_hostlist_entry *entry;
+  size_t namelen;
+  LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
+  namelen = strlen(hostname);
+  LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
+  entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
+  if (entry == NULL) {
+    return ERR_MEM;
+  }
+  entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
+  MEMCPY((char*)entry->name, hostname, namelen);
+  ((char*)entry->name)[namelen] = 0;
+  ip_addr_copy(entry->addr, *addr);
+  entry->next = local_hostlist_dynamic;
+  local_hostlist_dynamic = entry;
+  return ERR_OK;
+}
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
+#endif /* DNS_LOCAL_HOSTLIST */
+
+/**
+ * Look up a hostname in the array of known hostnames.
+ *
+ * @note This function only looks in the internal array of known
+ * hostnames, it does not send out a query for the hostname if none
+ * was found. The function dns_enqueue() can be used to send a query
+ * for a hostname.
+ *
+ * @param name the hostname to look up
+ * @return the hostname's IP address, as u32_t (instead of ip_addr_t to
+ *         better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname
+ *         was not found in the cached dns_table.
+ */
+static u32_t
+dns_lookup(const char *name)
+{
+  u8_t i;
+#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
+  u32_t addr;
+#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
+#if DNS_LOCAL_HOSTLIST
+  if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
+    return addr;
+  }
+#endif /* DNS_LOCAL_HOSTLIST */
+#ifdef DNS_LOOKUP_LOCAL_EXTERN
+  if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
+    return addr;
+  }
+#endif /* DNS_LOOKUP_LOCAL_EXTERN */
+
+  /* Walk through name list, return entry if found. If not, return NULL. */
+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
+    if ((dns_table[i].state == DNS_STATE_DONE) &&
+        (strcmp(name, dns_table[i].name) == 0)) {
+      LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
+      ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
+      LWIP_DEBUGF(DNS_DEBUG, ("\n"));
+      return ip4_addr_get_u32(&dns_table[i].ipaddr);
+    }
+  }
+
+  return IPADDR_NONE;
+}
+
+#if DNS_DOES_NAME_CHECK
+/**
+ * Compare the "dotted" name "query" with the encoded name "response"
+ * to make sure an answer from the DNS server matches the current dns_table
+ * entry (otherwise, answers might arrive late for hostname not on the list
+ * any more).
+ *
+ * @param query hostname (not encoded) from the dns_table
+ * @param response encoded hostname in the DNS response
+ * @return 0: names equal; 1: names differ
+ */
+static u8_t
+dns_compare_name(unsigned char *query, unsigned char *response)
+{
+  unsigned char n;
+
+  do {
+    n = *response++;
+    /** @see RFC 1035 - 4.1.4. Message compression */
+    if ((n & 0xc0) == 0xc0) {
+      /* Compressed name */
+      break;
+    } else {
+      /* Not compressed name */
+      while (n > 0) {
+        if ((*query) != (*response)) {
+          return 1;
+        }
+        ++response;
+        ++query;
+        --n;
+      };
+      ++query;
+    }
+  } while (*response != 0);
+
+  return 0;
+}
+#endif /* DNS_DOES_NAME_CHECK */
+
+/**
+ * Walk through a compact encoded DNS name and return the end of the name.
+ *
+ * @param query encoded DNS name in the DNS server response
+ * @return end of the name
+ */
+static unsigned char *
+dns_parse_name(unsigned char *query)
+{
+  unsigned char n;
+
+  do {
+    n = *query++;
+    /** @see RFC 1035 - 4.1.4. Message compression */
+    if ((n & 0xc0) == 0xc0) {
+      /* Compressed name */
+      break;
+    } else {
+      /* Not compressed name */
+      while (n > 0) {
+        ++query;
+        --n;
+      };
+    }
+  } while (*query != 0);
+
+  return query + 1;
+}
+
+/**
+ * Send a DNS query packet.
+ *
+ * @param numdns index of the DNS server in the dns_servers table
+ * @param name hostname to query
+ * @param id index of the hostname in dns_table, used as transaction ID in the
+ *        DNS query packet
+ * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
+ */
+static err_t
+dns_send(u8_t numdns, const char* name, u8_t id)
+{
+  err_t err;
+  struct dns_hdr *hdr;
+  struct dns_query qry;
+  struct pbuf *p;
+  char *query, *nptr;
+  const char *pHostname;
+  u8_t n;
+
+  LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
+              (u16_t)(numdns), name));
+  LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
+  LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
+
+  /* if here, we have either a new query or a retry on a previous query to process */
+  p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
+                 SIZEOF_DNS_QUERY, PBUF_RAM);
+  if (p != NULL) {
+    LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
+    /* fill dns header */
+    hdr = (struct dns_hdr*)p->payload;
+    memset(hdr, 0, SIZEOF_DNS_HDR);
+    hdr->id = htons(id);
+    hdr->flags1 = DNS_FLAG1_RD;
+    hdr->numquestions = PP_HTONS(1);
+    query = (char*)hdr + SIZEOF_DNS_HDR;
+    pHostname = name;
+    --pHostname;
+
+    /* convert hostname into suitable query format. */
+    do {
+      ++pHostname;
+      nptr = query;
+      ++query;
+      for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
+        *query = *pHostname;
+        ++query;
+        ++n;
+      }
+      *nptr = n;
+    } while(*pHostname != 0);
+    *query++='\0';
+
+    /* fill dns query */
+    qry.type = PP_HTONS(DNS_RRTYPE_A);
+    qry.cls = PP_HTONS(DNS_RRCLASS_IN);
+    SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
+
+    /* resize pbuf to the exact dns query */
+    pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
+
+    /* connect to the server for faster receiving */
+    udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
+    /* send dns packet */
+    err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
+
+    /* free pbuf */
+    pbuf_free(p);
+  } else {
+    err = ERR_MEM;
+  }
+
+  return err;
+}
+
+/**
+ * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
+ * Check an entry in the dns_table:
+ * - send out query for new entries
+ * - retry old pending entries on timeout (also with different servers)
+ * - remove completed entries from the table if their TTL has expired
+ *
+ * @param i index of the dns_table entry to check
+ */
+static void
+dns_check_entry(u8_t i)
+{
+  err_t err;
+  struct dns_table_entry *pEntry = &dns_table[i];
+
+  LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
+
+  switch(pEntry->state) {
+
+    case DNS_STATE_NEW: {
+      /* initialize new entry */
+      pEntry->state   = DNS_STATE_ASKING;
+      pEntry->numdns  = 0;
+      pEntry->tmr     = 1;
+      pEntry->retries = 0;
+      
+      /* send DNS packet for this entry */
+      err = dns_send(pEntry->numdns, pEntry->name, i);
+      if (err != ERR_OK) {
+        LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+                    ("dns_send returned error: %d\n", err)); //FIX DG, lwip_strerr is part of lwip/api
+      }
+      break;
+    }
+
+    case DNS_STATE_ASKING: {
+      if (--pEntry->tmr == 0) {
+        if (++pEntry->retries == DNS_MAX_RETRIES) {
+          if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
+            /* change of server */
+            pEntry->numdns++;
+            pEntry->tmr     = 1;
+            pEntry->retries = 0;
+            break;
+          } else {
+            LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
+            /* call specified callback function if provided */
+            if (pEntry->found)
+              (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
+            /* flush this entry */
+            pEntry->state   = DNS_STATE_UNUSED;
+            pEntry->found   = NULL;
+            break;
+          }
+        }
+
+        /* wait longer for the next retry */
+        pEntry->tmr = pEntry->retries;
+
+        /* send DNS packet for this entry */
+        err = dns_send(pEntry->numdns, pEntry->name, i);
+        if (err != ERR_OK) {
+          LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+                      ("dns_send returned error: %d\n", err)); //FIX DG, lwip_strerr is part of lwip/api
+        }
+      }
+      break;
+    }
+
+    case DNS_STATE_DONE: {
+      /* if the time to live is nul */
+      if (--pEntry->ttl == 0) {
+        LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
+        /* flush this entry */
+        pEntry->state = DNS_STATE_UNUSED;
+        pEntry->found = NULL;
+      }
+      break;
+    }
+    case DNS_STATE_UNUSED:
+      /* nothing to do */
+      break;
+    default:
+      LWIP_ASSERT("unknown dns_table entry state:", 0);
+      break;
+  }
+}
+
+/**
+ * Call dns_check_entry for each entry in dns_table - check all entries.
+ */
+static void
+dns_check_entries(void)
+{
+  u8_t i;
+
+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
+    dns_check_entry(i);
+  }
+}
+
+/**
+ * Receive input function for DNS response packets arriving for the dns UDP pcb.
+ *
+ * @params see udp.h
+ */
+static void
+dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+  u16_t i;
+  char *pHostname;
+  struct dns_hdr *hdr;
+  struct dns_answer ans;
+  struct dns_table_entry *pEntry;
+  u16_t nquestions, nanswers;
+
+  LWIP_UNUSED_ARG(arg);
+  LWIP_UNUSED_ARG(pcb);
+  LWIP_UNUSED_ARG(addr);
+  LWIP_UNUSED_ARG(port);
+
+  /* is the dns message too big ? */
+  if (p->tot_len > DNS_MSG_SIZE) {
+    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
+    /* free pbuf and return */
+    goto memerr;
+  }
+
+  /* is the dns message big enough ? */
+  if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
+    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
+    /* free pbuf and return */
+    goto memerr;
+  }
+
+  /* copy dns payload inside static buffer for processing */ 
+  if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
+    /* The ID in the DNS header should be our entry into the name table. */
+    hdr = (struct dns_hdr*)dns_payload;
+    i = htons(hdr->id);
+    if (i < DNS_TABLE_SIZE) {
+      pEntry = &dns_table[i];
+      if(pEntry->state == DNS_STATE_ASKING) {
+        /* This entry is now completed. */
+        pEntry->state = DNS_STATE_DONE;
+        pEntry->err   = hdr->flags2 & DNS_FLAG2_ERR_MASK;
+
+        /* We only care about the question(s) and the answers. The authrr
+           and the extrarr are simply discarded. */
+        nquestions = htons(hdr->numquestions);
+        nanswers   = htons(hdr->numanswers);
+
+        /* Check for error. If so, call callback to inform. */
+        if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
+          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
+          /* call callback to indicate error, clean up memory and return */
+          goto responseerr;
+        }
+
+#if DNS_DOES_NAME_CHECK
+        /* Check if the name in the "question" part match with the name in the entry. */
+        if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
+          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
+          /* call callback to indicate error, clean up memory and return */
+          goto responseerr;
+        }
+#endif /* DNS_DOES_NAME_CHECK */
+
+        /* Skip the name in the "question" part */
+        pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
+
+        while (nanswers > 0) {
+          /* skip answer resource record's host name */
+          pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
+
+          /* Check for IP address type and Internet class. Others are discarded. */
+          SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
+          if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
+             (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
+            /* read the answer resource record's TTL, and maximize it if needed */
+            pEntry->ttl = ntohl(ans.ttl);
+            if (pEntry->ttl > DNS_MAX_TTL) {
+              pEntry->ttl = DNS_MAX_TTL;
+            }
+            /* read the IP address after answer resource record's header */
+            SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
+            LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
+            ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
+            LWIP_DEBUGF(DNS_DEBUG, ("\n"));
+            /* call specified callback function if provided */
+            if (pEntry->found) {
+              (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
+            }
+            /* deallocate memory and return */
+            goto memerr;
+          } else {
+            pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
+          }
+          --nanswers;
+        }
+        LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
+        /* call callback to indicate error, clean up memory and return */
+        goto responseerr;
+      }
+    }
+  }
+
+  /* deallocate memory and return */
+  goto memerr;
+
+responseerr:
+  /* ERROR: call specified callback function with NULL as name to indicate an error */
+  if (pEntry->found) {
+    (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
+  }
+  /* flush this entry */
+  pEntry->state = DNS_STATE_UNUSED;
+  pEntry->found = NULL;
+
+memerr:
+  /* free pbuf */
+  pbuf_free(p);
+  return;
+}
+
+/**
+ * Queues a new hostname to resolve and sends out a DNS query for that hostname
+ *
+ * @param name the hostname that is to be queried
+ * @param found a callback founction to be called on success, failure or timeout
+ * @param callback_arg argument to pass to the callback function
+ * @return @return a err_t return code.
+ */
+static err_t
+dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
+{
+  u8_t i;
+  u8_t lseq, lseqi;
+  struct dns_table_entry *pEntry = NULL;
+  size_t namelen;
+
+  /* search an unused entry, or the oldest one */
+  lseq = lseqi = 0;
+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
+    pEntry = &dns_table[i];
+    /* is it an unused entry ? */
+    if (pEntry->state == DNS_STATE_UNUSED)
+      break;
+
+    /* check if this is the oldest completed entry */
+    if (pEntry->state == DNS_STATE_DONE) {
+      if ((dns_seqno - pEntry->seqno) > lseq) {
+        lseq = dns_seqno - pEntry->seqno;
+        lseqi = i;
+      }
+    }
+  }
+
+  /* if we don't have found an unused entry, use the oldest completed one */
+  if (i == DNS_TABLE_SIZE) {
+    if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
+      /* no entry can't be used now, table is full */
+      LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
+      return ERR_MEM;
+    } else {
+      /* use the oldest completed one */
+      i = lseqi;
+      pEntry = &dns_table[i];
+    }
+  }
+
+  /* use this entry */
+  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
+
+  /* fill the entry */
+  pEntry->state = DNS_STATE_NEW;
+  pEntry->seqno = dns_seqno++;
+  pEntry->found = found;
+  pEntry->arg   = callback_arg;
+  namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1);
+  MEMCPY(pEntry->name, name, namelen);
+  pEntry->name[namelen] = 0;
+
+  /* force to send query without waiting timer */
+  dns_check_entry(i);
+
+  /* dns query is enqueued */
+  return ERR_INPROGRESS;
+}
+
+/**
+ * Resolve a hostname (string) into an IP address.
+ * NON-BLOCKING callback version for use with raw API!!!
+ *
+ * Returns immediately with one of err_t return codes:
+ * - ERR_OK if hostname is a valid IP address string or the host
+ *   name is already in the local names table.
+ * - ERR_INPROGRESS enqueue a request to be sent to the DNS server
+ *   for resolution if no errors are present.
+ *
+ * @param hostname the hostname that is to be queried
+ * @param addr pointer to a ip_addr_t where to store the address if it is already
+ *             cached in the dns_table (only valid if ERR_OK is returned!)
+ * @param found a callback function to be called on success, failure or timeout (only if
+ *              ERR_INPROGRESS is returned!)
+ * @param callback_arg argument to pass to the callback function
+ * @return a err_t return code.
+ */
+err_t
+dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
+                  void *callback_arg)
+{
+  u32_t ipaddr;
+  /* not initialized or no valid server yet, or invalid addr pointer
+   * or invalid hostname or invalid hostname length */
+  if ((dns_pcb == NULL) || (addr == NULL) ||
+      (!hostname) || (!hostname[0]) ||
+      (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
+    return ERR_VAL;
+  }
+
+#if LWIP_HAVE_LOOPIF
+  if (strcmp(hostname, "localhost")==0) {
+    ip_addr_set_loopback(addr);
+    return ERR_OK;
+  }
+#endif /* LWIP_HAVE_LOOPIF */
+
+  /* host name already in octet notation? set ip addr and return ERR_OK */
+  ipaddr = ipaddr_addr(hostname);
+  if (ipaddr == IPADDR_NONE) {
+    /* already have this address cached? */
+    ipaddr = dns_lookup(hostname);
+  }
+  if (ipaddr != IPADDR_NONE) {
+    ip4_addr_set_u32(addr, ipaddr);
+    return ERR_OK;
+  }
+
+  /* queue query with specified callback */
+  return dns_enqueue(hostname, found, callback_arg);
+}
+
+#endif /* LWIP_DNS */
diff -r 000000000000 -r 350011bf8be7 lwip/core/init.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/init.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,303 @@
+/**
+ * @file
+ * Modules initialization
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/init.h"
+#include "lwip/stats.h"
+#include "lwip/sys.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/pbuf.h"
+#include "lwip/netif.h"
+#include "lwip/sockets.h"
+#include "lwip/ip.h"
+#include "lwip/raw.h"
+#include "lwip/udp.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/snmp_msg.h"
+#include "lwip/autoip.h"
+#include "lwip/igmp.h"
+#include "lwip/dns.h"
+#include "lwip/timers.h"
+#include "netif/etharp.h"
+
+/* Compile-time sanity checks for configuration errors.
+ * These can be done independently of LWIP_DEBUG, without penalty.
+ */
+#ifndef BYTE_ORDER
+  #error "BYTE_ORDER is not defined, you have to define it in your cc.h"
+#endif
+#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)
+  #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h"
+#endif
+#if (!LWIP_ARP && ARP_QUEUEING)
+  #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_UDPLITE)
+  #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_SNMP)
+  #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_DHCP)
+  #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_IGMP)
+  #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_SNMP)
+  #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_UDP && LWIP_DNS)
+  #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"
+#endif
+#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))
+  #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"
+#endif
+#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0))
+  #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h"
+#endif
+#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0))
+  #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h"
+#endif
+#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))
+  #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"
+#endif
+#if (LWIP_TCP && (TCP_WND > 0xffff))
+  #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
+#endif
+#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
+  #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
+#endif
+#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))
+  #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h"
+#endif
+#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))
+  #error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"
+#endif
+#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
+  #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
+#endif
+#if (LWIP_NETIF_API && (NO_SYS==1))
+  #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"
+#endif
+#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
+  #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
+#endif
+#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
+  #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
+#endif
+#if (!LWIP_NETCONN && LWIP_SOCKET)
+  #error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"
+#endif
+#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP)
+  #error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h"
+#endif
+#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK)
+  #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h"
+#endif
+#if (!LWIP_ARP && LWIP_AUTOIP)
+  #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h"
+#endif
+#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))
+  #error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h"
+#endif
+#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
+  #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
+#endif
+#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))
+  #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
+#endif
+/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
+#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
+  #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
+#endif
+#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
+  #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
+#endif
+#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)
+  #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h"
+#endif
+#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)
+  #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"
+#endif
+#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)
+  #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf"
+#endif
+#if (TCP_QUEUE_OOSEQ && !LWIP_TCP)
+  #error "TCP_QUEUE_OOSEQ requires LWIP_TCP"
+#endif
+#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
+  #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
+#endif
+#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
+  #error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on"
+#endif
+#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)
+  #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
+#endif
+#if LWIP_IGMP && !defined(LWIP_RAND)
+  #error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
+#endif
+#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING
+  #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
+#endif
+#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE
+  #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets"
+#endif
+#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
+  #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
+#endif
+
+
+/* Compile-time checks for deprecated options.
+ */
+#ifdef MEMP_NUM_TCPIP_MSG
+  #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h."
+#endif
+#ifdef MEMP_NUM_API_MSG
+  #error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h."
+#endif
+#ifdef TCP_REXMIT_DEBUG
+  #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h."
+#endif
+#ifdef RAW_STATS
+  #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h."
+#endif
+#ifdef ETHARP_QUEUE_FIRST
+  #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h."
+#endif
+#ifdef ETHARP_ALWAYS_INSERT
+  #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
+#endif
+
+#ifdef LWIP_DEBUG
+static void
+lwip_sanity_check(void)
+{
+  /* Warnings */
+#if LWIP_NETCONN
+  if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n"));
+#endif /* LWIP_NETCONN */
+#if LWIP_TCP
+  if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));
+  if (TCP_SND_BUF < 2 * TCP_MSS)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n"));
+  if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));
+  if (TCP_SNDLOWAT >= TCP_SND_BUF)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n"));
+  if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n"));
+  if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));
+  if (TCP_WND < TCP_MSS)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));
+#endif /* LWIP_TCP */
+#if LWIP_SOCKET
+  /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
+  if (SO_ACCEPTCONN != SOF_ACCEPTCONN)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n"));
+  if (SO_REUSEADDR != SOF_REUSEADDR)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n"));
+  if (SO_KEEPALIVE != SOF_KEEPALIVE)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n"));
+  if (SO_BROADCAST != SOF_BROADCAST)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n"));
+  if (SO_LINGER != SOF_LINGER)
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n"));
+#endif /* LWIP_SOCKET */
+}
+#else  /* LWIP_DEBUG */
+#define lwip_sanity_check()
+#endif /* LWIP_DEBUG */
+
+/**
+ * Perform Sanity check of user-configurable values, and initialize all modules.
+ */
+void
+lwip_init(void)
+{
+  /* Sanity check user-configurable values */
+  lwip_sanity_check();
+
+  /* Modules initialization */
+  stats_init();
+#if !NO_SYS
+  sys_init();
+#endif /* !NO_SYS */
+  mem_init();
+  memp_init();
+  pbuf_init();
+  netif_init();
+#if LWIP_SOCKET
+  lwip_socket_init();
+#endif /* LWIP_SOCKET */
+  ip_init();
+#if LWIP_ARP
+  etharp_init();
+#endif /* LWIP_ARP */
+#if LWIP_RAW
+  raw_init();
+#endif /* LWIP_RAW */
+#if LWIP_UDP
+  udp_init();
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+  tcp_init();
+#endif /* LWIP_TCP */
+#if LWIP_SNMP
+  snmp_init();
+#endif /* LWIP_SNMP */
+#if LWIP_AUTOIP
+  autoip_init();
+#endif /* LWIP_AUTOIP */
+#if LWIP_IGMP
+  igmp_init();
+#endif /* LWIP_IGMP */
+#if LWIP_DNS
+  dns_init();
+#endif /* LWIP_DNS */
+
+#if LWIP_TIMERS
+  sys_timeouts_init();
+#endif /* LWIP_TIMERS */
+}
diff -r 000000000000 -r 350011bf8be7 lwip/core/ipv4/autoip.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/ipv4/autoip.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,541 @@
+/**
+ * @file
+ * AutoIP Automatic LinkLocal IP Configuration
+ *
+ */
+
+/*
+ *
+ * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
+ * 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 <kontakt@dspies.de>
+ *
+ * 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
+ * <kontakt@dspies.de>
+ */
+
+/*******************************************************************************
+ * USAGE:
+ * 
+ * define LWIP_AUTOIP 1  in your lwipopts.h
+ * 
+ * If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
+ * - First, call autoip_init().
+ * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
+ *   that should be defined in autoip.h.
+ *   I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
+ *   Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
+ *
+ * Without DHCP:
+ * - Call autoip_start() after netif_add().
+ * 
+ * With DHCP:
+ * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
+ * - Configure your DHCP Client.
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
+
+#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"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* 169.254.0.0 */
+#define AUTOIP_NET         0xA9FE0000
+/* 169.254.1.0 */
+#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
+/* 169.254.254.255 */
+#define AUTOIP_RANGE_END   (AUTOIP_NET | 0xFEFF)
+
+
+/** Pseudo random macro based on netif informations.
+ * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
+#ifndef LWIP_AUTOIP_RAND
+#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
+                                   ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
+                                   ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
+                                   ((u32_t)((netif->hwaddr[4]) & 0xff))) + \
+                                   (netif->autoip?netif->autoip->tried_llipaddr:0))
+#endif /* LWIP_AUTOIP_RAND */
+
+/**
+ * Macro that generates the initial IP address to be tried by AUTOIP.
+ * If you want to override this, define it to something else in lwipopts.h.
+ */
+#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
+#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
+  htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
+                 ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
+#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
+
+/* static functions */
+static void autoip_handle_arp_conflict(struct netif *netif);
+
+/* creates a pseudo random LL IP-Address for a network interface */
+static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr);
+
+/* sends an ARP probe */
+static err_t autoip_arp_probe(struct netif *netif);
+
+/* 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);
+
+/* start sending probes for llipaddr */
+static void autoip_start_probing(struct netif *netif);
+
+/**
+ * Initialize this module
+ */
+void
+autoip_init(void)
+{
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
+}
+
+/** Set a statically allocated struct autoip to work with.
+ * Using this prevents autoip_start to allocate it using mem_malloc.
+ *
+ * @param netif the netif for which to set the struct autoip
+ * @param dhcp (uninitialised) dhcp struct allocated by the application
+ */
+void
+autoip_set_struct(struct netif *netif, struct autoip *autoip)
+{
+  LWIP_ASSERT("netif != NULL", netif != NULL);
+  LWIP_ASSERT("autoip != NULL", autoip != NULL);
+  LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL);
+
+  /* clear data structure */
+  memset(autoip, 0, sizeof(struct autoip));
+  /* autoip->state = AUTOIP_STATE_OFF; */
+  netif->autoip = autoip;
+}
+
+/** Restart AutoIP client and check the next address (conflict detected)
+ *
+ * @param netif The netif under AutoIP control
+ */
+static void
+autoip_restart(struct netif *netif)
+{
+  netif->autoip->tried_llipaddr++;
+  autoip_start(netif);
+}
+
+/**
+ * Handle a IP address conflict after an ARP conflict detection
+ */
+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 | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+        ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
+
+      /* TODO: close all TCP sessions */
+      autoip_restart(netif);
+    } else {
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+        ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
+      autoip_arp_announce(netif);
+      netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
+    }
+  } else {
+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+      ("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
+    /* TODO: close all TCP sessions */
+    autoip_restart(netif);
+  }
+}
+
+/**
+ * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
+ *
+ * @param netif network interface on which create the IP-Address
+ * @param ipaddr ip address to initialize
+ */
+static void
+autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
+{
+  /* 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 */
+
+  u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
+  addr += netif->autoip->tried_llipaddr;
+  addr = AUTOIP_NET | (addr & 0xffff);
+  /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ 
+
+  if (addr < AUTOIP_RANGE_START) {
+    addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
+  }
+  if (addr > AUTOIP_RANGE_END) {
+    addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
+  }
+  LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
+    (addr <= AUTOIP_RANGE_END));
+  ip4_addr_set_u32(ipaddr, htonl(addr));
+  
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+    ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+    (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
+    ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
+}
+
+/**
+ * Sends an ARP probe from a network interface
+ *
+ * @param netif network interface used to send the probe
+ */
+static err_t
+autoip_arp_probe(struct netif *netif)
+{
+  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
+    (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, &ethzero,
+    &netif->autoip->llipaddr, ARP_REQUEST);
+}
+
+/**
+ * Sends an ARP announce from a network interface
+ *
+ * @param netif network interface used to send the announce
+ */
+static err_t
+autoip_arp_announce(struct netif *netif)
+{
+  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
+    (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, &ethzero,
+    &netif->autoip->llipaddr, ARP_REQUEST);
+}
+
+/**
+ * Configure interface for use with current LL IP-Address
+ *
+ * @param netif network interface to configure with current LL IP-Address
+ */
+static err_t
+autoip_bind(struct netif *netif)
+{
+  struct autoip *autoip = netif->autoip;
+  ip_addr_t sn_mask, gw_addr;
+
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+    ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num,
+    ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
+    ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
+
+  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;
+}
+
+/**
+ * Start AutoIP client
+ *
+ * @param netif network interface on which start the AutoIP client
+ */
+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
+   */
+  ip_addr_set_zero(&netif->ip_addr);
+  ip_addr_set_zero(&netif->netmask);
+  ip_addr_set_zero(&netif->gw);
+
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_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 | LWIP_DBG_TRACE,
+      ("autoip_start(): starting new AUTOIP client\n"));
+    autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
+    if(autoip == NULL) {
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_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 | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
+  } else {
+    autoip->state = AUTOIP_STATE_OFF;
+    autoip->ttw = 0;
+    autoip->sent_num = 0;
+    ip_addr_set_zero(&autoip->llipaddr);
+    autoip->lastconflict = 0;
+  }
+
+  autoip_create_addr(netif, &(autoip->llipaddr));
+  autoip_start_probing(netif);
+
+  return result;
+}
+
+static void
+autoip_start_probing(struct netif *netif)
+{
+  struct autoip *autoip = netif->autoip;
+
+  autoip->state = AUTOIP_STATE_PROBING;
+  autoip->sent_num = 0;
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+     ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
+      ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
+
+  /* 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 = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_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_TICKS_PER_SECOND;
+  }
+}
+
+/**
+ * Handle a possible change in the network configuration.
+ *
+ * If there is an AutoIP address configured, take the interface down
+ * and begin probing with the same address.
+ */
+void
+autoip_network_changed(struct netif *netif)
+{
+  if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
+    netif_set_down(netif);
+    autoip_start_probing(netif);
+  }
+}
+
+/**
+ * Stop AutoIP client
+ *
+ * @param netif network interface on which stop the AutoIP client
+ */
+err_t
+autoip_stop(struct netif *netif)
+{
+  netif->autoip->state = AUTOIP_STATE_OFF;
+  netif_set_down(netif);
+  return ERR_OK;
+}
+
+/**
+ * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
+ */
+void
+autoip_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 | LWIP_DBG_TRACE,
+        ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
+        (u16_t)(netif->autoip->state), netif->autoip->ttw));
+
+      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_TICKS_PER_SECOND;
+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+                 ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+                  ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
+                  ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
+            } else {
+              autoip_arp_probe(netif);
+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+                ("autoip_tmr() PROBING Sent Probe\n"));
+              netif->autoip->sent_num++;
+              /* calculate time to wait to next probe */
+              netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
+                ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
+                PROBE_MIN * AUTOIP_TICKS_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 calls netif_set_up. This triggers a gratuitous ARP
+              * which counts as an announcement.
+              */
+              autoip_bind(netif);
+            } else {
+              autoip_arp_announce(netif);
+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
+                ("autoip_tmr() ANNOUNCING Sent Announce\n"));
+            }
+            netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
+            netif->autoip->sent_num++;
+
+            if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
+                netif->autoip->state = AUTOIP_STATE_BOUND;
+                netif->autoip->sent_num = 0;
+                netif->autoip->ttw = 0;
+                 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+                    ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+                     ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
+                     ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
+            }
+          }
+          break;
+      }
+    }
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+}
+
+/**
+ * Handles every incoming ARP Packet, called by etharp_arp_input.
+ *
+ * @param netif network interface to use for autoip processing
+ * @param hdr Incoming ARP packet
+ */
+void
+autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
+{
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("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
+    */
+    ip_addr_t 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).
+     */
+    IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
+    IPADDR2_COPY(&dipaddr, &hdr->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 | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
+          ("autoip_arp_reply(): Probe Conflict detected\n"));
+        autoip_restart(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 | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
+          ("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
+        autoip_handle_arp_conflict(netif);
+      }
+    }
+  }
+}
+
+#endif /* LWIP_AUTOIP */
diff -r 000000000000 -r 350011bf8be7 lwip/core/ipv4/icmp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/ipv4/icmp.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,335 @@
+/**
+ * @file
+ * ICMP - Internet Control Message Protocol
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+/* Some ICMP messages should be passed to the transport protocols. This
+   is not implemented. */
+
+#include "lwip/opt.h"
+
+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/icmp.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/ip.h"
+#include "lwip/def.h"
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+
+#include <string.h>
+
+/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
+ * used to modify and send a response packet (and to 1 if this is not the case,
+ * e.g. when link header is stripped of when receiving) */
+#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
+#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
+#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
+
+/* The amount of data from the original packet to return in a dest-unreachable */
+#define ICMP_DEST_UNREACH_DATASIZE 8
+
+static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
+
+/**
+ * Processes ICMP input packets, called from ip_input().
+ *
+ * Currently only processes icmp echo requests and sends
+ * out the echo response.
+ *
+ * @param p the icmp echo request packet, p->payload pointing to the ip header
+ * @param inp the netif on which this packet was received
+ */
+void
+icmp_input(struct pbuf *p, struct netif *inp)
+{
+  u8_t type;
+#ifdef LWIP_DEBUG
+  u8_t code;
+#endif /* LWIP_DEBUG */
+  struct icmp_echo_hdr *iecho;
+  struct ip_hdr *iphdr;
+  s16_t hlen;
+
+  ICMP_STATS_INC(icmp.recv);
+  snmp_inc_icmpinmsgs();
+
+
+  iphdr = (struct ip_hdr *)p->payload;
+  hlen = IPH_HL(iphdr) * 4;
+  if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
+    goto lenerr;
+  }
+
+  type = *((u8_t *)p->payload);
+#ifdef LWIP_DEBUG
+  code = *(((u8_t *)p->payload)+1);
+#endif /* LWIP_DEBUG */
+  switch (type) {
+  case ICMP_ER:
+    /* This is OK, echo reply might have been parsed by a raw PCB
+       (as obviously, an echo request has been sent, too). */
+    break; 
+  case ICMP_ECHO:
+#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
+    {
+      int accepted = 1;
+#if !LWIP_MULTICAST_PING
+      /* multicast destination address? */
+      if (ip_addr_ismulticast(&current_iphdr_dest)) {
+        accepted = 0;
+      }
+#endif /* LWIP_MULTICAST_PING */
+#if !LWIP_BROADCAST_PING
+      /* broadcast destination address? */
+      if (ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
+        accepted = 0;
+      }
+#endif /* LWIP_BROADCAST_PING */
+      /* broadcast or multicast destination address not acceptd? */
+      if (!accepted) {
+        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
+        ICMP_STATS_INC(icmp.err);
+        pbuf_free(p);
+        return;
+      }
+    }
+#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
+    if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
+      goto lenerr;
+    }
+    if (inet_chksum_pbuf(p) != 0) {
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
+      pbuf_free(p);
+      ICMP_STATS_INC(icmp.chkerr);
+      snmp_inc_icmpinerrors();
+      return;
+    }
+#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
+    if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
+      /* p is not big enough to contain link headers
+       * allocate a new one and copy p into it
+       */
+      struct pbuf *r;
+      /* switch p->payload to ip header */
+      if (pbuf_header(p, hlen)) {
+        LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
+        goto memerr;
+      }
+      /* allocate new packet buffer with space for link headers */
+      r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
+      if (r == NULL) {
+        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
+        goto memerr;
+      }
+      LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
+                  (r->len >= hlen + sizeof(struct icmp_echo_hdr)));
+      /* copy the whole packet including ip header */
+      if (pbuf_copy(r, p) != ERR_OK) {
+        LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
+        goto memerr;
+      }
+      iphdr = (struct ip_hdr *)r->payload;
+      /* switch r->payload back to icmp header */
+      if (pbuf_header(r, -hlen)) {
+        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
+        goto memerr;
+      }
+      /* free the original p */
+      pbuf_free(p);
+      /* we now have an identical copy of p that has room for link headers */
+      p = r;
+    } else {
+      /* restore p->payload to point to icmp header */
+      if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
+        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
+        goto memerr;
+      }
+    }
+#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
+    /* At this point, all checks are OK. */
+    /* We generate an answer by switching the dest and src ip addresses,
+     * setting the icmp type to ECHO_RESPONSE and updating the checksum. */
+    iecho = (struct icmp_echo_hdr *)p->payload;
+    ip_addr_copy(iphdr->src, *ip_current_dest_addr());
+    ip_addr_copy(iphdr->dest, *ip_current_src_addr());
+    ICMPH_TYPE_SET(iecho, ICMP_ER);
+    /* adjust the checksum */
+    if (iecho->chksum >= PP_HTONS(0xffff - (ICMP_ECHO << 8))) {
+      iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
+    } else {
+      iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
+    }
+
+    /* Set the correct TTL and recalculate the header checksum. */
+    IPH_TTL_SET(iphdr, ICMP_TTL);
+    IPH_CHKSUM_SET(iphdr, 0);
+#if CHECKSUM_GEN_IP
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
+#endif /* CHECKSUM_GEN_IP */
+
+    ICMP_STATS_INC(icmp.xmit);
+    /* increase number of messages attempted to send */
+    snmp_inc_icmpoutmsgs();
+    /* increase number of echo replies attempted to send */
+    snmp_inc_icmpoutechoreps();
+
+    if(pbuf_header(p, hlen)) {
+      LWIP_ASSERT("Can't move over header in packet", 0);
+    } else {
+      err_t ret;
+      /* send an ICMP packet, src addr is the dest addr of the curren packet */
+      ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,
+                   ICMP_TTL, 0, IP_PROTO_ICMP, inp);
+      if (ret != ERR_OK) {
+        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
+      }
+    }
+    break;
+  default:
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", 
+                (s16_t)type, (s16_t)code));
+    ICMP_STATS_INC(icmp.proterr);
+    ICMP_STATS_INC(icmp.drop);
+  }
+  pbuf_free(p);
+  return;
+lenerr:
+  pbuf_free(p);
+  ICMP_STATS_INC(icmp.lenerr);
+  snmp_inc_icmpinerrors();
+  return;
+#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
+memerr:
+  pbuf_free(p);
+  ICMP_STATS_INC(icmp.err);
+  snmp_inc_icmpinerrors();
+  return;
+#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
+}
+
+/**
+ * Send an icmp 'destination unreachable' packet, called from ip_input() if
+ * the transport layer protocol is unknown and from udp_input() if the local
+ * port is not bound.
+ *
+ * @param p the input packet for which the 'unreachable' should be sent,
+ *          p->payload pointing to the IP header
+ * @param t type of the 'unreachable' packet
+ */
+void
+icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
+{
+  icmp_send_response(p, ICMP_DUR, t);
+}
+
+#if IP_FORWARD || IP_REASSEMBLY
+/**
+ * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.
+ *
+ * @param p the input packet for which the 'time exceeded' should be sent,
+ *          p->payload pointing to the IP header
+ * @param t type of the 'time exceeded' packet
+ */
+void
+icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
+{
+  icmp_send_response(p, ICMP_TE, t);
+}
+
+#endif /* IP_FORWARD || IP_REASSEMBLY */
+
+/**
+ * Send an icmp packet in response to an incoming packet.
+ *
+ * @param p the input packet for which the 'unreachable' should be sent,
+ *          p->payload pointing to the IP header
+ * @param type Type of the ICMP header
+ * @param code Code of the ICMP header
+ */
+static void
+icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
+{
+  struct pbuf *q;
+  struct ip_hdr *iphdr;
+  /* we can use the echo header here */
+  struct icmp_echo_hdr *icmphdr;
+  ip_addr_t iphdr_src;
+
+  /* ICMP header + IP header + 8 bytes of data */
+  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
+                 PBUF_RAM);
+  if (q == NULL) {
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
+    return;
+  }
+  LWIP_ASSERT("check that first pbuf can hold icmp message",
+             (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
+
+  iphdr = (struct ip_hdr *)p->payload;
+  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
+  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
+  LWIP_DEBUGF(ICMP_DEBUG, (" to "));
+  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
+  LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
+
+  icmphdr = (struct icmp_echo_hdr *)q->payload;
+  icmphdr->type = type;
+  icmphdr->code = code;
+  icmphdr->id = 0;
+  icmphdr->seqno = 0;
+
+  /* copy fields from original packet */
+  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
+          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
+
+  /* calculate checksum */
+  icmphdr->chksum = 0;
+  icmphdr->chksum = inet_chksum(icmphdr, q->len);
+  ICMP_STATS_INC(icmp.xmit);
+  /* increase number of messages attempted to send */
+  snmp_inc_icmpoutmsgs();
+  /* increase number of destination unreachable messages attempted to send */
+  snmp_inc_icmpouttimeexcds();
+  ip_addr_copy(iphdr_src, iphdr->src);
+  ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
+  pbuf_free(q);
+}
+
+#endif /* LWIP_ICMP */
diff -r 000000000000 -r 350011bf8be7 lwip/core/ipv4/igmp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/ipv4/igmp.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,818 @@
+#pragma diag_remark 177
+/**
+ * @file
+ * IGMP - Internet Group Management Protocol
+ *
+ */
+
+/*
+ * Copyright (c) 2002 CITEL Technologies Ltd.
+ * 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. Neither the name of CITEL Technologies Ltd nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``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 CITEL TECHNOLOGIES OR CONTRIBUTORS 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. 
+ *
+ * This file is a contribution to the lwIP TCP/IP stack.
+ * The Swedish Institute of Computer Science and Adam Dunkels
+ * are specifically granted permission to redistribute this
+ * source code.
+*/
+
+/*-------------------------------------------------------------
+Note 1)
+Although the rfc requires V1 AND V2 capability
+we will only support v2 since now V1 is very old (August 1989)
+V1 can be added if required
+
+a debug print and statistic have been implemented to
+show this up.
+-------------------------------------------------------------
+-------------------------------------------------------------
+Note 2)
+A query for a specific group address (as opposed to ALLHOSTS)
+has now been implemented as I am unsure if it is required
+
+a debug print and statistic have been implemented to
+show this up.
+-------------------------------------------------------------
+-------------------------------------------------------------
+Note 3)
+The router alert rfc 2113 is implemented in outgoing packets
+but not checked rigorously incoming
+-------------------------------------------------------------
+Steve Reynolds
+------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------------
+ * RFC 988  - Host extensions for IP multicasting                         - V0
+ * RFC 1054 - Host extensions for IP multicasting                         -
+ * RFC 1112 - Host extensions for IP multicasting                         - V1
+ * RFC 2236 - Internet Group Management Protocol, Version 2               - V2  <- this code is based on this RFC (it's the "de facto" standard)
+ * RFC 3376 - Internet Group Management Protocol, Version 3               - V3
+ * RFC 4604 - Using Internet Group Management Protocol Version 3...       - V3+
+ * RFC 2113 - IP Router Alert Option                                      - 
+ *----------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------------
+ * Includes
+ *----------------------------------------------------------------------------*/
+
+#include "lwip/opt.h"
+
+#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/igmp.h"
+#include "lwip/debug.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/ip.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/icmp.h"
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+#include "lwip/stats.h"
+
+#include "string.h"
+
+/* 
+ * IGMP constants
+ */
+#define IGMP_TTL                       1
+#define IGMP_MINLEN                    8
+#define ROUTER_ALERT                   0x9404
+#define ROUTER_ALERTLEN                4
+
+/*
+ * IGMP message types, including version number.
+ */
+#define IGMP_MEMB_QUERY                0x11 /* Membership query         */
+#define IGMP_V1_MEMB_REPORT            0x12 /* Ver. 1 membership report */
+#define IGMP_V2_MEMB_REPORT            0x16 /* Ver. 2 membership report */
+#define IGMP_LEAVE_GROUP               0x17 /* Leave-group message      */
+
+/* Group  membership states */
+#define IGMP_GROUP_NON_MEMBER          0
+#define IGMP_GROUP_DELAYING_MEMBER     1
+#define IGMP_GROUP_IDLE_MEMBER         2
+
+/**
+ * IGMP packet format.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct igmp_msg {
+ PACK_STRUCT_FIELD(u8_t           igmp_msgtype);
+ PACK_STRUCT_FIELD(u8_t           igmp_maxresp);
+ PACK_STRUCT_FIELD(u16_t          igmp_checksum);
+ PACK_STRUCT_FIELD(ip_addr_p_t    igmp_group_address);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+
+static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
+static err_t  igmp_remove_group(struct igmp_group *group);
+static void   igmp_timeout( struct igmp_group *group);
+static void   igmp_start_timer(struct igmp_group *group, u8_t max_time);
+static void   igmp_stop_timer(struct igmp_group *group);
+static void   igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
+static err_t  igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
+static void   igmp_send(struct igmp_group *group, u8_t type);
+
+
+static struct igmp_group* igmp_group_list;
+static ip_addr_t     allsystems;
+static ip_addr_t     allrouters;
+
+
+/**
+ * Initialize the IGMP module
+ */
+void
+igmp_init(void)
+{
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
+
+  IP4_ADDR(&allsystems, 224, 0, 0, 1);
+  IP4_ADDR(&allrouters, 224, 0, 0, 2);
+}
+
+#ifdef LWIP_DEBUG
+/**
+ * Dump global IGMP groups list
+ */
+void
+igmp_dump_group_list()
+{ 
+  struct igmp_group *group = igmp_group_list;
+
+  while (group != NULL) {
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
+    ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
+    LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
+    group = group->next;
+  }
+  LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+}
+#else
+#define igmp_dump_group_list()
+#endif /* LWIP_DEBUG */
+
+/**
+ * Start IGMP processing on interface
+ *
+ * @param netif network interface on which start IGMP processing
+ */
+err_t
+igmp_start(struct netif *netif)
+{
+  struct igmp_group* group;
+
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
+
+  group = igmp_lookup_group(netif, &allsystems);
+
+  if (group != NULL) {
+    group->group_state = IGMP_GROUP_IDLE_MEMBER;
+    group->use++;
+
+    /* Allow the igmp messages at the MAC level */
+    if (netif->igmp_mac_filter != NULL) {
+      LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
+      ip_addr_debug_print(IGMP_DEBUG, &allsystems);
+      LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+      netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
+    }
+
+    return ERR_OK;
+  }
+
+  return ERR_MEM;
+}
+
+/**
+ * Stop IGMP processing on interface
+ *
+ * @param netif network interface on which stop IGMP processing
+ */
+err_t
+igmp_stop(struct netif *netif)
+{
+  struct igmp_group *group = igmp_group_list;
+  struct igmp_group *prev  = NULL;
+  struct igmp_group *next;
+
+  /* look for groups joined on this interface further down the list */
+  while (group != NULL) {
+    next = group->next;
+    /* is it a group joined on this interface? */
+    if (group->netif == netif) {
+      /* is it the first group of the list? */
+      if (group == igmp_group_list) {
+        igmp_group_list = next;
+      }
+      /* is there a "previous" group defined? */
+      if (prev != NULL) {
+        prev->next = next;
+      }
+      /* disable the group at the MAC level */
+      if (netif->igmp_mac_filter != NULL) {
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
+        ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
+        LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+        netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
+      }
+      /* free group */
+      memp_free(MEMP_IGMP_GROUP, group);
+    } else {
+      /* change the "previous" */
+      prev = group;
+    }
+    /* move to "next" */
+    group = next;
+  }
+  return ERR_OK;
+}
+
+/**
+ * Report IGMP memberships for this interface
+ *
+ * @param netif network interface on which report IGMP memberships
+ */
+void
+igmp_report_groups(struct netif *netif)
+{
+  struct igmp_group *group = igmp_group_list;
+
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
+
+  while (group != NULL) {
+    if (group->netif == netif) {
+      igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
+    }
+    group = group->next;
+  }
+}
+
+/**
+ * Search for a group in the global igmp_group_list
+ *
+ * @param ifp the network interface for which to look
+ * @param addr the group ip address to search for
+ * @return a struct igmp_group* if the group has been found,
+ *         NULL if the group wasn't found.
+ */
+struct igmp_group *
+igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
+{
+  struct igmp_group *group = igmp_group_list;
+
+  while (group != NULL) {
+    if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
+      return group;
+    }
+    group = group->next;
+  }
+
+  /* to be clearer, we return NULL here instead of
+   * 'group' (which is also NULL at this point).
+   */
+  return NULL;
+}
+
+/**
+ * Search for a specific igmp group and create a new one if not found-
+ *
+ * @param ifp the network interface for which to look
+ * @param addr the group ip address to search
+ * @return a struct igmp_group*,
+ *         NULL on memory error.
+ */
+struct igmp_group *
+igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
+{
+  struct igmp_group *group = igmp_group_list;
+  
+  /* Search if the group already exists */
+  group = igmp_lookfor_group(ifp, addr);
+  if (group != NULL) {
+    /* Group already exists. */
+    return group;
+  }
+
+  /* Group doesn't exist yet, create a new one */
+  group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
+  if (group != NULL) {
+    group->netif              = ifp;
+    ip_addr_set(&(group->group_address), addr);
+    group->timer              = 0; /* Not running */
+    group->group_state        = IGMP_GROUP_NON_MEMBER;
+    group->last_reporter_flag = 0;
+    group->use                = 0;
+    group->next               = igmp_group_list;
+    
+    igmp_group_list = group;
+  }
+
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
+  ip_addr_debug_print(IGMP_DEBUG, addr);
+  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
+
+  return group;
+}
+
+/**
+ * Remove a group in the global igmp_group_list
+ *
+ * @param group the group to remove from the global igmp_group_list
+ * @return ERR_OK if group was removed from the list, an err_t otherwise
+ */
+static err_t
+igmp_remove_group(struct igmp_group *group)
+{
+  err_t err = ERR_OK;
+
+  /* Is it the first group? */
+  if (igmp_group_list == group) {
+    igmp_group_list = group->next;
+  } else {
+    /* look for group further down the list */
+    struct igmp_group *tmpGroup;
+    for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
+      if (tmpGroup->next == group) {
+        tmpGroup->next = group->next;
+        break;
+      }
+    }
+    /* Group not found in the global igmp_group_list */
+    if (tmpGroup == NULL)
+      err = ERR_ARG;
+  }
+  /* free group */
+  memp_free(MEMP_IGMP_GROUP, group);
+
+  return err;
+}
+
+/**
+ * Called from ip_input() if a new IGMP packet is received.
+ *
+ * @param p received igmp packet, p->payload pointing to the ip header
+ * @param inp network interface on which the packet was received
+ * @param dest destination ip address of the igmp packet
+ */
+void
+igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
+{
+  struct ip_hdr *    iphdr;
+  struct igmp_msg*   igmp;
+  struct igmp_group* group;
+  struct igmp_group* groupref;
+
+  IGMP_STATS_INC(igmp.recv);
+
+  /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */    
+  iphdr = (struct ip_hdr *)p->payload;
+  if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
+    pbuf_free(p);
+    IGMP_STATS_INC(igmp.lenerr);
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
+    return;
+  }
+
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
+  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
+  LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
+  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
+  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
+
+  /* Now calculate and check the checksum */
+  igmp = (struct igmp_msg *)p->payload;
+  if (inet_chksum(igmp, p->len)) {
+    pbuf_free(p);
+    IGMP_STATS_INC(igmp.chkerr);
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
+    return;
+  }
+
+  /* Packet is ok so find an existing group */
+  group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
+  
+  /* If group can be found or create... */
+  if (!group) {
+    pbuf_free(p);
+    IGMP_STATS_INC(igmp.drop);
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
+    return;
+  }
+
+  /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
+  switch (igmp->igmp_msgtype) {
+   case IGMP_MEMB_QUERY: {
+     /* IGMP_MEMB_QUERY to the "all systems" address ? */
+     if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {
+       /* THIS IS THE GENERAL QUERY */
+       LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
+
+       if (igmp->igmp_maxresp == 0) {
+         IGMP_STATS_INC(igmp.rx_v1);
+         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
+         igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
+       } else {
+         IGMP_STATS_INC(igmp.rx_general);
+       }
+
+       groupref = igmp_group_list;
+       while (groupref) {
+         /* Do not send messages on the all systems group address! */
+         if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
+           igmp_delaying_member(groupref, igmp->igmp_maxresp);
+         }
+         groupref = groupref->next;
+       }
+     } else {
+       /* IGMP_MEMB_QUERY to a specific group ? */
+       if (!ip_addr_isany(&igmp->igmp_group_address)) {
+         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
+         ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
+         if (ip_addr_cmp(dest, &allsystems)) {
+           ip_addr_t groupaddr;
+           LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
+           /* we first need to re-look for the group since we used dest last time */
+           ip_addr_copy(groupaddr, igmp->igmp_group_address);
+           group = igmp_lookfor_group(inp, &groupaddr);
+         } else {
+           LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
+         }
+
+         if (group != NULL) {
+           IGMP_STATS_INC(igmp.rx_group);
+           igmp_delaying_member(group, igmp->igmp_maxresp);
+         } else {
+           IGMP_STATS_INC(igmp.drop);
+         }
+       } else {
+         IGMP_STATS_INC(igmp.proterr);
+       }
+     }
+     break;
+   }
+   case IGMP_V2_MEMB_REPORT: {
+     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
+     IGMP_STATS_INC(igmp.rx_report);
+     if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
+       /* This is on a specific group we have already looked up */
+       group->timer = 0; /* stopped */
+       group->group_state = IGMP_GROUP_IDLE_MEMBER;
+       group->last_reporter_flag = 0;
+     }
+     break;
+   }
+   default: {
+     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
+       igmp->igmp_msgtype, group->group_state, &group, group->netif));
+     IGMP_STATS_INC(igmp.proterr);
+     break;
+   }
+  }
+
+  pbuf_free(p);
+  return;
+}
+
+/**
+ * Join a group on one network interface.
+ *
+ * @param ifaddr ip address of the network interface which should join a new group
+ * @param groupaddr the ip address of the group which to join
+ * @return ERR_OK if group was joined on the netif(s), an err_t otherwise
+ */
+err_t
+igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
+{
+  err_t              err = ERR_VAL; /* no matching interface */
+  struct igmp_group *group;
+  struct netif      *netif;
+
+  /* make sure it is multicast address */
+  LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
+  LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
+
+  /* loop through netif's */
+  netif = netif_list;
+  while (netif != NULL) {
+    /* Should we join this interface ? */
+    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
+      /* find group or create a new one if not found */
+      group = igmp_lookup_group(netif, groupaddr);
+
+      if (group != NULL) {
+        /* This should create a new group, check the state to make sure */
+        if (group->group_state != IGMP_GROUP_NON_MEMBER) {
+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
+        } else {
+          /* OK - it was new group */
+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
+          ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+
+          /* If first use of the group, allow the group at the MAC level */
+          if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
+            ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+            netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
+          }
+
+          IGMP_STATS_INC(igmp.tx_join);
+          igmp_send(group, IGMP_V2_MEMB_REPORT);
+
+          igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
+
+          /* Need to work out where this timer comes from */
+          group->group_state = IGMP_GROUP_DELAYING_MEMBER;
+        }
+        /* Increment group use */
+        group->use++;
+        /* Join on this interface */
+        err = ERR_OK;
+      } else {
+        /* Return an error even if some network interfaces are joined */
+        /** @todo undo any other netif already joined */
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
+        return ERR_MEM;
+      }
+    }
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+
+  return err;
+}
+
+/**
+ * Leave a group on one network interface.
+ *
+ * @param ifaddr ip address of the network interface which should leave a group
+ * @param groupaddr the ip address of the group which to leave
+ * @return ERR_OK if group was left on the netif(s), an err_t otherwise
+ */
+err_t
+igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
+{
+  err_t              err = ERR_VAL; /* no matching interface */
+  struct igmp_group *group;
+  struct netif      *netif;
+
+  /* make sure it is multicast address */
+  LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
+  LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
+
+  /* loop through netif's */
+  netif = netif_list;
+  while (netif != NULL) {
+    /* Should we leave this interface ? */
+    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
+      /* find group */
+      group = igmp_lookfor_group(netif, groupaddr);
+
+      if (group != NULL) {
+        /* Only send a leave if the flag is set according to the state diagram */
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
+        ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+        LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
+
+        /* If there is no other use of the group */
+        if (group->use <= 1) {
+          /* If we are the last reporter for this group */
+          if (group->last_reporter_flag) {
+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
+            IGMP_STATS_INC(igmp.tx_leave);
+            igmp_send(group, IGMP_LEAVE_GROUP);
+          }
+          
+          /* Disable the group at the MAC level */
+          if (netif->igmp_mac_filter != NULL) {
+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
+            ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
+            netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
+          }
+          
+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
+          ip_addr_debug_print(IGMP_DEBUG, groupaddr);
+          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));          
+          
+          /* Free the group */
+          igmp_remove_group(group);
+        } else {
+          /* Decrement group use */
+          group->use--;
+        }
+        /* Leave on this interface */
+        err = ERR_OK;
+      } else {
+        /* It's not a fatal error on "leavegroup" */
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
+      }
+    }
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+
+  return err;
+}
+
+/**
+ * The igmp timer function (both for NO_SYS=1 and =0)
+ * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
+ */
+void
+igmp_tmr(void)
+{
+  struct igmp_group *group = igmp_group_list;
+
+  while (group != NULL) {
+    if (group->timer > 0) {
+      group->timer--;
+      if (group->timer == 0) {
+        igmp_timeout(group);
+      }
+    }
+    group = group->next;
+  }
+}
+
+/**
+ * Called if a timeout for one group is reached.
+ * Sends a report for this group.
+ *
+ * @param group an igmp_group for which a timeout is reached
+ */
+static void
+igmp_timeout(struct igmp_group *group)
+{
+  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
+  if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
+    ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
+    LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
+
+    IGMP_STATS_INC(igmp.tx_report);
+    igmp_send(group, IGMP_V2_MEMB_REPORT);
+  }
+}
+
+/**
+ * Start a timer for an igmp group
+ *
+ * @param group the igmp_group for which to start a timer
+ * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
+ *        every call to igmp_tmr())
+ */
+static void
+igmp_start_timer(struct igmp_group *group, u8_t max_time)
+{
+  /* ensure the input value is > 0 */
+  if (max_time == 0) {
+    max_time = 1;
+  }
+  /* ensure the random value is > 0 */
+  group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
+}
+
+/**
+ * Stop a timer for an igmp_group
+ *
+ * @param group the igmp_group for which to stop the timer
+ */
+static void
+igmp_stop_timer(struct igmp_group *group)
+{
+  group->timer = 0;
+}
+
+/**
+ * Delaying membership report for a group if necessary
+ *
+ * @param group the igmp_group for which "delaying" membership report
+ * @param maxresp query delay
+ */
+static void
+igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
+{
+  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
+     ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
+      ((group->timer == 0) || (maxresp < group->timer)))) {
+    igmp_start_timer(group, maxresp);
+    group->group_state = IGMP_GROUP_DELAYING_MEMBER;
+  }
+}
+
+
+/**
+ * Sends an IP packet on a network interface. This function constructs the IP header
+ * and calculates the IP header checksum. If the source IP address is NULL,
+ * the IP address of the outgoing network interface is filled in as source address.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param netif the netif on which to send this packet
+ * @return ERR_OK if the packet was sent OK
+ *         ERR_BUF if p doesn't have enough space for IP/LINK headers
+ *         returns errors returned by netif->output
+ */
+static err_t
+igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
+{
+  /* This is the "router alert" option */
+  u16_t ra[2];
+  ra[0] = PP_HTONS(ROUTER_ALERT);
+  ra[1] = 0x0000; /* Router shall examine packet */
+  IGMP_STATS_INC(igmp.xmit);
+  return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
+}
+
+/**
+ * Send an igmp packet to a specific group.
+ *
+ * @param group the group to which to send the packet
+ * @param type the type of igmp packet to send
+ */
+static void
+igmp_send(struct igmp_group *group, u8_t type)
+{
+  struct pbuf*     p    = NULL;
+  struct igmp_msg* igmp = NULL;
+  ip_addr_t   src  = *IP_ADDR_ANY;
+  ip_addr_t*  dest = NULL;
+
+  /* IP header + "router alert" option + IGMP header */
+  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
+  
+  if (p) {
+    igmp = (struct igmp_msg *)p->payload;
+    LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
+               (p->len >= sizeof(struct igmp_msg)));
+    ip_addr_copy(src, group->netif->ip_addr);
+     
+    if (type == IGMP_V2_MEMB_REPORT) {
+      dest = &(group->group_address);
+      ip_addr_copy(igmp->igmp_group_address, group->group_address);
+      group->last_reporter_flag = 1; /* Remember we were the last to report */
+    } else {
+      if (type == IGMP_LEAVE_GROUP) {
+        dest = &allrouters;
+        ip_addr_copy(igmp->igmp_group_address, group->group_address);
+      }
+    }
+
+    if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
+      igmp->igmp_msgtype  = type;
+      igmp->igmp_maxresp  = 0;
+      igmp->igmp_checksum = 0;
+      igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
+
+      igmp_ip_output_if(p, &src, dest, group->netif);
+    }
+
+    pbuf_free(p);
+  } else {
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
+    IGMP_STATS_INC(igmp.memerr);
+  }
+}
+
+#endif /* LWIP_IGMP */
diff -r 000000000000 -r 350011bf8be7 lwip/core/ipv4/inet.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/ipv4/inet.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,42 @@
+/**
+ * @file
+ * Functions common to all TCP/IPv4 modules, such as the byte order functions.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/inet.h"
+
diff -r 000000000000 -r 350011bf8be7 lwip/core/ipv4/inet_chksum.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/ipv4/inet_chksum.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,450 @@
+/**
+ * @file
+ * Incluse internet checksum functions.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/inet_chksum.h"
+#include "lwip/def.h"
+
+#include <stddef.h>
+#include <string.h>
+
+/* These are some reference implementations of the checksum algorithm, with the
+ * aim of being simple, correct and fully portable. Checksumming is the
+ * first thing you would want to optimize for your platform. If you create
+ * your own version, link it in and in your cc.h put:
+ * 
+ * #define LWIP_CHKSUM <your_checksum_routine> 
+ *
+ * Or you can select from the implementations below by defining
+ * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
+ */
+
+#ifndef LWIP_CHKSUM
+# define LWIP_CHKSUM lwip_standard_chksum
+# ifndef LWIP_CHKSUM_ALGORITHM
+#  define LWIP_CHKSUM_ALGORITHM 2
+# endif
+#endif
+/* If none set: */
+#ifndef LWIP_CHKSUM_ALGORITHM
+# define LWIP_CHKSUM_ALGORITHM 0
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
+/**
+ * lwip checksum
+ *
+ * @param dataptr points to start of data to be summed at any boundary
+ * @param len length of data to be summed
+ * @return host order (!) lwip checksum (non-inverted Internet sum) 
+ *
+ * @note accumulator size limits summable length to 64k
+ * @note host endianess is irrelevant (p3 RFC1071)
+ */
+static u16_t
+lwip_standard_chksum(void *dataptr, u16_t len)
+{
+  u32_t acc;
+  u16_t src;
+  u8_t *octetptr;
+
+  acc = 0;
+  /* dataptr may be at odd or even addresses */
+  octetptr = (u8_t*)dataptr;
+  while (len > 1) {
+    /* declare first octet as most significant
+       thus assume network order, ignoring host order */
+    src = (*octetptr) << 8;
+    octetptr++;
+    /* declare second octet as least significant */
+    src |= (*octetptr);
+    octetptr++;
+    acc += src;
+    len -= 2;
+  }
+  if (len > 0) {
+    /* accumulate remaining octet */
+    src = (*octetptr) << 8;
+    acc += src;
+  }
+  /* add deferred carry bits */
+  acc = (acc >> 16) + (acc & 0x0000ffffUL);
+  if ((acc & 0xffff0000UL) != 0) {
+    acc = (acc >> 16) + (acc & 0x0000ffffUL);
+  }
+  /* This maybe a little confusing: reorder sum using htons()
+     instead of ntohs() since it has a little less call overhead.
+     The caller must invert bits for Internet sum ! */
+  return htons((u16_t)acc);
+}
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
+/*
+ * Curt McDowell
+ * Broadcom Corp.
+ * csm@broadcom.com
+ *
+ * IP checksum two bytes at a time with support for
+ * unaligned buffer.
+ * Works for len up to and including 0x20000.
+ * by Curt McDowell, Broadcom Corp. 12/08/2005
+ *
+ * @param dataptr points to start of data to be summed at any boundary
+ * @param len length of data to be summed
+ * @return host order (!) lwip checksum (non-inverted Internet sum) 
+ */
+
+static u16_t
+lwip_standard_chksum(void *dataptr, int len)
+{
+  u8_t *pb = (u8_t *)dataptr;
+  u16_t *ps, t = 0;
+  u32_t sum = 0;
+  int odd = ((mem_ptr_t)pb & 1);
+
+  /* Get aligned to u16_t */
+  if (odd && len > 0) {
+    ((u8_t *)&t)[1] = *pb++;
+    len--;
+  }
+
+  /* Add the bulk of the data */
+  ps = (u16_t *)(void *)pb;
+  while (len > 1) {
+    sum += *ps++;
+    len -= 2;
+  }
+
+  /* Consume left-over byte, if any */
+  if (len > 0) {
+    ((u8_t *)&t)[0] = *(u8_t *)ps;
+  }
+
+  /* Add end bytes */
+  sum += t;
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  sum = FOLD_U32T(sum);
+  sum = FOLD_U32T(sum);
+
+  /* Swap if alignment was odd */
+  if (odd) {
+    sum = SWAP_BYTES_IN_WORD(sum);
+  }
+
+  return (u16_t)sum;
+}
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
+/**
+ * An optimized checksum routine. Basically, it uses loop-unrolling on
+ * the checksum loop, treating the head and tail bytes specially, whereas
+ * the inner loop acts on 8 bytes at a time. 
+ *
+ * @arg start of buffer to be checksummed. May be an odd byte address.
+ * @len number of bytes in the buffer to be checksummed.
+ * @return host order (!) lwip checksum (non-inverted Internet sum) 
+ * 
+ * by Curt McDowell, Broadcom Corp. December 8th, 2005
+ */
+
+static u16_t
+lwip_standard_chksum(void *dataptr, int len)
+{
+  u8_t *pb = (u8_t *)dataptr;
+  u16_t *ps, t = 0;
+  u32_t *pl;
+  u32_t sum = 0, tmp;
+  /* starts at odd byte address? */
+  int odd = ((mem_ptr_t)pb & 1);
+
+  if (odd && len > 0) {
+    ((u8_t *)&t)[1] = *pb++;
+    len--;
+  }
+
+  ps = (u16_t *)pb;
+
+  if (((mem_ptr_t)ps & 3) && len > 1) {
+    sum += *ps++;
+    len -= 2;
+  }
+
+  pl = (u32_t *)ps;
+
+  while (len > 7)  {
+    tmp = sum + *pl++;          /* ping */
+    if (tmp < sum) {
+      tmp++;                    /* add back carry */
+    }
+
+    sum = tmp + *pl++;          /* pong */
+    if (sum < tmp) {
+      sum++;                    /* add back carry */
+    }
+
+    len -= 8;
+  }
+
+  /* make room in upper bits */
+  sum = FOLD_U32T(sum);
+
+  ps = (u16_t *)pl;
+
+  /* 16-bit aligned word remaining? */
+  while (len > 1) {
+    sum += *ps++;
+    len -= 2;
+  }
+
+  /* dangling tail byte remaining? */
+  if (len > 0) {                /* include odd byte */
+    ((u8_t *)&t)[0] = *(u8_t *)ps;
+  }
+
+  sum += t;                     /* add end bytes */
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  sum = FOLD_U32T(sum);
+  sum = FOLD_U32T(sum);
+
+  if (odd) {
+    sum = SWAP_BYTES_IN_WORD(sum);
+  }
+
+  return (u16_t)sum;
+}
+#endif
+
+/* inet_chksum_pseudo:
+ *
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
+ * IP addresses are expected to be in network byte order.
+ *
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)
+ * @param src source ip address (used for checksum of pseudo header)
+ * @param dst destination ip address (used for checksum of pseudo header)
+ * @param proto ip protocol (used for checksum of pseudo header)
+ * @param proto_len length of the ip data part (used for checksum of pseudo header)
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pseudo(struct pbuf *p,
+       ip_addr_t *src, ip_addr_t *dest,
+       u8_t proto, u16_t proto_len)
+{
+  u32_t acc;
+  u32_t addr;
+  struct pbuf *q;
+  u8_t swapped;
+
+  acc = 0;
+  swapped = 0;
+  /* iterate through all pbuf in chain */
+  for(q = p; q != NULL; q = q->next) {
+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
+      (void *)q, (void *)q->next));
+    acc += LWIP_CHKSUM(q->payload, q->len);
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
+    /* just executing this next line is probably faster that the if statement needed
+       to check whether we really need to execute it, and does no harm */
+    acc = FOLD_U32T(acc);
+    if (q->len % 2 != 0) {
+      swapped = 1 - swapped;
+      acc = SWAP_BYTES_IN_WORD(acc);
+    }
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
+  }
+
+  if (swapped) {
+    acc = SWAP_BYTES_IN_WORD(acc);
+  }
+  addr = ip4_addr_get_u32(src);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  addr = ip4_addr_get_u32(dest);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  acc += (u32_t)htons((u16_t)proto);
+  acc += (u32_t)htons(proto_len);
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
+  return (u16_t)~(acc & 0xffffUL);
+}
+
+/* inet_chksum_pseudo:
+ *
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
+ * IP addresses are expected to be in network byte order.
+ *
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)
+ * @param src source ip address (used for checksum of pseudo header)
+ * @param dst destination ip address (used for checksum of pseudo header)
+ * @param proto ip protocol (used for checksum of pseudo header)
+ * @param proto_len length of the ip data part (used for checksum of pseudo header)
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pseudo_partial(struct pbuf *p,
+       ip_addr_t *src, ip_addr_t *dest,
+       u8_t proto, u16_t proto_len, u16_t chksum_len)
+{
+  u32_t acc;
+  u32_t addr;
+  struct pbuf *q;
+  u8_t swapped;
+  u16_t chklen;
+
+  acc = 0;
+  swapped = 0;
+  /* iterate through all pbuf in chain */
+  for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
+      (void *)q, (void *)q->next));
+    chklen = q->len;
+    if (chklen > chksum_len) {
+      chklen = chksum_len;
+    }
+    acc += LWIP_CHKSUM(q->payload, chklen);
+    chksum_len -= chklen;
+    LWIP_ASSERT("delete me", chksum_len < 0x7fff);
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
+    /* fold the upper bit down */
+    acc = FOLD_U32T(acc);
+    if (q->len % 2 != 0) {
+      swapped = 1 - swapped;
+      acc = SWAP_BYTES_IN_WORD(acc);
+    }
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
+  }
+
+  if (swapped) {
+    acc = SWAP_BYTES_IN_WORD(acc);
+  }
+  addr = ip4_addr_get_u32(src);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  addr = ip4_addr_get_u32(dest);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  acc += (u32_t)htons((u16_t)proto);
+  acc += (u32_t)htons(proto_len);
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
+  return (u16_t)~(acc & 0xffffUL);
+}
+
+/* inet_chksum:
+ *
+ * Calculates the Internet checksum over a portion of memory. Used primarily for IP
+ * and ICMP.
+ *
+ * @param dataptr start of the buffer to calculate the checksum (no alignment needed)
+ * @param len length of the buffer to calculate the checksum
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+
+u16_t
+inet_chksum(void *dataptr, u16_t len)
+{
+  return ~LWIP_CHKSUM(dataptr, len);
+}
+
+/**
+ * Calculate a checksum over a chain of pbufs (without pseudo-header, much like
+ * inet_chksum only pbufs are used).
+ *
+ * @param p pbuf chain over that the checksum should be calculated
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pbuf(struct pbuf *p)
+{
+  u32_t acc;
+  struct pbuf *q;
+  u8_t swapped;
+
+  acc = 0;
+  swapped = 0;
+  for(q = p; q != NULL; q = q->next) {
+    acc += LWIP_CHKSUM(q->payload, q->len);
+    acc = FOLD_U32T(acc);
+    if (q->len % 2 != 0) {
+      swapped = 1 - swapped;
+      acc = SWAP_BYTES_IN_WORD(acc);
+    }
+  }
+
+  if (swapped) {
+    acc = SWAP_BYTES_IN_WORD(acc);
+  }
+  return (u16_t)~(acc & 0xffffUL);
+}
+
+/* These are some implementations for LWIP_CHKSUM_COPY, which copies data
+ * like MEMCPY but generates a checksum at the same time. Since this is a
+ * performance-sensitive function, you might want to create your own version
+ * in assembly targeted at your hardware by defining it in lwipopts.h:
+ *   #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
+ */
+
+#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
+/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.
+ * For architectures with big caches, data might still be in cache when
+ * generating the checksum after copying.
+ */
+u16_t
+lwip_chksum_copy(void *dst, const void *src, u16_t len)
+{
+  MEMCPY(dst, src, len);
+  return LWIP_CHKSUM(dst, len);
+}
+#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */
diff -r 000000000000 -r 350011bf8be7 lwip/core/ipv4/ip.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/ipv4/ip.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,857 @@
+/**
+ * @file
+ * This is the IPv4 layer implementation for incoming and outgoing IP traffic.
+ * 
+ * @see ip_frag.c
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/ip_frag.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/icmp.h"
+#include "lwip/igmp.h"
+#include "lwip/raw.h"
+#include "lwip/udp.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/snmp.h"
+#include "lwip/dhcp.h"
+#include "lwip/autoip.h"
+#include "lwip/stats.h"
+#include "arch/perf.h"
+
+#include <string.h>
+
+/** Set this to 0 in the rare case of wanting to call an extra function to
+ * generate the IP checksum (in contrast to calculating it on-the-fly). */
+#ifndef LWIP_INLINE_IP_CHKSUM
+#define LWIP_INLINE_IP_CHKSUM   1
+#endif
+#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
+#define CHECKSUM_GEN_IP_INLINE  1
+#else
+#define CHECKSUM_GEN_IP_INLINE  0
+#endif
+
+#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)
+#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1
+
+/** Some defines for DHCP to let link-layer-addressed packets through while the
+ * netif is down.
+ * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT
+ * to return 1 if the port is accepted and 0 if the port is not accepted.
+ */
+#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)
+/* accept DHCP client port and custom port */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \
+         || (LWIP_IP_ACCEPT_UDP_PORT(port)))
+#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+/* accept custom port only */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))
+#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+/* accept DHCP client port only */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
+#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+
+#else /* LWIP_DHCP */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
+#endif /* LWIP_DHCP */
+
+/**
+ * The interface that provided the packet for the current callback
+ * invocation.
+ */
+struct netif *current_netif;
+
+/**
+ * Header of the input packet currently being processed.
+ */
+const struct ip_hdr *current_header;
+/** Source IP address of current_header */
+ip_addr_t current_iphdr_src;
+/** Destination IP address of current_header */
+ip_addr_t current_iphdr_dest;
+
+/** The IP header ID of the next outgoing IP packet */
+static u16_t ip_id;
+
+/**
+ * Finds the appropriate network interface for a given IP address. It
+ * searches the list of network interfaces linearly. A match is found
+ * if the masked IP address of the network interface equals the masked
+ * IP address given to the function.
+ *
+ * @param dest the destination IP address for which to find the route
+ * @return the netif on which to send to reach dest
+ */
+struct netif *
+ip_route(ip_addr_t *dest)
+{
+  struct netif *netif;
+
+  /* iterate through netifs */
+  for(netif = netif_list; netif != NULL; netif = netif->next) {
+    /* network mask matches? */
+    if (netif_is_up(netif)) {
+      if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
+        /* return netif on which to forward IP packet */
+        return netif;
+      }
+    }
+  }
+  if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
+    IP_STATS_INC(ip.rterr);
+    snmp_inc_ipoutnoroutes();
+    return NULL;
+  }
+  /* no matching netif found, use default netif */
+  return netif_default;
+}
+
+#if IP_FORWARD
+/**
+ * Forwards an IP packet. It finds an appropriate route for the
+ * packet, decrements the TTL value of the packet, adjusts the
+ * checksum and outputs the packet on the appropriate interface.
+ *
+ * @param p the packet to forward (p->payload points to IP header)
+ * @param iphdr the IP header of the input packet
+ * @param inp the netif on which this packet was received
+ */
+static void
+ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
+{
+  struct netif *netif;
+
+  PERF_START;
+
+  /* RFC3927 2.7: do not forward link-local addresses */
+  if (ip_addr_islinklocal(&current_iphdr_dest)) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
+      ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
+    goto return_noroute;
+  }
+
+  /* Find network interface where to forward this IP packet to. */
+  netif = ip_route(&current_iphdr_dest);
+  if (netif == NULL) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
+      ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
+      ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
+    goto return_noroute;
+  }
+  /* Do not forward packets onto the same network interface on which
+   * they arrived. */
+  if (netif == inp) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
+    goto return_noroute;
+  }
+
+  /* decrement TTL */
+  IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
+  /* send ICMP if TTL == 0 */
+  if (IPH_TTL(iphdr) == 0) {
+    snmp_inc_ipinhdrerrors();
+#if LWIP_ICMP
+    /* Don't send ICMP messages in response to ICMP messages */
+    if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
+      icmp_time_exceeded(p, ICMP_TE_TTL);
+    }
+#endif /* LWIP_ICMP */
+    return;
+  }
+
+  /* Incrementally update the IP checksum. */
+  if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffff - 0x100)) {
+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
+  } else {
+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
+  }
+
+  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+    ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
+    ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
+
+  IP_STATS_INC(ip.fw);
+  IP_STATS_INC(ip.xmit);
+  snmp_inc_ipforwdatagrams();
+
+  PERF_STOP("ip_forward");
+  /* transmit pbuf on chosen interface */
+  netif->output(netif, p, &current_iphdr_dest);
+  return;
+return_noroute:
+  snmp_inc_ipoutnoroutes();
+}
+#endif /* IP_FORWARD */
+
+/**
+ * This function is called by the network interface device driver when
+ * an IP packet is received. The function does the basic checks of the
+ * IP header such as packet size being at least larger than the header
+ * size etc. If the packet was not destined for us, the packet is
+ * forwarded (using ip_forward). The IP checksum is always checked.
+ *
+ * Finally, the packet is sent to the upper layer protocol input function.
+ * 
+ * @param p the received IP packet (p->payload points to IP header)
+ * @param inp the netif on which this packet was received
+ * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
+ *         processed, but currently always returns ERR_OK)
+ */
+err_t
+ip_input(struct pbuf *p, struct netif *inp)
+{
+  struct ip_hdr *iphdr;
+  struct netif *netif;
+  u16_t iphdr_hlen;
+  u16_t iphdr_len;
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+  int check_ip_src=1;
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+
+  IP_STATS_INC(ip.recv);
+  snmp_inc_ipinreceives();
+
+  /* identify the IP header */
+  iphdr = (struct ip_hdr *)p->payload;
+  if (IPH_V(iphdr) != 4) {
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
+    ip_debug_print(p);
+    pbuf_free(p);
+    IP_STATS_INC(ip.err);
+    IP_STATS_INC(ip.drop);
+    snmp_inc_ipinhdrerrors();
+    return ERR_OK;
+  }
+
+  /* obtain IP header length in number of 32-bit words */
+  iphdr_hlen = IPH_HL(iphdr);
+  /* calculate IP header length in bytes */
+  iphdr_hlen *= 4;
+  /* obtain ip length in bytes */
+  iphdr_len = ntohs(IPH_LEN(iphdr));
+
+  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
+  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
+    if (iphdr_hlen > p->len) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
+        iphdr_hlen, p->len));
+    }
+    if (iphdr_len > p->tot_len) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
+        iphdr_len, p->tot_len));
+    }
+    /* free (drop) packet pbufs */
+    pbuf_free(p);
+    IP_STATS_INC(ip.lenerr);
+    IP_STATS_INC(ip.drop);
+    snmp_inc_ipindiscards();
+    return ERR_OK;
+  }
+
+  /* verify checksum */
+#if CHECKSUM_CHECK_IP
+  if (inet_chksum(iphdr, iphdr_hlen) != 0) {
+
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+      ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
+    ip_debug_print(p);
+    pbuf_free(p);
+    IP_STATS_INC(ip.chkerr);
+    IP_STATS_INC(ip.drop);
+    snmp_inc_ipinhdrerrors();
+    return ERR_OK;
+  }
+#endif
+
+  /* Trim pbuf. This should have been done at the netif layer,
+   * but we'll do it anyway just to be sure that its done. */
+  pbuf_realloc(p, iphdr_len);
+
+  /* copy IP addresses to aligned ip_addr_t */
+  ip_addr_copy(current_iphdr_dest, iphdr->dest);
+  ip_addr_copy(current_iphdr_src, iphdr->src);
+
+  /* match packet against an interface, i.e. is this packet for us? */
+#if LWIP_IGMP
+  if (ip_addr_ismulticast(&current_iphdr_dest)) {
+    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &current_iphdr_dest))) {
+      netif = inp;
+    } else {
+      netif = NULL;
+    }
+  } else
+#endif /* LWIP_IGMP */
+  {
+    /* start trying with inp. if that's not acceptable, start walking the
+       list of configured netifs.
+       'first' is used as a boolean to mark whether we started walking the list */
+    int first = 1;
+    netif = inp;
+    do {
+      LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
+          ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr),
+          ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask),
+          ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask),
+          ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask)));
+
+      /* interface is up and configured? */
+      if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
+        /* unicast to this interface address? */
+        if (ip_addr_cmp(&current_iphdr_dest, &(netif->ip_addr)) ||
+            /* or broadcast on this interface network address? */
+            ip_addr_isbroadcast(&current_iphdr_dest, netif)) {
+          LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
+              netif->name[0], netif->name[1]));
+          /* break out of for loop */
+          break;
+        }
+#if LWIP_AUTOIP
+        /* connections to link-local addresses must persist after changing
+           the netif's address (RFC3927 ch. 1.9) */
+        if ((netif->autoip != NULL) &&
+            ip_addr_cmp(&current_iphdr_dest, &(netif->autoip->llipaddr))) {
+          LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n",
+              netif->name[0], netif->name[1]));
+          /* break out of for loop */
+          break;
+        }
+#endif /* LWIP_AUTOIP */
+      }
+      if (first) {
+        first = 0;
+        netif = netif_list;
+      } else {
+        netif = netif->next;
+      }
+      if (netif == inp) {
+        netif = netif->next;
+      }
+    } while(netif != NULL);
+  }
+
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+  /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
+   * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
+   * According to RFC 1542 section 3.1.1, referred by RFC 2131).
+   *
+   * If you want to accept private broadcast communication while a netif is down,
+   * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:
+   *
+   * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))
+   */
+  if (netif == NULL) {
+    /* remote port is DHCP server? */
+    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
+      struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
+        ntohs(udphdr->dest)));
+      if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
+        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
+        netif = inp;
+        check_ip_src = 0;
+      }
+    }
+  }
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+
+  /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+  /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
+  if (check_ip_src && !ip_addr_isany(&current_iphdr_src))
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+  {  if ((ip_addr_isbroadcast(&current_iphdr_src, inp)) ||
+         (ip_addr_ismulticast(&current_iphdr_src))) {
+      /* packet source is not valid */
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
+      /* free (drop) packet pbufs */
+      pbuf_free(p);
+      IP_STATS_INC(ip.drop);
+      snmp_inc_ipinaddrerrors();
+      snmp_inc_ipindiscards();
+      return ERR_OK;
+    }
+  }
+
+  /* packet not for us? */
+  if (netif == NULL) {
+    /* packet not for us, route or discard */
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
+#if IP_FORWARD
+    /* non-broadcast packet? */
+    if (!ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
+      /* try to forward IP packet on (other) interfaces */
+      ip_forward(p, iphdr, inp);
+    } else
+#endif /* IP_FORWARD */
+    {
+      snmp_inc_ipinaddrerrors();
+      snmp_inc_ipindiscards();
+    }
+    pbuf_free(p);
+    return ERR_OK;
+  }
+  /* packet consists of multiple fragments? */
+  if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
+#if IP_REASSEMBLY /* packet fragment reassembly code present? */
+    LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
+      ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
+    /* reassemble the packet*/
+    p = ip_reass(p);
+    /* packet not fully reassembled yet? */
+    if (p == NULL) {
+      return ERR_OK;
+    }
+    iphdr = (struct ip_hdr *)p->payload;
+#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
+    pbuf_free(p);
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
+      ntohs(IPH_OFFSET(iphdr))));
+    IP_STATS_INC(ip.opterr);
+    IP_STATS_INC(ip.drop);
+    /* unsupported protocol feature */
+    snmp_inc_ipinunknownprotos();
+    return ERR_OK;
+#endif /* IP_REASSEMBLY */
+  }
+
+#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
+
+#if LWIP_IGMP
+  /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
+  if((iphdr_hlen > IP_HLEN) &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
+#else
+  if (iphdr_hlen > IP_HLEN) {
+#endif /* LWIP_IGMP */
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
+    pbuf_free(p);
+    IP_STATS_INC(ip.opterr);
+    IP_STATS_INC(ip.drop);
+    /* unsupported protocol feature */
+    snmp_inc_ipinunknownprotos();
+    return ERR_OK;
+  }
+#endif /* IP_OPTIONS_ALLOWED == 0 */
+
+  /* send to upper layers */
+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
+  ip_debug_print(p);
+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
+
+  current_netif = inp;
+  current_header = iphdr;
+
+#if LWIP_RAW
+  /* raw input did not eat the packet? */
+  if (raw_input(p, inp) == 0)
+#endif /* LWIP_RAW */
+  {
+
+    switch (IPH_PROTO(iphdr)) {
+#if LWIP_UDP
+    case IP_PROTO_UDP:
+#if LWIP_UDPLITE
+    case IP_PROTO_UDPLITE:
+#endif /* LWIP_UDPLITE */
+      snmp_inc_ipindelivers();
+      udp_input(p, inp);
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+    case IP_PROTO_TCP:
+      snmp_inc_ipindelivers();
+      tcp_input(p, inp);
+      break;
+#endif /* LWIP_TCP */
+#if LWIP_ICMP
+    case IP_PROTO_ICMP:
+      snmp_inc_ipindelivers();
+      icmp_input(p, inp);
+      break;
+#endif /* LWIP_ICMP */
+#if LWIP_IGMP
+    case IP_PROTO_IGMP:
+      igmp_input(p, inp, &current_iphdr_dest);
+      break;
+#endif /* LWIP_IGMP */
+    default:
+#if LWIP_ICMP
+      /* send ICMP destination protocol unreachable unless is was a broadcast */
+      if (!ip_addr_isbroadcast(&current_iphdr_dest, inp) &&
+          !ip_addr_ismulticast(&current_iphdr_dest)) {
+        p->payload = iphdr;
+        icmp_dest_unreach(p, ICMP_DUR_PROTO);
+      }
+#endif /* LWIP_ICMP */
+      pbuf_free(p);
+
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
+
+      IP_STATS_INC(ip.proterr);
+      IP_STATS_INC(ip.drop);
+      snmp_inc_ipinunknownprotos();
+    }
+  }
+
+  current_netif = NULL;
+  current_header = NULL;
+  ip_addr_set_any(&current_iphdr_src);
+  ip_addr_set_any(&current_iphdr_dest);
+
+  return ERR_OK;
+}
+
+/**
+ * Sends an IP packet on a network interface. This function constructs
+ * the IP header and calculates the IP header checksum. If the source
+ * IP address is NULL, the IP address of the outgoing network
+ * interface is filled in as source address.
+ * If the destination IP address is IP_HDRINCL, p is assumed to already
+ * include an IP header and p->payload points to it instead of the data.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param netif the netif on which to send this packet
+ * @return ERR_OK if the packet was sent OK
+ *         ERR_BUF if p doesn't have enough space for IP/LINK headers
+ *         returns errors returned by netif->output
+ *
+ * @note ip_id: RFC791 "some host may be able to simply use
+ *  unique identifiers independent of destination"
+ */
+err_t
+ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+             u8_t ttl, u8_t tos,
+             u8_t proto, struct netif *netif)
+{
+#if IP_OPTIONS_SEND
+  return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
+}
+
+/**
+ * Same as ip_output_if() but with the possibility to include IP options:
+ *
+ * @ param ip_options pointer to the IP options, copied into the IP header
+ * @ param optlen length of ip_options
+ */
+err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
+       u16_t optlen)
+{
+#endif /* IP_OPTIONS_SEND */
+  struct ip_hdr *iphdr;
+  ip_addr_t dest_addr;
+#if CHECKSUM_GEN_IP_INLINE
+  u32_t chk_sum = 0;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  snmp_inc_ipoutrequests();
+
+  /* Should the IP header be generated or is it already included in p? */
+  if (dest != IP_HDRINCL) {
+    u16_t ip_hlen = IP_HLEN;
+#if IP_OPTIONS_SEND
+    u16_t optlen_aligned = 0;
+    if (optlen != 0) {
+#if CHECKSUM_GEN_IP_INLINE
+      int i;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+      /* round up to a multiple of 4 */
+      optlen_aligned = ((optlen + 3) & ~3);
+      ip_hlen += optlen_aligned;
+      /* First write in the IP options */
+      if (pbuf_header(p, optlen_aligned)) {
+        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
+        IP_STATS_INC(ip.err);
+        snmp_inc_ipoutdiscards();
+        return ERR_BUF;
+      }
+      MEMCPY(p->payload, ip_options, optlen);
+      if (optlen < optlen_aligned) {
+        /* zero the remaining bytes */
+        memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
+      }
+#if CHECKSUM_GEN_IP_INLINE
+      for (i = 0; i < optlen_aligned; i += sizeof(u16_t)) {
+        chk_sum += ((u16_t*)p->payload)[i];
+      }
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    }
+#endif /* IP_OPTIONS_SEND */
+    /* generate IP header */
+    if (pbuf_header(p, IP_HLEN)) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
+
+      IP_STATS_INC(ip.err);
+      snmp_inc_ipoutdiscards();
+      return ERR_BUF;
+    }
+
+    iphdr = (struct ip_hdr *)p->payload;
+    LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
+               (p->len >= sizeof(struct ip_hdr)));
+
+    IPH_TTL_SET(iphdr, ttl);
+    IPH_PROTO_SET(iphdr, proto);
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += LWIP_MAKE_U16(proto, ttl);
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+    /* dest cannot be NULL here */
+    ip_addr_copy(iphdr->dest, *dest);
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;
+    chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+    IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += iphdr->_v_hl_tos;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    IPH_LEN_SET(iphdr, htons(p->tot_len));
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += iphdr->_len;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    IPH_OFFSET_SET(iphdr, 0);
+    IPH_ID_SET(iphdr, htons(ip_id));
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += iphdr->_id;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    ++ip_id;
+
+    if (ip_addr_isany(src)) {
+      ip_addr_copy(iphdr->src, netif->ip_addr);
+    } else {
+      /* src cannot be NULL here */
+      ip_addr_copy(iphdr->src, *src);
+    }
+
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;
+    chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;
+    chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);
+    chk_sum = (chk_sum >> 16) + chk_sum;
+    chk_sum = ~chk_sum;
+    iphdr->_chksum = chk_sum; /* network order */
+#else /* CHECKSUM_GEN_IP_INLINE */
+    IPH_CHKSUM_SET(iphdr, 0);
+#if CHECKSUM_GEN_IP
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
+#endif
+#endif /* CHECKSUM_GEN_IP_INLINE */
+  } else {
+    /* IP header already included in p */
+    iphdr = (struct ip_hdr *)p->payload;
+    ip_addr_copy(dest_addr, iphdr->dest);
+    dest = &dest_addr;
+  }
+
+  IP_STATS_INC(ip.xmit);
+
+  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
+  ip_debug_print(p);
+
+#if ENABLE_LOOPBACK
+  if (ip_addr_cmp(dest, &netif->ip_addr)) {
+    /* Packet to self, enqueue it for loopback */
+    LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
+    return netif_loop_output(netif, p, dest);
+  }
+#if LWIP_IGMP
+  if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
+    netif_loop_output(netif, p, dest);
+  }
+#endif /* LWIP_IGMP */
+#endif /* ENABLE_LOOPBACK */
+#if IP_FRAG
+  /* don't fragment if interface has mtu set to 0 [loopif] */
+  if (netif->mtu && (p->tot_len > netif->mtu)) {
+    return ip_frag(p, netif, dest);
+  }
+#endif /* IP_FRAG */
+
+  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
+  return netif->output(netif, p, dest);
+}
+
+/**
+ * Simple interface to ip_output_if. It finds the outgoing network
+ * interface and calls upon ip_output_if to do the actual work.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ *
+ * @return ERR_RTE if no route is found
+ *         see ip_output_if() for more return values
+ */
+err_t
+ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+          u8_t ttl, u8_t tos, u8_t proto)
+{
+  struct netif *netif;
+
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  if ((netif = ip_route(dest)) == NULL) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
+    IP_STATS_INC(ip.rterr);
+    return ERR_RTE;
+  }
+
+  return ip_output_if(p, src, dest, ttl, tos, proto, netif);
+}
+
+#if LWIP_NETIF_HWADDRHINT
+/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
+ *  before calling ip_output_if.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param addr_hint address hint pointer set to netif->addr_hint before
+ *        calling ip_output_if()
+ *
+ * @return ERR_RTE if no route is found
+ *         see ip_output_if() for more return values
+ */
+err_t
+ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+          u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
+{
+  struct netif *netif;
+  err_t err;
+
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  if ((netif = ip_route(dest)) == NULL) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
+    IP_STATS_INC(ip.rterr);
+    return ERR_RTE;
+  }
+
+  netif->addr_hint = addr_hint;
+  err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
+  netif->addr_hint = NULL;
+
+  return err;
+}
+#endif /* LWIP_NETIF_HWADDRHINT*/
+
+#if IP_DEBUG
+/* Print an IP header by using LWIP_DEBUGF
+ * @param p an IP packet, p->payload pointing to the IP header
+ */
+void
+ip_debug_print(struct pbuf *p)
+{
+  struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
+  u8_t *payload;
+
+  payload = (u8_t *)iphdr + IP_HLEN;
+
+  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n",
+                    IPH_V(iphdr),
+                    IPH_HL(iphdr),
+                    IPH_TOS(iphdr),
+                    ntohs(IPH_LEN(iphdr))));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n",
+                    ntohs(IPH_ID(iphdr)),
+                    ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
+                    ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
+                    ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
+                    ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n",
+                    IPH_TTL(iphdr),
+                    IPH_PROTO(iphdr),
+                    ntohs(IPH_CHKSUM(iphdr))));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n",
+                    ip4_addr1_16(&iphdr->src),
+                    ip4_addr2_16(&iphdr->src),
+                    ip4_addr3_16(&iphdr->src),
+                    ip4_addr4_16(&iphdr->src)));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n",
+                    ip4_addr1_16(&iphdr->dest),
+                    ip4_addr2_16(&iphdr->dest),
+                    ip4_addr3_16(&iphdr->dest),
+                    ip4_addr4_16(&iphdr->dest)));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+}
+#endif /* IP_DEBUG */
diff -r 000000000000 -r 350011bf8be7 lwip/core/ipv4/ip_addr.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/ipv4/ip_addr.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,312 @@
+/**
+ * @file
+ * This is the IPv4 address tools implementation.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+
+/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
+const ip_addr_t ip_addr_any = { IPADDR_ANY };
+const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST };
+
+/**
+ * Determine if an address is a broadcast address on a network interface 
+ * 
+ * @param addr address to be checked
+ * @param netif the network interface against which the address is checked
+ * @return returns non-zero if the address is a broadcast address
+ */
+u8_t
+ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
+{
+  ip_addr_t ipaddr;
+  ip4_addr_set_u32(&ipaddr, addr);
+
+  /* all ones (broadcast) or all zeroes (old skool broadcast) */
+  if ((~addr == IPADDR_ANY) ||
+      (addr == IPADDR_ANY)) {
+    return 1;
+  /* no broadcast support on this network interface? */
+  } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {
+    /* the given address cannot be a broadcast address
+     * nor can we check against any broadcast addresses */
+    return 0;
+  /* address matches network interface address exactly? => no broadcast */
+  } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
+    return 0;
+  /*  on the same (sub) network... */
+  } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
+         /* ...and host identifier bits are all ones? =>... */
+          && ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
+           (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
+    /* => network broadcast address */
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+/** Checks if a netmask is valid (starting with ones, then only zeros)
+ *
+ * @param netmask the IPv4 netmask to check (in network byte order!)
+ * @return 1 if the netmask is valid, 0 if it is not
+ */
+u8_t
+ip4_addr_netmask_valid(u32_t netmask)
+{
+  u32_t mask;
+  u32_t nm_hostorder = lwip_htonl(netmask);
+
+  /* first, check for the first zero */
+  for (mask = 1U << 31 ; mask != 0; mask >>= 1) {
+    if ((nm_hostorder & mask) == 0) {
+      break;
+    }
+  }
+  /* then check that there is no one */
+  for (; mask != 0; mask >>= 1) {
+    if ((nm_hostorder & mask) != 0) {
+      /* there is a one after the first zero -> invalid */
+      return 0;
+    }
+  }
+  /* no one after the first zero -> valid */
+  return 1;
+}
+
+/* Here for now until needed in other places in lwIP */
+#ifndef isprint
+#define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)
+#define isprint(c)           in_range(c, 0x20, 0x7f)
+#define isdigit(c)           in_range(c, '0', '9')
+#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
+#define islower(c)           in_range(c, 'a', 'z')
+#define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
+#endif
+
+/**
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ *
+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")
+ * @return ip address in network order
+ */
+u32_t
+ipaddr_addr(const char *cp)
+{
+  ip_addr_t val;
+
+  if (ipaddr_aton(cp, &val)) {
+    return ip4_addr_get_u32(&val);
+  }
+  return (IPADDR_NONE);
+}
+
+/**
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ *
+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")
+ * @param addr pointer to which to save the ip address in network order
+ * @return 1 if cp could be converted to addr, 0 on failure
+ */
+int
+ipaddr_aton(const char *cp, ip_addr_t *addr)
+{
+  u32_t val;
+  u8_t base;
+  char c;
+  u32_t parts[4];
+  u32_t *pp = parts;
+
+  c = *cp;
+  for (;;) {
+    /*
+     * Collect number up to ``.''.
+     * Values are specified as for C:
+     * 0x=hex, 0=octal, 1-9=decimal.
+     */
+    if (!isdigit(c))
+      return (0);
+    val = 0;
+    base = 10;
+    if (c == '0') {
+      c = *++cp;
+      if (c == 'x' || c == 'X') {
+        base = 16;
+        c = *++cp;
+      } else
+        base = 8;
+    }
+    for (;;) {
+      if (isdigit(c)) {
+        val = (val * base) + (int)(c - '0');
+        c = *++cp;
+      } else if (base == 16 && isxdigit(c)) {
+        val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
+        c = *++cp;
+      } else
+        break;
+    }
+    if (c == '.') {
+      /*
+       * Internet format:
+       *  a.b.c.d
+       *  a.b.c   (with c treated as 16 bits)
+       *  a.b (with b treated as 24 bits)
+       */
+      if (pp >= parts + 3) {
+        return (0);
+      }
+      *pp++ = val;
+      c = *++cp;
+    } else
+      break;
+  }
+  /*
+   * Check for trailing characters.
+   */
+  if (c != '\0' && !isspace(c)) {
+    return (0);
+  }
+  /*
+   * Concoct the address according to
+   * the number of parts specified.
+   */
+  switch (pp - parts + 1) {
+
+  case 0:
+    return (0);       /* initial nondigit */
+
+  case 1:             /* a -- 32 bits */
+    break;
+
+  case 2:             /* a.b -- 8.24 bits */
+    if (val > 0xffffffUL) {
+      return (0);
+    }
+    val |= parts[0] << 24;
+    break;
+
+  case 3:             /* a.b.c -- 8.8.16 bits */
+    if (val > 0xffff) {
+      return (0);
+    }
+    val |= (parts[0] << 24) | (parts[1] << 16);
+    break;
+
+  case 4:             /* a.b.c.d -- 8.8.8.8 bits */
+    if (val > 0xff) {
+      return (0);
+    }
+    val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+    break;
+  default:
+    LWIP_ASSERT("unhandled", 0);
+    break;
+  }
+  if (addr) {
+    ip4_addr_set_u32(addr, htonl(val));
+  }
+  return (1);
+}
+
+/**
+ * Convert numeric IP address into decimal dotted ASCII representation.
+ * returns ptr to static buffer; not reentrant!
+ *
+ * @param addr ip address in network order to convert
+ * @return pointer to a global static (!) buffer that holds the ASCII
+ *         represenation of addr
+ */
+char *
+ipaddr_ntoa(const ip_addr_t *addr)
+{
+  static char str[16];
+  return ipaddr_ntoa_r(addr, str, 16);
+}
+
+/**
+ * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
+ *
+ * @param addr ip address in network order to convert
+ * @param buf target buffer where the string is stored
+ * @param buflen length of buf
+ * @return either pointer to buf which now holds the ASCII
+ *         representation of addr or NULL if buf was too small
+ */
+char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
+{
+  u32_t s_addr;
+  char inv[3];
+  char *rp;
+  u8_t *ap;
+  u8_t rem;
+  u8_t n;
+  u8_t i;
+  int len = 0;
+
+  s_addr = ip4_addr_get_u32(addr);
+
+  rp = buf;
+  ap = (u8_t *)&s_addr;
+  for(n = 0; n < 4; n++) {
+    i = 0;
+    do {
+      rem = *ap % (u8_t)10;
+      *ap /= (u8_t)10;
+      inv[i++] = '0' + rem;
+    } while(*ap);
+    while(i--) {
+      if (len++ >= buflen) {
+        return NULL;
+      }
+      *rp++ = inv[i];
+    }
+    if (len++ >= buflen) {
+      return NULL;
+    }
+    *rp++ = '.';
+    ap++;
+  }
+  *--rp = 0;
+  return buf;
+}
diff -r 000000000000 -r 350011bf8be7 lwip/core/ipv4/ip_frag.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/ipv4/ip_frag.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,863 @@
+/**
+ * @file
+ * This is the IPv4 packet segmentation and reassembly implementation.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Jani Monoses <jani@iv.ro> 
+ *         Simon Goldschmidt
+ * original reassembly code by Adam Dunkels <adam@sics.se>
+ * 
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip_frag.h"
+#include "lwip/def.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/snmp.h"
+#include "lwip/stats.h"
+#include "lwip/icmp.h"
+
+#include <string.h>
+
+#if IP_REASSEMBLY
+/**
+ * The IP reassembly code currently has the following limitations:
+ * - IP header options are not supported
+ * - fragments must not overlap (e.g. due to different routes),
+ *   currently, overlapping or duplicate fragments are thrown away
+ *   if IP_REASS_CHECK_OVERLAP=1 (the default)!
+ *
+ * @todo: work with IP header options
+ */
+
+/** Setting this to 0, you can turn off checking the fragments for overlapping
+ * regions. The code gets a little smaller. Only use this if you know that
+ * overlapping won't occur on your network! */
+#ifndef IP_REASS_CHECK_OVERLAP
+#define IP_REASS_CHECK_OVERLAP 1
+#endif /* IP_REASS_CHECK_OVERLAP */
+
+/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
+ * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
+ * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
+ * is set to 1, so one datagram can be reassembled at a time, only. */
+#ifndef IP_REASS_FREE_OLDEST
+#define IP_REASS_FREE_OLDEST 1
+#endif /* IP_REASS_FREE_OLDEST */
+
+#define IP_REASS_FLAG_LASTFRAG 0x01
+
+/** This is a helper struct which holds the starting
+ * offset and the ending offset of this fragment to
+ * easily chain the fragments.
+ * It has the same packing requirements as the IP header, since it replaces
+ * the IP header in memory in incoming fragments (after copying it) to keep
+ * track of the various fragments. (-> If the IP header doesn't need packing,
+ * this struct doesn't need packing, too.)
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_reass_helper {
+  PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
+  PACK_STRUCT_FIELD(u16_t start);
+  PACK_STRUCT_FIELD(u16_t end);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB)  \
+  (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
+   ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
+   IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
+
+/* global variables */
+static struct ip_reassdata *reassdatagrams;
+static u16_t ip_reass_pbufcount;
+
+/* function prototypes */
+static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
+static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
+
+/**
+ * Reassembly timer base function
+ * for both NO_SYS == 0 and 1 (!).
+ *
+ * Should be called every 1000 msec (defined by IP_TMR_INTERVAL).
+ */
+void
+ip_reass_tmr(void)
+{
+  struct ip_reassdata *r, *prev = NULL;
+
+  r = reassdatagrams;
+  while (r != NULL) {
+    /* Decrement the timer. Once it reaches 0,
+     * clean up the incomplete fragment assembly */
+    if (r->timer > 0) {
+      r->timer--;
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));
+      prev = r;
+      r = r->next;
+    } else {
+      /* reassembly timed out */
+      struct ip_reassdata *tmp;
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));
+      tmp = r;
+      /* get the next pointer before freeing */
+      r = r->next;
+      /* free the helper struct and all enqueued pbufs */
+      ip_reass_free_complete_datagram(tmp, prev);
+     }
+   }
+}
+
+/**
+ * Free a datagram (struct ip_reassdata) and all its pbufs.
+ * Updates the total count of enqueued pbufs (ip_reass_pbufcount),
+ * SNMP counters and sends an ICMP time exceeded packet.
+ *
+ * @param ipr datagram to free
+ * @param prev the previous datagram in the linked list
+ * @return the number of pbufs freed
+ */
+static int
+ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
+{
+  u16_t pbufs_freed = 0;
+  u8_t clen;
+  struct pbuf *p;
+  struct ip_reass_helper *iprh;
+
+  LWIP_ASSERT("prev != ipr", prev != ipr);
+  if (prev != NULL) {
+    LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
+  }
+
+  snmp_inc_ipreasmfails();
+#if LWIP_ICMP
+  iprh = (struct ip_reass_helper *)ipr->p->payload;
+  if (iprh->start == 0) {
+    /* The first fragment was received, send ICMP time exceeded. */
+    /* First, de-queue the first pbuf from r->p. */
+    p = ipr->p;
+    ipr->p = iprh->next_pbuf;
+    /* Then, copy the original header into it. */
+    SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
+    icmp_time_exceeded(p, ICMP_TE_FRAG);
+    clen = pbuf_clen(p);
+    LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
+    pbufs_freed += clen;
+    pbuf_free(p);
+  }
+#endif /* LWIP_ICMP */
+
+  /* First, free all received pbufs.  The individual pbufs need to be released 
+     separately as they have not yet been chained */
+  p = ipr->p;
+  while (p != NULL) {
+    struct pbuf *pcur;
+    iprh = (struct ip_reass_helper *)p->payload;
+    pcur = p;
+    /* get the next pointer before freeing */
+    p = iprh->next_pbuf;
+    clen = pbuf_clen(pcur);
+    LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
+    pbufs_freed += clen;
+    pbuf_free(pcur);
+  }
+  /* Then, unchain the struct ip_reassdata from the list and free it. */
+  ip_reass_dequeue_datagram(ipr, prev);
+  LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
+  ip_reass_pbufcount -= pbufs_freed;
+
+  return pbufs_freed;
+}
+
+#if IP_REASS_FREE_OLDEST
+/**
+ * Free the oldest datagram to make room for enqueueing new fragments.
+ * The datagram 'fraghdr' belongs to is not freed!
+ *
+ * @param fraghdr IP header of the current fragment
+ * @param pbufs_needed number of pbufs needed to enqueue
+ *        (used for freeing other datagrams if not enough space)
+ * @return the number of pbufs freed
+ */
+static int
+ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
+{
+  /* @todo Can't we simply remove the last datagram in the
+   *       linked list behind reassdatagrams?
+   */
+  struct ip_reassdata *r, *oldest, *prev;
+  int pbufs_freed = 0, pbufs_freed_current;
+  int other_datagrams;
+
+  /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
+   * but don't free the datagram that 'fraghdr' belongs to! */
+  do {
+    oldest = NULL;
+    prev = NULL;
+    other_datagrams = 0;
+    r = reassdatagrams;
+    while (r != NULL) {
+      if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
+        /* Not the same datagram as fraghdr */
+        other_datagrams++;
+        if (oldest == NULL) {
+          oldest = r;
+        } else if (r->timer <= oldest->timer) {
+          /* older than the previous oldest */
+          oldest = r;
+        }
+      }
+      if (r->next != NULL) {
+        prev = r;
+      }
+      r = r->next;
+    }
+    if (oldest != NULL) {
+      pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);
+      pbufs_freed += pbufs_freed_current;
+    }
+  } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
+  return pbufs_freed;
+}
+#endif /* IP_REASS_FREE_OLDEST */
+
+/**
+ * Enqueues a new fragment into the fragment queue
+ * @param fraghdr points to the new fragments IP hdr
+ * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)
+ * @return A pointer to the queue location into which the fragment was enqueued
+ */
+static struct ip_reassdata*
+ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
+{
+  struct ip_reassdata* ipr;
+  /* No matching previous fragment found, allocate a new reassdata struct */
+  ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
+  if (ipr == NULL) {
+#if IP_REASS_FREE_OLDEST
+    if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
+      ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
+    }
+    if (ipr == NULL)
+#endif /* IP_REASS_FREE_OLDEST */
+    {
+      IPFRAG_STATS_INC(ip_frag.memerr);
+      LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));
+      return NULL;
+    }
+  }
+  memset(ipr, 0, sizeof(struct ip_reassdata));
+  ipr->timer = IP_REASS_MAXAGE;
+
+  /* enqueue the new structure to the front of the list */
+  ipr->next = reassdatagrams;
+  reassdatagrams = ipr;
+  /* copy the ip header for later tests and input */
+  /* @todo: no ip options supported? */
+  SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
+  return ipr;
+}
+
+/**
+ * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.
+ * @param ipr points to the queue entry to dequeue
+ */
+static void
+ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
+{
+  
+  /* dequeue the reass struct  */
+  if (reassdatagrams == ipr) {
+    /* it was the first in the list */
+    reassdatagrams = ipr->next;
+  } else {
+    /* it wasn't the first, so it must have a valid 'prev' */
+    LWIP_ASSERT("sanity check linked list", prev != NULL);
+    prev->next = ipr->next;
+  }
+
+  /* now we can free the ip_reass struct */
+  memp_free(MEMP_REASSDATA, ipr);
+}
+
+/**
+ * Chain a new pbuf into the pbuf list that composes the datagram.  The pbuf list
+ * will grow over time as  new pbufs are rx.
+ * Also checks that the datagram passes basic continuity checks (if the last
+ * fragment was received at least once).
+ * @param root_p points to the 'root' pbuf for the current datagram being assembled.
+ * @param new_p points to the pbuf for the current fragment
+ * @return 0 if invalid, >0 otherwise
+ */
+static int
+ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
+{
+  struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
+  struct pbuf *q;
+  u16_t offset,len;
+  struct ip_hdr *fraghdr;
+  int valid = 1;
+
+  /* Extract length and fragment offset from current fragment */
+  fraghdr = (struct ip_hdr*)new_p->payload; 
+  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
+  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
+
+  /* overwrite the fragment's ip header from the pbuf with our helper struct,
+   * and setup the embedded helper structure. */
+  /* make sure the struct ip_reass_helper fits into the IP header */
+  LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
+              sizeof(struct ip_reass_helper) <= IP_HLEN);
+  iprh = (struct ip_reass_helper*)new_p->payload;
+  iprh->next_pbuf = NULL;
+  iprh->start = offset;
+  iprh->end = offset + len;
+
+  /* Iterate through until we either get to the end of the list (append),
+   * or we find on with a larger offset (insert). */
+  for (q = ipr->p; q != NULL;) {
+    iprh_tmp = (struct ip_reass_helper*)q->payload;
+    if (iprh->start < iprh_tmp->start) {
+      /* the new pbuf should be inserted before this */
+      iprh->next_pbuf = q;
+      if (iprh_prev != NULL) {
+        /* not the fragment with the lowest offset */
+#if IP_REASS_CHECK_OVERLAP
+        if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
+          /* fragment overlaps with previous or following, throw away */
+          goto freepbuf;
+        }
+#endif /* IP_REASS_CHECK_OVERLAP */
+        iprh_prev->next_pbuf = new_p;
+      } else {
+        /* fragment with the lowest offset */
+        ipr->p = new_p;
+      }
+      break;
+    } else if(iprh->start == iprh_tmp->start) {
+      /* received the same datagram twice: no need to keep the datagram */
+      goto freepbuf;
+#if IP_REASS_CHECK_OVERLAP
+    } else if(iprh->start < iprh_tmp->end) {
+      /* overlap: no need to keep the new datagram */
+      goto freepbuf;
+#endif /* IP_REASS_CHECK_OVERLAP */
+    } else {
+      /* Check if the fragments received so far have no wholes. */
+      if (iprh_prev != NULL) {
+        if (iprh_prev->end != iprh_tmp->start) {
+          /* There is a fragment missing between the current
+           * and the previous fragment */
+          valid = 0;
+        }
+      }
+    }
+    q = iprh_tmp->next_pbuf;
+    iprh_prev = iprh_tmp;
+  }
+
+  /* If q is NULL, then we made it to the end of the list. Determine what to do now */
+  if (q == NULL) {
+    if (iprh_prev != NULL) {
+      /* this is (for now), the fragment with the highest offset:
+       * chain it to the last fragment */
+#if IP_REASS_CHECK_OVERLAP
+      LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
+#endif /* IP_REASS_CHECK_OVERLAP */
+      iprh_prev->next_pbuf = new_p;
+      if (iprh_prev->end != iprh->start) {
+        valid = 0;
+      }
+    } else {
+#if IP_REASS_CHECK_OVERLAP
+      LWIP_ASSERT("no previous fragment, this must be the first fragment!",
+        ipr->p == NULL);
+#endif /* IP_REASS_CHECK_OVERLAP */
+      /* this is the first fragment we ever received for this ip datagram */
+      ipr->p = new_p;
+    }
+  }
+
+  /* At this point, the validation part begins: */
+  /* If we already received the last fragment */
+  if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
+    /* and had no wholes so far */
+    if (valid) {
+      /* then check if the rest of the fragments is here */
+      /* Check if the queue starts with the first datagram */
+      if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
+        valid = 0;
+      } else {
+        /* and check that there are no wholes after this datagram */
+        iprh_prev = iprh;
+        q = iprh->next_pbuf;
+        while (q != NULL) {
+          iprh = (struct ip_reass_helper*)q->payload;
+          if (iprh_prev->end != iprh->start) {
+            valid = 0;
+            break;
+          }
+          iprh_prev = iprh;
+          q = iprh->next_pbuf;
+        }
+        /* if still valid, all fragments are received
+         * (because to the MF==0 already arrived */
+        if (valid) {
+          LWIP_ASSERT("sanity check", ipr->p != NULL);
+          LWIP_ASSERT("sanity check",
+            ((struct ip_reass_helper*)ipr->p->payload) != iprh);
+          LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
+            iprh->next_pbuf == NULL);
+          LWIP_ASSERT("validate_datagram:datagram end!=datagram len",
+            iprh->end == ipr->datagram_len);
+        }
+      }
+    }
+    /* If valid is 0 here, there are some fragments missing in the middle
+     * (since MF == 0 has already arrived). Such datagrams simply time out if
+     * no more fragments are received... */
+    return valid;
+  }
+  /* If we come here, not all fragments were received, yet! */
+  return 0; /* not yet valid! */
+#if IP_REASS_CHECK_OVERLAP
+freepbuf:
+  ip_reass_pbufcount -= pbuf_clen(new_p);
+  pbuf_free(new_p);
+  return 0;
+#endif /* IP_REASS_CHECK_OVERLAP */
+}
+
+/**
+ * Reassembles incoming IP fragments into an IP datagram.
+ *
+ * @param p points to a pbuf chain of the fragment
+ * @return NULL if reassembly is incomplete, ? otherwise
+ */
+struct pbuf *
+ip_reass(struct pbuf *p)
+{
+  struct pbuf *r;
+  struct ip_hdr *fraghdr;
+  struct ip_reassdata *ipr;
+  struct ip_reass_helper *iprh;
+  u16_t offset, len;
+  u8_t clen;
+  struct ip_reassdata *ipr_prev = NULL;
+
+  IPFRAG_STATS_INC(ip_frag.recv);
+  snmp_inc_ipreasmreqds();
+
+  fraghdr = (struct ip_hdr*)p->payload;
+
+  if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
+    LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
+    IPFRAG_STATS_INC(ip_frag.err);
+    goto nullreturn;
+  }
+
+  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
+  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
+
+  /* Check if we are allowed to enqueue more datagrams. */
+  clen = pbuf_clen(p);
+  if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
+#if IP_REASS_FREE_OLDEST
+    if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
+        ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
+#endif /* IP_REASS_FREE_OLDEST */
+    {
+      /* No datagram could be freed and still too many pbufs enqueued */
+      LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
+        ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
+      IPFRAG_STATS_INC(ip_frag.memerr);
+      /* @todo: send ICMP time exceeded here? */
+      /* drop this pbuf */
+      goto nullreturn;
+    }
+  }
+
+  /* Look for the datagram the fragment belongs to in the current datagram queue,
+   * remembering the previous in the queue for later dequeueing. */
+  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
+    /* Check if the incoming fragment matches the one currently present
+       in the reassembly buffer. If so, we proceed with copying the
+       fragment into the buffer. */
+    if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
+        ntohs(IPH_ID(fraghdr))));
+      IPFRAG_STATS_INC(ip_frag.cachehit);
+      break;
+    }
+    ipr_prev = ipr;
+  }
+
+  if (ipr == NULL) {
+  /* Enqueue a new datagram into the datagram queue */
+    ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
+    /* Bail if unable to enqueue */
+    if(ipr == NULL) {
+      goto nullreturn;
+    }
+  } else {
+    if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && 
+      ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
+      /* ipr->iphdr is not the header from the first fragment, but fraghdr is
+       * -> copy fraghdr into ipr->iphdr since we want to have the header
+       * of the first fragment (for ICMP time exceeded and later, for copying
+       * all options, if supported)*/
+      SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
+    }
+  }
+  /* Track the current number of pbufs current 'in-flight', in order to limit 
+  the number of fragments that may be enqueued at any one time */
+  ip_reass_pbufcount += clen;
+
+  /* At this point, we have either created a new entry or pointing 
+   * to an existing one */
+
+  /* check for 'no more fragments', and update queue entry*/
+  if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
+    ipr->flags |= IP_REASS_FLAG_LASTFRAG;
+    ipr->datagram_len = offset + len;
+    LWIP_DEBUGF(IP_REASS_DEBUG,
+     ("ip_reass: last fragment seen, total len %"S16_F"\n",
+      ipr->datagram_len));
+  }
+  /* find the right place to insert this pbuf */
+  /* @todo: trim pbufs if fragments are overlapping */
+  if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
+    /* the totally last fragment (flag more fragments = 0) was received at least
+     * once AND all fragments are received */
+    ipr->datagram_len += IP_HLEN;
+
+    /* save the second pbuf before copying the header over the pointer */
+    r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
+
+    /* copy the original ip header back to the first pbuf */
+    fraghdr = (struct ip_hdr*)(ipr->p->payload);
+    SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
+    IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
+    IPH_OFFSET_SET(fraghdr, 0);
+    IPH_CHKSUM_SET(fraghdr, 0);
+    /* @todo: do we need to set calculate the correct checksum? */
+    IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
+
+    p = ipr->p;
+
+    /* chain together the pbufs contained within the reass_data list. */
+    while(r != NULL) {
+      iprh = (struct ip_reass_helper*)r->payload;
+
+      /* hide the ip header for every succeding fragment */
+      pbuf_header(r, -IP_HLEN);
+      pbuf_cat(p, r);
+      r = iprh->next_pbuf;
+    }
+    /* release the sources allocate for the fragment queue entry */
+    ip_reass_dequeue_datagram(ipr, ipr_prev);
+
+    /* and adjust the number of pbufs currently queued for reassembly. */
+    ip_reass_pbufcount -= pbuf_clen(p);
+
+    /* Return the pbuf chain */
+    return p;
+  }
+  /* the datagram is not (yet?) reassembled completely */
+  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
+  return NULL;
+
+nullreturn:
+  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
+  IPFRAG_STATS_INC(ip_frag.drop);
+  pbuf_free(p);
+  return NULL;
+}
+#endif /* IP_REASSEMBLY */
+
+#if IP_FRAG
+#if IP_FRAG_USES_STATIC_BUF
+static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
+#else /* IP_FRAG_USES_STATIC_BUF */
+
+#if !LWIP_NETIF_TX_SINGLE_PBUF
+/** Allocate a new struct pbuf_custom_ref */
+static struct pbuf_custom_ref*
+ip_frag_alloc_pbuf_custom_ref(void)
+{
+  return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
+}
+
+/** Free a struct pbuf_custom_ref */
+static void
+ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
+{
+  LWIP_ASSERT("p != NULL", p != NULL);
+  memp_free(MEMP_FRAG_PBUF, p);
+}
+
+/** Free-callback function to free a 'struct pbuf_custom_ref', called by
+ * pbuf_free. */
+static void
+ipfrag_free_pbuf_custom(struct pbuf *p)
+{
+  struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
+  LWIP_ASSERT("pcr != NULL", pcr != NULL);
+  LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
+  if (pcr->original != NULL) {
+    pbuf_free(pcr->original);
+  }
+  ip_frag_free_pbuf_custom_ref(pcr);
+}
+#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
+#endif /* IP_FRAG_USES_STATIC_BUF */
+
+/**
+ * Fragment an IP datagram if too large for the netif.
+ *
+ * Chop the datagram in MTU sized chunks and send them in order
+ * by using a fixed size static memory buffer (PBUF_REF) or
+ * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
+ *
+ * @param p ip packet to send
+ * @param netif the netif on which to send
+ * @param dest destination ip address to which to send
+ *
+ * @return ERR_OK if sent successfully, err_t otherwise
+ */
+err_t 
+ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
+{
+  struct pbuf *rambuf;
+#if IP_FRAG_USES_STATIC_BUF
+  struct pbuf *header;
+#else
+#if !LWIP_NETIF_TX_SINGLE_PBUF
+  struct pbuf *newpbuf;
+#endif
+  struct ip_hdr *original_iphdr;
+#endif
+  struct ip_hdr *iphdr;
+  u16_t nfb;
+  u16_t left, cop;
+  u16_t mtu = netif->mtu;
+  u16_t ofo, omf;
+  u16_t last;
+  u16_t poff = IP_HLEN;
+  u16_t tmp;
+#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
+  u16_t newpbuflen = 0;
+  u16_t left_to_copy;
+#endif
+
+  /* Get a RAM based MTU sized pbuf */
+#if IP_FRAG_USES_STATIC_BUF
+  /* When using a static buffer, we use a PBUF_REF, which we will
+   * use to reference the packet (without link header).
+   * Layer and length is irrelevant.
+   */
+  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
+  if (rambuf == NULL) {
+    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
+    return ERR_MEM;
+  }
+  rambuf->tot_len = rambuf->len = mtu;
+  rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
+
+  /* Copy the IP header in it */
+  iphdr = (struct ip_hdr *)rambuf->payload;
+  SMEMCPY(iphdr, p->payload, IP_HLEN);
+#else /* IP_FRAG_USES_STATIC_BUF */
+  original_iphdr = (struct ip_hdr *)p->payload;
+  iphdr = original_iphdr;
+#endif /* IP_FRAG_USES_STATIC_BUF */
+
+  /* Save original offset */
+  tmp = ntohs(IPH_OFFSET(iphdr));
+  ofo = tmp & IP_OFFMASK;
+  omf = tmp & IP_MF;
+
+  left = p->tot_len - IP_HLEN;
+
+  nfb = (mtu - IP_HLEN) / 8;
+
+  while (left) {
+    last = (left <= mtu - IP_HLEN);
+
+    /* Set new offset and MF flag */
+    tmp = omf | (IP_OFFMASK & (ofo));
+    if (!last) {
+      tmp = tmp | IP_MF;
+    }
+
+    /* Fill this fragment */
+    cop = last ? left : nfb * 8;
+
+#if IP_FRAG_USES_STATIC_BUF
+    poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
+#else /* IP_FRAG_USES_STATIC_BUF */
+#if LWIP_NETIF_TX_SINGLE_PBUF
+    rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
+    if (rambuf == NULL) {
+      return ERR_MEM;
+    }
+    LWIP_ASSERT("this needs a pbuf in one piece!",
+      (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
+    poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
+    /* make room for the IP header */
+    if(pbuf_header(rambuf, IP_HLEN)) {
+      pbuf_free(rambuf);
+      return ERR_MEM;
+    }
+    /* fill in the IP header */
+    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
+    iphdr = rambuf->payload;
+#else /* LWIP_NETIF_TX_SINGLE_PBUF */
+    /* When not using a static buffer, create a chain of pbufs.
+     * The first will be a PBUF_RAM holding the link and IP header.
+     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
+     * but limited to the size of an mtu.
+     */
+    rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
+    if (rambuf == NULL) {
+      return ERR_MEM;
+    }
+    LWIP_ASSERT("this needs a pbuf in one piece!",
+                (p->len >= (IP_HLEN)));
+    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
+    iphdr = (struct ip_hdr *)rambuf->payload;
+
+    /* Can just adjust p directly for needed offset. */
+    p->payload = (u8_t *)p->payload + poff;
+    p->len -= poff;
+
+    left_to_copy = cop;
+    while (left_to_copy) {
+      struct pbuf_custom_ref *pcr;
+      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
+      /* Is this pbuf already empty? */
+      if (!newpbuflen) {
+        p = p->next;
+        continue;
+      }
+      pcr = ip_frag_alloc_pbuf_custom_ref();
+      if (pcr == NULL) {
+        pbuf_free(rambuf);
+        return ERR_MEM;
+      }
+      /* Mirror this pbuf, although we might not need all of it. */
+      newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
+      if (newpbuf == NULL) {
+        ip_frag_free_pbuf_custom_ref(pcr);
+        pbuf_free(rambuf);
+        return ERR_MEM;
+      }
+      pbuf_ref(p);
+      pcr->original = p;
+      pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
+
+      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
+       * so that it is removed when pbuf_dechain is later called on rambuf.
+       */
+      pbuf_cat(rambuf, newpbuf);
+      left_to_copy -= newpbuflen;
+      if (left_to_copy) {
+        p = p->next;
+      }
+    }
+    poff = newpbuflen;
+#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
+#endif /* IP_FRAG_USES_STATIC_BUF */
+
+    /* Correct header */
+    IPH_OFFSET_SET(iphdr, htons(tmp));
+    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
+    IPH_CHKSUM_SET(iphdr, 0);
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
+
+#if IP_FRAG_USES_STATIC_BUF
+    if (last) {
+      pbuf_realloc(rambuf, left + IP_HLEN);
+    }
+
+    /* This part is ugly: we alloc a RAM based pbuf for 
+     * the link level header for each chunk and then 
+     * free it.A PBUF_ROM style pbuf for which pbuf_header
+     * worked would make things simpler.
+     */
+    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
+    if (header != NULL) {
+      pbuf_chain(header, rambuf);
+      netif->output(netif, header, dest);
+      IPFRAG_STATS_INC(ip_frag.xmit);
+      snmp_inc_ipfragcreates();
+      pbuf_free(header);
+    } else {
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
+      pbuf_free(rambuf);
+      return ERR_MEM;
+    }
+#else /* IP_FRAG_USES_STATIC_BUF */
+    /* No need for separate header pbuf - we allowed room for it in rambuf
+     * when allocated.
+     */
+    netif->output(netif, rambuf, dest);
+    IPFRAG_STATS_INC(ip_frag.xmit);
+
+    /* Unfortunately we can't reuse rambuf - the hardware may still be
+     * using the buffer. Instead we free it (and the ensuing chain) and
+     * recreate it next time round the loop. If we're lucky the hardware
+     * will have already sent the packet, the free will really free, and
+     * there will be zero memory penalty.
+     */
+    
+    pbuf_free(rambuf);
+#endif /* IP_FRAG_USES_STATIC_BUF */
+    left -= cop;
+    ofo += nfb;
+  }
+#if IP_FRAG_USES_STATIC_BUF
+  pbuf_free(rambuf);
+#endif /* IP_FRAG_USES_STATIC_BUF */
+  snmp_inc_ipfragoks();
+  return ERR_OK;
+}
+#endif /* IP_FRAG */
diff -r 000000000000 -r 350011bf8be7 lwip/core/mem.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/mem.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,643 @@
+#pragma diag_remark 177
+/**
+ * @file
+ * Dynamic memory manager
+ *
+ * This is a lightweight replacement for the standard C library malloc().
+ *
+ * If you want to use the standard C library malloc() instead, define
+ * MEM_LIBC_MALLOC to 1 in your lwipopts.h
+ *
+ * To let mem_malloc() use pools (prevents fragmentation and is much faster than
+ * a heap but might waste some memory), define MEM_USE_POOLS to 1, define
+ * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
+ * of pools like this (more pools can be added between _START and _END):
+ *
+ * Define three pools with sizes 256, 512, and 1512 bytes
+ * LWIP_MALLOC_MEMPOOL_START
+ * LWIP_MALLOC_MEMPOOL(20, 256)
+ * LWIP_MALLOC_MEMPOOL(10, 512)
+ * LWIP_MALLOC_MEMPOOL(5, 1512)
+ * LWIP_MALLOC_MEMPOOL_END
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *         Simon Goldschmidt
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/sys.h"
+#include "lwip/stats.h"
+#include "lwip/err.h"
+
+#include <string.h>
+
+#if MEM_USE_POOLS
+/* lwIP head implemented with different sized pools */
+
+/**
+ * Allocate memory: determine the smallest pool that is big enough
+ * to contain an element of 'size' and get an element from that pool.
+ *
+ * @param size the size in bytes of the memory needed
+ * @return a pointer to the allocated memory or NULL if the pool is empty
+ */
+void *
+mem_malloc(mem_size_t size)
+{
+  struct memp_malloc_helper *element;
+  memp_t poolnr;
+  mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
+
+  for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
+#if MEM_USE_POOLS_TRY_BIGGER_POOL
+again:
+#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
+    /* is this pool big enough to hold an element of the required size
+       plus a struct memp_malloc_helper that saves the pool this element came from? */
+    if (required_size <= memp_sizes[poolnr]) {
+      break;
+    }
+  }
+  if (poolnr > MEMP_POOL_LAST) {
+    LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
+    return NULL;
+  }
+  element = (struct memp_malloc_helper*)memp_malloc(poolnr);
+  if (element == NULL) {
+    /* No need to DEBUGF or ASSERT: This error is already
+       taken care of in memp.c */
+#if MEM_USE_POOLS_TRY_BIGGER_POOL
+    /** Try a bigger pool if this one is empty! */
+    if (poolnr < MEMP_POOL_LAST) {
+      poolnr++;
+      goto again;
+    }
+#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
+    return NULL;
+  }
+
+  /* save the pool number this element came from */
+  element->poolnr = poolnr;
+  /* and return a pointer to the memory directly after the struct memp_malloc_helper */
+  element++;
+
+  return element;
+}
+
+/**
+ * Free memory previously allocated by mem_malloc. Loads the pool number
+ * and calls memp_free with that pool number to put the element back into
+ * its pool
+ *
+ * @param rmem the memory element to free
+ */
+void
+mem_free(void *rmem)
+{
+  struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
+
+  LWIP_ASSERT("rmem != NULL", (rmem != NULL));
+  LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
+
+  /* get the original struct memp_malloc_helper */
+  hmem--;
+
+  LWIP_ASSERT("hmem != NULL", (hmem != NULL));
+  LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
+  LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
+
+  /* and put it in the pool we saved earlier */
+  memp_free(hmem->poolnr, hmem);
+}
+
+#else /* MEM_USE_POOLS */
+/* lwIP replacement for your libc malloc() */
+
+/**
+ * The heap is made up as a list of structs of this type.
+ * This does not have to be aligned since for getting its size,
+ * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.
+ */
+struct mem {
+  /** index (-> ram[next]) of the next struct */
+  mem_size_t next;
+  /** index (-> ram[prev]) of the previous struct */
+  mem_size_t prev;
+  /** 1: this area is used; 0: this area is unused */
+  u8_t used;
+};
+
+/** All allocated blocks will be MIN_SIZE bytes big, at least!
+ * MIN_SIZE can be overridden to suit your needs. Smaller values save space,
+ * larger values could prevent too small blocks to fragment the RAM too much. */
+#ifndef MIN_SIZE
+#define MIN_SIZE             12
+#endif /* MIN_SIZE */
+/* some alignment macros: we define them here for better source code layout */
+#define MIN_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MIN_SIZE)
+#define SIZEOF_STRUCT_MEM    LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
+#define MEM_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
+
+/** If you want to relocate the heap to external memory, simply define
+ * LWIP_RAM_HEAP_POINTER as a void-pointer to that location.
+ * If so, make sure the memory at that location is big enough (see below on
+ * how that space is calculated). */
+#ifndef LWIP_RAM_HEAP_POINTER
+/** the heap. we need one struct mem at the end and some room for alignment */
+u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT] MEM_POSITION;
+#define LWIP_RAM_HEAP_POINTER ram_heap
+#endif /* LWIP_RAM_HEAP_POINTER */
+
+/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */
+static u8_t *ram;
+/** the last entry, always unused! */
+static struct mem *ram_end;
+/** pointer to the lowest free block, this is used for faster search */
+static struct mem *lfree;
+
+/** concurrent access protection */
+static sys_mutex_t mem_mutex;
+
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+
+static volatile u8_t mem_free_count;
+
+/* Allow mem_free from other (e.g. interrupt) context */
+#define LWIP_MEM_FREE_DECL_PROTECT()  SYS_ARCH_DECL_PROTECT(lev_free)
+#define LWIP_MEM_FREE_PROTECT()       SYS_ARCH_PROTECT(lev_free)
+#define LWIP_MEM_FREE_UNPROTECT()     SYS_ARCH_UNPROTECT(lev_free)
+#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
+#define LWIP_MEM_ALLOC_PROTECT()      SYS_ARCH_PROTECT(lev_alloc)
+#define LWIP_MEM_ALLOC_UNPROTECT()    SYS_ARCH_UNPROTECT(lev_alloc)
+
+#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+
+/* Protect the heap only by using a semaphore */
+#define LWIP_MEM_FREE_DECL_PROTECT()
+#define LWIP_MEM_FREE_PROTECT()    sys_mutex_lock(&mem_mutex)
+#define LWIP_MEM_FREE_UNPROTECT()  sys_mutex_unlock(&mem_mutex)
+/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */
+#define LWIP_MEM_ALLOC_DECL_PROTECT()
+#define LWIP_MEM_ALLOC_PROTECT()
+#define LWIP_MEM_ALLOC_UNPROTECT()
+
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+
+
+/**
+ * "Plug holes" by combining adjacent empty struct mems.
+ * After this function is through, there should not exist
+ * one empty struct mem pointing to another empty struct mem.
+ *
+ * @param mem this points to a struct mem which just has been freed
+ * @internal this function is only called by mem_free() and mem_trim()
+ *
+ * This assumes access to the heap is protected by the calling function
+ * already.
+ */
+static void
+plug_holes(struct mem *mem)
+{
+  struct mem *nmem;
+  struct mem *pmem;
+
+  LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
+  LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
+  LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
+
+  /* plug hole forward */
+  LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
+
+  nmem = (struct mem *)(void *)&ram[mem->next];
+  if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
+    /* if mem->next is unused and not end of ram, combine mem and mem->next */
+    if (lfree == nmem) {
+      lfree = mem;
+    }
+    mem->next = nmem->next;
+    ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);
+  }
+
+  /* plug hole backward */
+  pmem = (struct mem *)(void *)&ram[mem->prev];
+  if (pmem != mem && pmem->used == 0) {
+    /* if mem->prev is unused, combine mem and mem->prev */
+    if (lfree == mem) {
+      lfree = pmem;
+    }
+    pmem->next = mem->next;
+    ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);
+  }
+}
+
+/**
+ * Zero the heap and initialize start, end and lowest-free
+ */
+void
+mem_init(void)
+{
+  struct mem *mem;
+
+  LWIP_ASSERT("Sanity check alignment",
+    (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);
+
+  /* align the heap */
+  ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);
+  /* initialize the start of the heap */
+  mem = (struct mem *)(void *)ram;
+  mem->next = MEM_SIZE_ALIGNED;
+  mem->prev = 0;
+  mem->used = 0;
+  /* initialize the end of the heap */
+  ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED];
+  ram_end->used = 1;
+  ram_end->next = MEM_SIZE_ALIGNED;
+  ram_end->prev = MEM_SIZE_ALIGNED;
+
+  /* initialize the lowest-free pointer to the start of the heap */
+  lfree = (struct mem *)(void *)ram;
+
+  MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
+
+  if(sys_mutex_new(&mem_mutex) != ERR_OK) {
+    LWIP_ASSERT("failed to create mem_mutex", 0);
+  }
+}
+
+/**
+ * Put a struct mem back on the heap
+ *
+ * @param rmem is the data portion of a struct mem as returned by a previous
+ *             call to mem_malloc()
+ */
+void
+mem_free(void *rmem)
+{
+  struct mem *mem;
+  LWIP_MEM_FREE_DECL_PROTECT();
+
+  if (rmem == NULL) {
+    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
+    return;
+  }
+  LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
+
+  LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
+    (u8_t *)rmem < (u8_t *)ram_end);
+
+  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
+    SYS_ARCH_DECL_PROTECT(lev);
+    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
+    /* protect mem stats from concurrent access */
+    SYS_ARCH_PROTECT(lev);
+    MEM_STATS_INC(illegal);
+    SYS_ARCH_UNPROTECT(lev);
+    return;
+  }
+  /* protect the heap from concurrent access */
+  LWIP_MEM_FREE_PROTECT();
+  /* Get the corresponding struct mem ... */
+  mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
+  /* ... which has to be in a used state ... */
+  LWIP_ASSERT("mem_free: mem->used", mem->used);
+  /* ... and is now unused. */
+  mem->used = 0;
+
+  if (mem < lfree) {
+    /* the newly freed struct is now the lowest */
+    lfree = mem;
+  }
+
+  MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram)));
+
+  /* finally, see if prev or next are free also */
+  plug_holes(mem);
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+  mem_free_count = 1;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+  LWIP_MEM_FREE_UNPROTECT();
+}
+
+/**
+ * Shrink memory returned by mem_malloc().
+ *
+ * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked
+ * @param newsize required size after shrinking (needs to be smaller than or
+ *                equal to the previous size)
+ * @return for compatibility reasons: is always == rmem, at the moment
+ *         or NULL if newsize is > old size, in which case rmem is NOT touched
+ *         or freed!
+ */
+void *
+mem_trim(void *rmem, mem_size_t newsize)
+{
+  mem_size_t size;
+  mem_size_t ptr, ptr2;
+  struct mem *mem, *mem2;
+  /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
+  LWIP_MEM_FREE_DECL_PROTECT();
+
+  /* Expand the size of the allocated memory region so that we can
+     adjust for alignment. */
+  newsize = LWIP_MEM_ALIGN_SIZE(newsize);
+
+  if(newsize < MIN_SIZE_ALIGNED) {
+    /* every data block must be at least MIN_SIZE_ALIGNED long */
+    newsize = MIN_SIZE_ALIGNED;
+  }
+
+  if (newsize > MEM_SIZE_ALIGNED) {
+    return NULL;
+  }
+
+  LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
+   (u8_t *)rmem < (u8_t *)ram_end);
+
+  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
+    SYS_ARCH_DECL_PROTECT(lev);
+    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n"));
+    /* protect mem stats from concurrent access */
+    SYS_ARCH_PROTECT(lev);
+    MEM_STATS_INC(illegal);
+    SYS_ARCH_UNPROTECT(lev);
+    return rmem;
+  }
+  /* Get the corresponding struct mem ... */
+  mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
+  /* ... and its offset pointer */
+  ptr = (mem_size_t)((u8_t *)mem - ram);
+
+  size = mem->next - ptr - SIZEOF_STRUCT_MEM;
+  LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size);
+  if (newsize > size) {
+    /* not supported */
+    return NULL;
+  }
+  if (newsize == size) {
+    /* No change in size, simply return */
+    return rmem;
+  }
+
+  /* protect the heap from concurrent access */
+  LWIP_MEM_FREE_PROTECT();
+
+  mem2 = (struct mem *)(void *)&ram[mem->next];
+  if(mem2->used == 0) {
+    /* The next struct is unused, we can simply move it at little */
+    mem_size_t next;
+    /* remember the old next pointer */
+    next = mem2->next;
+    /* create new struct mem which is moved directly after the shrinked mem */
+    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
+    if (lfree == mem2) {
+      lfree = (struct mem *)(void *)&ram[ptr2];
+    }
+    mem2 = (struct mem *)(void *)&ram[ptr2];
+    mem2->used = 0;
+    /* restore the next pointer */
+    mem2->next = next;
+    /* link it back to mem */
+    mem2->prev = ptr;
+    /* link mem to it */
+    mem->next = ptr2;
+    /* last thing to restore linked list: as we have moved mem2,
+     * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not
+     * the end of the heap */
+    if (mem2->next != MEM_SIZE_ALIGNED) {
+      ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
+    }
+    MEM_STATS_DEC_USED(used, (size - newsize));
+    /* no need to plug holes, we've already done that */
+  } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
+    /* Next struct is used but there's room for another struct mem with
+     * at least MIN_SIZE_ALIGNED of data.
+     * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem
+     * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').
+     * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
+     *       region that couldn't hold data, but when mem->next gets freed,
+     *       the 2 regions would be combined, resulting in more free memory */
+    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
+    mem2 = (struct mem *)(void *)&ram[ptr2];
+    if (mem2 < lfree) {
+      lfree = mem2;
+    }
+    mem2->used = 0;
+    mem2->next = mem->next;
+    mem2->prev = ptr;
+    mem->next = ptr2;
+    if (mem2->next != MEM_SIZE_ALIGNED) {
+      ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
+    }
+    MEM_STATS_DEC_USED(used, (size - newsize));
+    /* the original mem->next is used, so no need to plug holes! */
+  }
+  /* else {
+    next struct mem is used but size between mem and mem2 is not big enough
+    to create another struct mem
+    -> don't do anyhting. 
+    -> the remaining space stays unused since it is too small
+  } */
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+  mem_free_count = 1;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+  LWIP_MEM_FREE_UNPROTECT();
+  return rmem;
+}
+
+/**
+ * Adam's mem_malloc() plus solution for bug #17922
+ * Allocate a block of memory with a minimum of 'size' bytes.
+ *
+ * @param size is the minimum size of the requested block in bytes.
+ * @return pointer to allocated memory or NULL if no free memory was found.
+ *
+ * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).
+ */
+void *
+mem_malloc(mem_size_t size)
+{
+  mem_size_t ptr, ptr2;
+  struct mem *mem, *mem2;
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+  u8_t local_mem_free_count = 0;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+  LWIP_MEM_ALLOC_DECL_PROTECT();
+
+  if (size == 0) {
+    return NULL;
+  }
+
+  /* Expand the size of the allocated memory region so that we can
+     adjust for alignment. */
+  size = LWIP_MEM_ALIGN_SIZE(size);
+
+  if(size < MIN_SIZE_ALIGNED) {
+    /* every data block must be at least MIN_SIZE_ALIGNED long */
+    size = MIN_SIZE_ALIGNED;
+  }
+
+  if (size > MEM_SIZE_ALIGNED) {
+    return NULL;
+  }
+
+  /* protect the heap from concurrent access */
+  sys_mutex_lock(&mem_mutex);
+  LWIP_MEM_ALLOC_PROTECT();
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+  /* run as long as a mem_free disturbed mem_malloc */
+  do {
+    local_mem_free_count = 0;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+
+    /* Scan through the heap searching for a free block that is big enough,
+     * beginning with the lowest free block.
+     */
+    for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size;
+         ptr = ((struct mem *)(void *)&ram[ptr])->next) {
+      mem = (struct mem *)(void *)&ram[ptr];
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+      mem_free_count = 0;
+      LWIP_MEM_ALLOC_UNPROTECT();
+      /* allow mem_free to run */
+      LWIP_MEM_ALLOC_PROTECT();
+      if (mem_free_count != 0) {
+        local_mem_free_count = mem_free_count;
+      }
+      mem_free_count = 0;
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+
+      if ((!mem->used) &&
+          (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
+        /* mem is not used and at least perfect fit is possible:
+         * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
+
+        if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
+          /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
+           * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
+           * -> split large block, create empty remainder,
+           * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
+           * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
+           * struct mem would fit in but no data between mem2 and mem2->next
+           * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
+           *       region that couldn't hold data, but when mem->next gets freed,
+           *       the 2 regions would be combined, resulting in more free memory
+           */
+          ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
+          /* create mem2 struct */
+          mem2 = (struct mem *)(void *)&ram[ptr2];
+          mem2->used = 0;
+          mem2->next = mem->next;
+          mem2->prev = ptr;
+          /* and insert it between mem and mem->next */
+          mem->next = ptr2;
+          mem->used = 1;
+
+          if (mem2->next != MEM_SIZE_ALIGNED) {
+            ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
+          }
+          MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
+        } else {
+          /* (a mem2 struct does no fit into the user data space of mem and mem->next will always
+           * be used at this point: if not we have 2 unused structs in a row, plug_holes should have
+           * take care of this).
+           * -> near fit or excact fit: do not split, no mem2 creation
+           * also can't move mem->next directly behind mem, since mem->next
+           * will always be used at this point!
+           */
+          mem->used = 1;
+          MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
+        }
+
+        if (mem == lfree) {
+          /* Find next free block after mem and update lowest free pointer */
+          while (lfree->used && lfree != ram_end) {
+            LWIP_MEM_ALLOC_UNPROTECT();
+            /* prevent high interrupt latency... */
+            LWIP_MEM_ALLOC_PROTECT();
+            lfree = (struct mem *)(void *)&ram[lfree->next];
+          }
+          LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
+        }
+        LWIP_MEM_ALLOC_UNPROTECT();
+        sys_mutex_unlock(&mem_mutex);
+        LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
+         (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
+        LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
+         ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
+        LWIP_ASSERT("mem_malloc: sanity check alignment",
+          (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
+
+        return (u8_t *)mem + SIZEOF_STRUCT_MEM;
+      }
+    }
+#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
+    /* if we got interrupted by a mem_free, try again */
+  } while(local_mem_free_count != 0);
+#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
+  LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
+  MEM_STATS_INC(err);
+  LWIP_MEM_ALLOC_UNPROTECT();
+  sys_mutex_unlock(&mem_mutex);
+  return NULL;
+}
+
+#endif /* MEM_USE_POOLS */
+/**
+ * Contiguously allocates enough space for count objects that are size bytes
+ * of memory each and returns a pointer to the allocated memory.
+ *
+ * The allocated memory is filled with bytes of value zero.
+ *
+ * @param count number of objects to allocate
+ * @param size size of the objects to allocate
+ * @return pointer to allocated memory / NULL pointer if there is an error
+ */
+void *mem_calloc(mem_size_t count, mem_size_t size)
+{
+  void *p;
+
+  /* allocate 'count' objects of size 'size' */
+  p = mem_malloc(count * size);
+  if (p) {
+    /* zero the memory */
+    memset(p, 0, count * size);
+  }
+  return p;
+}
+
+#endif /* !MEM_LIBC_MALLOC */
diff -r 000000000000 -r 350011bf8be7 lwip/core/memp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/memp.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,469 @@
+/**
+ * @file
+ * Dynamic pool memory manager
+ *
+ * lwIP has dedicated pools for many structures (netconn, protocol control blocks,
+ * packet buffers, ...). All these pools are managed here.
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/memp.h"
+#include "lwip/pbuf.h"
+#include "lwip/udp.h"
+#include "lwip/raw.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/igmp.h"
+#include "lwip/api.h"
+#include "lwip/api_msg.h"
+#include "lwip/tcpip.h"
+#include "lwip/sys.h"
+#include "lwip/timers.h"
+#include "lwip/stats.h"
+#include "netif/etharp.h"
+#include "lwip/ip_frag.h"
+#include "lwip/snmp_structs.h"
+#include "lwip/snmp_msg.h"
+#include "lwip/dns.h"
+#include "netif/ppp_oe.h"
+
+#include <string.h>
+
+#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
+
+struct memp {
+  struct memp *next;
+#if MEMP_OVERFLOW_CHECK
+  const char *file;
+  int line;
+#endif /* MEMP_OVERFLOW_CHECK */
+};
+
+#if MEMP_OVERFLOW_CHECK
+/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
+ * and at the end of each element, initialize them as 0xcd and check
+ * them later. */
+/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
+ * every single element in each pool is checked!
+ * This is VERY SLOW but also very helpful. */
+/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
+ * lwipopts.h to change the amount reserved for checking. */
+#ifndef MEMP_SANITY_REGION_BEFORE
+#define MEMP_SANITY_REGION_BEFORE  16
+#endif /* MEMP_SANITY_REGION_BEFORE*/
+#if MEMP_SANITY_REGION_BEFORE > 0
+#define MEMP_SANITY_REGION_BEFORE_ALIGNED    LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
+#else
+#define MEMP_SANITY_REGION_BEFORE_ALIGNED    0
+#endif /* MEMP_SANITY_REGION_BEFORE*/
+#ifndef MEMP_SANITY_REGION_AFTER
+#define MEMP_SANITY_REGION_AFTER   16
+#endif /* MEMP_SANITY_REGION_AFTER*/
+#if MEMP_SANITY_REGION_AFTER > 0
+#define MEMP_SANITY_REGION_AFTER_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
+#else
+#define MEMP_SANITY_REGION_AFTER_ALIGNED     0
+#endif /* MEMP_SANITY_REGION_AFTER*/
+
+/* MEMP_SIZE: save space for struct memp and for sanity check */
+#define MEMP_SIZE          (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
+#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
+
+#else /* MEMP_OVERFLOW_CHECK */
+
+/* No sanity checks
+ * We don't need to preserve the struct memp while not allocated, so we
+ * can save a little space and set MEMP_SIZE to 0.
+ */
+#define MEMP_SIZE           0
+#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
+
+#endif /* MEMP_OVERFLOW_CHECK */
+
+/** This array holds the first free element of each pool.
+ *  Elements form a linked list. */
+static struct memp *memp_tab[MEMP_MAX] MEM_POSITION;
+
+#else /* MEMP_MEM_MALLOC */
+
+#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
+
+#endif /* MEMP_MEM_MALLOC */
+
+/** This array holds the element sizes of each pool. */
+#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
+static
+#endif
+const u16_t memp_sizes[MEMP_MAX] = {
+#define LWIP_MEMPOOL(name,num,size,desc)  LWIP_MEM_ALIGN_SIZE(size),
+#include "lwip/memp_std.h"
+};
+
+#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
+
+/** This array holds the number of elements in each pool. */
+static const u16_t memp_num[MEMP_MAX] = {
+#define LWIP_MEMPOOL(name,num,size,desc)  (num),
+#include "lwip/memp_std.h"
+};
+
+/** This array holds a textual description of each pool. */
+#ifdef LWIP_DEBUG
+static const char *memp_desc[MEMP_MAX] = {
+#define LWIP_MEMPOOL(name,num,size,desc)  (desc),
+#include "lwip/memp_std.h"
+};
+#endif /* LWIP_DEBUG */
+
+#if MEMP_SEPARATE_POOLS
+
+/** This creates each memory pool. These are named memp_memory_XXX_base (where
+ * XXX is the name of the pool defined in memp_std.h).
+ * To relocate a pool, declare it as extern in cc.h. Example for GCC:
+ *   extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[];
+ */
+#define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \
+  [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))];   
+#include "lwip/memp_std.h"
+
+/** This array holds the base of each memory pool. */
+static u8_t *const memp_bases[] = { 
+#define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base,   
+#include "lwip/memp_std.h"
+} MEM_POSITION;
+
+#else /* MEMP_SEPARATE_POOLS */
+
+/** This is the actual memory used by the pools (all pools in one big block). */
+static u8_t memp_memory[MEM_ALIGNMENT - 1 
+#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
+#include "lwip/memp_std.h"
+] MEM_POSITION;
+
+#endif /* MEMP_SEPARATE_POOLS */
+
+#if MEMP_SANITY_CHECK
+/**
+ * Check that memp-lists don't form a circle
+ */
+static int
+memp_sanity(void)
+{
+  s16_t i, c;
+  struct memp *m, *n;
+
+  for (i = 0; i < MEMP_MAX; i++) {
+    for (m = memp_tab[i]; m != NULL; m = m->next) {
+      c = 1;
+      for (n = memp_tab[i]; n != NULL; n = n->next) {
+        if (n == m && --c < 0) {
+          return 0;
+        }
+      }
+    }
+  }
+  return 1;
+}
+#endif /* MEMP_SANITY_CHECK*/
+#if MEMP_OVERFLOW_CHECK
+#if defined(LWIP_DEBUG) && MEMP_STATS
+static const char * memp_overflow_names[] = {
+#define LWIP_MEMPOOL(name,num,size,desc) "/"desc,
+#include "lwip/memp_std.h"
+  };
+#endif
+
+/**
+ * Check if a memp element was victim of an overflow
+ * (e.g. the restricted area after it has been altered)
+ *
+ * @param p the memp element to check
+ * @param memp_type the pool p comes from
+ */
+static void
+memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
+{
+  u16_t k;
+  u8_t *m;
+#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
+  m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type];
+  for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
+    if (m[k] != 0xcd) {
+      char errstr[128] = "detected memp overflow in pool ";
+      char digit[] = "0";
+      if(memp_type >= 10) {
+        digit[0] = '0' + (memp_type/10);
+        strcat(errstr, digit);
+      }
+      digit[0] = '0' + (memp_type%10);
+      strcat(errstr, digit);
+#if defined(LWIP_DEBUG) && MEMP_STATS
+      strcat(errstr, memp_overflow_names[memp_type]);
+#endif
+      LWIP_ASSERT(errstr, 0);
+    }
+  }
+#endif
+}
+
+/**
+ * Check if a memp element was victim of an underflow
+ * (e.g. the restricted area before it has been altered)
+ *
+ * @param p the memp element to check
+ * @param memp_type the pool p comes from
+ */
+static void
+memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
+{
+  u16_t k;
+  u8_t *m;
+#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
+  m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
+  for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
+    if (m[k] != 0xcd) {
+      char errstr[128] = "detected memp underflow in pool ";
+      char digit[] = "0";
+      if(memp_type >= 10) {
+        digit[0] = '0' + (memp_type/10);
+        strcat(errstr, digit);
+      }
+      digit[0] = '0' + (memp_type%10);
+      strcat(errstr, digit);
+#if defined(LWIP_DEBUG) && MEMP_STATS
+      strcat(errstr, memp_overflow_names[memp_type]);
+#endif
+      LWIP_ASSERT(errstr, 0);
+    }
+  }
+#endif
+}
+
+/**
+ * Do an overflow check for all elements in every pool.
+ *
+ * @see memp_overflow_check_element for a description of the check
+ */
+static void
+memp_overflow_check_all(void)
+{
+  u16_t i, j;
+  struct memp *p;
+
+  p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
+  for (i = 0; i < MEMP_MAX; ++i) {
+    p = p;
+    for (j = 0; j < memp_num[i]; ++j) {
+      memp_overflow_check_element_overflow(p, i);
+      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
+    }
+  }
+  p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
+  for (i = 0; i < MEMP_MAX; ++i) {
+    p = p;
+    for (j = 0; j < memp_num[i]; ++j) {
+      memp_overflow_check_element_underflow(p, i);
+      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
+    }
+  }
+}
+
+/**
+ * Initialize the restricted areas of all memp elements in every pool.
+ */
+static void
+memp_overflow_init(void)
+{
+  u16_t i, j;
+  struct memp *p;
+  u8_t *m;
+
+  p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
+  for (i = 0; i < MEMP_MAX; ++i) {
+    p = p;
+    for (j = 0; j < memp_num[i]; ++j) {
+#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
+      m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
+      memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
+#endif
+#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
+      m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];
+      memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
+#endif
+      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
+    }
+  }
+}
+#endif /* MEMP_OVERFLOW_CHECK */
+
+/**
+ * Initialize this module.
+ * 
+ * Carves out memp_memory into linked lists for each pool-type.
+ */
+void
+memp_init(void)
+{
+  struct memp *memp;
+  u16_t i, j;
+
+  for (i = 0; i < MEMP_MAX; ++i) {
+    MEMP_STATS_AVAIL(used, i, 0);
+    MEMP_STATS_AVAIL(max, i, 0);
+    MEMP_STATS_AVAIL(err, i, 0);
+    MEMP_STATS_AVAIL(avail, i, memp_num[i]);
+  }
+
+#if !MEMP_SEPARATE_POOLS
+  memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
+#endif /* !MEMP_SEPARATE_POOLS */
+  /* for every pool: */
+  for (i = 0; i < MEMP_MAX; ++i) {
+    memp_tab[i] = NULL;
+#if MEMP_SEPARATE_POOLS
+    memp = (struct memp*)memp_bases[i];
+#endif /* MEMP_SEPARATE_POOLS */
+    /* create a linked list of memp elements */
+    for (j = 0; j < memp_num[i]; ++j) {
+      memp->next = memp_tab[i];
+      memp_tab[i] = memp;
+      memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
+#if MEMP_OVERFLOW_CHECK
+        + MEMP_SANITY_REGION_AFTER_ALIGNED
+#endif
+      );
+    }
+  }
+#if MEMP_OVERFLOW_CHECK
+  memp_overflow_init();
+  /* check everything a first time to see if it worked */
+  memp_overflow_check_all();
+#endif /* MEMP_OVERFLOW_CHECK */
+}
+
+/**
+ * Get an element from a specific pool.
+ *
+ * @param type the pool to get an element from
+ *
+ * the debug version has two more parameters:
+ * @param file file name calling this function
+ * @param line number of line where this function is called
+ *
+ * @return a pointer to the allocated memory or a NULL pointer on error
+ */
+void *
+#if !MEMP_OVERFLOW_CHECK
+memp_malloc(memp_t type)
+#else
+memp_malloc_fn(memp_t type, const char* file, const int line)
+#endif
+{
+  struct memp *memp;
+  SYS_ARCH_DECL_PROTECT(old_level);
+ 
+  LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
+
+  SYS_ARCH_PROTECT(old_level);
+#if MEMP_OVERFLOW_CHECK >= 2
+  memp_overflow_check_all();
+#endif /* MEMP_OVERFLOW_CHECK >= 2 */
+
+  memp = memp_tab[type];
+  
+  if (memp != NULL) {
+    memp_tab[type] = memp->next;
+#if MEMP_OVERFLOW_CHECK
+    memp->next = NULL;
+    memp->file = file;
+    memp->line = line;
+#endif /* MEMP_OVERFLOW_CHECK */
+    MEMP_STATS_INC_USED(used, type);
+    LWIP_ASSERT("memp_malloc: memp properly aligned",
+                ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
+    memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
+  } else {
+    LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
+    MEMP_STATS_INC(err, type);
+  }
+
+  SYS_ARCH_UNPROTECT(old_level);
+
+  return memp;
+}
+
+/**
+ * Put an element back into its pool.
+ *
+ * @param type the pool where to put mem
+ * @param mem the memp element to free
+ */
+void
+memp_free(memp_t type, void *mem)
+{
+  struct memp *memp;
+  SYS_ARCH_DECL_PROTECT(old_level);
+
+  if (mem == NULL) {
+    return;
+  }
+  LWIP_ASSERT("memp_free: mem properly aligned",
+                ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
+
+  memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
+
+  SYS_ARCH_PROTECT(old_level);
+#if MEMP_OVERFLOW_CHECK
+#if MEMP_OVERFLOW_CHECK >= 2
+  memp_overflow_check_all();
+#else
+  memp_overflow_check_element_overflow(memp, type);
+  memp_overflow_check_element_underflow(memp, type);
+#endif /* MEMP_OVERFLOW_CHECK >= 2 */
+#endif /* MEMP_OVERFLOW_CHECK */
+
+  MEMP_STATS_DEC(used, type); 
+  
+  memp->next = memp_tab[type]; 
+  memp_tab[type] = memp;
+
+#if MEMP_SANITY_CHECK
+  LWIP_ASSERT("memp sanity", memp_sanity());
+#endif /* MEMP_SANITY_CHECK */
+
+  SYS_ARCH_UNPROTECT(old_level);
+}
+
+#endif /* MEMP_MEM_MALLOC */
diff -r 000000000000 -r 350011bf8be7 lwip/core/netif.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/netif.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,752 @@
+/**
+ * @file
+ * lwIP network interface abstraction
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/def.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/snmp.h"
+#include "lwip/igmp.h"
+#include "netif/etharp.h"
+#include "lwip/stats.h"
+#if ENABLE_LOOPBACK
+#include "lwip/sys.h"
+#if LWIP_NETIF_LOOPBACK_MULTITHREADING
+#include "lwip/tcpip.h"
+#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
+#endif /* ENABLE_LOOPBACK */
+
+#if LWIP_AUTOIP
+#include "lwip/autoip.h"
+#endif /* LWIP_AUTOIP */
+#if LWIP_DHCP
+#include "lwip/dhcp.h"
+#endif /* LWIP_DHCP */
+
+#if LWIP_NETIF_STATUS_CALLBACK
+#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
+#else
+#define NETIF_STATUS_CALLBACK(n)
+#endif /* LWIP_NETIF_STATUS_CALLBACK */ 
+
+#if LWIP_NETIF_LINK_CALLBACK
+#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0)
+#else
+#define NETIF_LINK_CALLBACK(n)
+#endif /* LWIP_NETIF_LINK_CALLBACK */ 
+
+struct netif *netif_list;
+struct netif *netif_default;
+
+#if LWIP_HAVE_LOOPIF
+static struct netif loop_netif;
+
+/**
+ * Initialize a lwip network interface structure for a loopback interface
+ *
+ * @param netif the lwip network interface structure for this loopif
+ * @return ERR_OK if the loopif is initialized
+ *         ERR_MEM if private data couldn't be allocated
+ */
+static err_t
+netif_loopif_init(struct netif *netif)
+{
+  /* initialize the snmp variables and counters inside the struct netif
+   * ifSpeed: no assumption can be made!
+   */
+  NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0);
+
+  netif->name[0] = 'l';
+  netif->name[1] = 'o';
+  netif->output = netif_loop_output;
+  return ERR_OK;
+}
+#endif /* LWIP_HAVE_LOOPIF */
+
+void
+netif_init(void)
+{
+#if LWIP_HAVE_LOOPIF
+  ip_addr_t loop_ipaddr, loop_netmask, loop_gw;
+  IP4_ADDR(&loop_gw, 127,0,0,1);
+  IP4_ADDR(&loop_ipaddr, 127,0,0,1);
+  IP4_ADDR(&loop_netmask, 255,0,0,0);
+
+#if NO_SYS
+  netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);
+#else  /* NO_SYS */
+  netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);
+#endif /* NO_SYS */
+  netif_set_up(&loop_netif);
+
+#endif /* LWIP_HAVE_LOOPIF */
+}
+
+/**
+ * Add a network interface to the list of lwIP netifs.
+ *
+ * @param netif a pre-allocated netif structure
+ * @param ipaddr IP address for the new netif
+ * @param netmask network mask for the new netif
+ * @param gw default gateway IP address for the new netif
+ * @param state opaque data passed to the new netif
+ * @param init callback function that initializes the interface
+ * @param input callback function that is called to pass
+ * ingress packets up in the protocol layer stack.
+ *
+ * @return netif, or NULL if failed.
+ */
+struct netif *
+netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
+  ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
+{
+  static u8_t netifnum = 0;
+
+  LWIP_ASSERT("No init function given", init != NULL);
+
+  /* reset new interface configuration state */
+  ip_addr_set_zero(&netif->ip_addr);
+  ip_addr_set_zero(&netif->netmask);
+  ip_addr_set_zero(&netif->gw);
+  netif->flags = 0;
+#if LWIP_DHCP
+  /* netif not under DHCP control by default */
+  netif->dhcp = NULL;
+#endif /* LWIP_DHCP */
+#if LWIP_AUTOIP
+  /* netif not under AutoIP control by default */
+  netif->autoip = NULL;
+#endif /* LWIP_AUTOIP */
+#if LWIP_NETIF_STATUS_CALLBACK
+  netif->status_callback = NULL;
+#endif /* LWIP_NETIF_STATUS_CALLBACK */
+#if LWIP_NETIF_LINK_CALLBACK
+  netif->link_callback = NULL;
+#endif /* LWIP_NETIF_LINK_CALLBACK */
+#if LWIP_IGMP
+  netif->igmp_mac_filter = NULL;
+#endif /* LWIP_IGMP */
+#if ENABLE_LOOPBACK
+  netif->loop_first = NULL;
+  netif->loop_last = NULL;
+#endif /* ENABLE_LOOPBACK */
+
+  /* remember netif specific state information data */
+  netif->state = state;
+  netif->num = netifnum++;
+  netif->input = input;
+#if LWIP_NETIF_HWADDRHINT
+  netif->addr_hint = NULL;
+#endif /* LWIP_NETIF_HWADDRHINT*/
+#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
+  netif->loop_cnt_current = 0;
+#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
+
+  netif_set_addr(netif, ipaddr, netmask, gw);
+
+  /* call user specified initialization function for netif */
+  if (init(netif) != ERR_OK) {
+    return NULL;
+  }
+
+  /* add this netif to the list */
+  netif->next = netif_list;
+  netif_list = netif;
+  snmp_inc_iflist();
+
+#if LWIP_IGMP
+  /* start IGMP processing */
+  if (netif->flags & NETIF_FLAG_IGMP) {
+    igmp_start(netif);
+  }
+#endif /* LWIP_IGMP */
+
+  LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",
+    netif->name[0], netif->name[1]));
+  ip_addr_debug_print(NETIF_DEBUG, ipaddr);
+  LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
+  ip_addr_debug_print(NETIF_DEBUG, netmask);
+  LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
+  ip_addr_debug_print(NETIF_DEBUG, gw);
+  LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
+  return netif;
+}
+
+/**
+ * Change IP address configuration for a network interface (including netmask
+ * and default gateway).
+ *
+ * @param netif the network interface to change
+ * @param ipaddr the new IP address
+ * @param netmask the new netmask
+ * @param gw the new default gateway
+ */
+void
+netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
+    ip_addr_t *gw)
+{
+  netif_set_ipaddr(netif, ipaddr);
+  netif_set_netmask(netif, netmask);
+  netif_set_gw(netif, gw);
+}
+
+/**
+ * Remove a network interface from the list of lwIP netifs.
+ *
+ * @param netif the network interface to remove
+ */
+void
+netif_remove(struct netif *netif)
+{
+  if (netif == NULL) {
+    return;
+  }
+
+#if LWIP_IGMP
+  /* stop IGMP processing */
+  if (netif->flags & NETIF_FLAG_IGMP) {
+    igmp_stop(netif);
+  }
+#endif /* LWIP_IGMP */
+  if (netif_is_up(netif)) {
+    /* set netif down before removing (call callback function) */
+    netif_set_down(netif);
+  }
+
+  snmp_delete_ipaddridx_tree(netif);
+
+  /*  is it the first netif? */
+  if (netif_list == netif) {
+    netif_list = netif->next;
+  } else {
+    /*  look for netif further down the list */
+    struct netif * tmpNetif;
+    for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
+      if (tmpNetif->next == netif) {
+        tmpNetif->next = netif->next;
+        break;
+      }
+    }
+    if (tmpNetif == NULL)
+      return; /*  we didn't find any netif today */
+  }
+  snmp_dec_iflist();
+  /* this netif is default? */
+  if (netif_default == netif) {
+    /* reset default netif */
+    netif_set_default(NULL);
+  }
+  LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
+}
+
+/**
+ * Find a network interface by searching for its name
+ *
+ * @param name the name of the netif (like netif->name) plus concatenated number
+ * in ascii representation (e.g. 'en0')
+ */
+struct netif *
+netif_find(char *name)
+{
+  struct netif *netif;
+  u8_t num;
+
+  if (name == NULL) {
+    return NULL;
+  }
+
+  num = name[2] - '0';
+
+  for(netif = netif_list; netif != NULL; netif = netif->next) {
+    if (num == netif->num &&
+       name[0] == netif->name[0] &&
+       name[1] == netif->name[1]) {
+      LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));
+      return netif;
+    }
+  }
+  LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));
+  return NULL;
+}
+
+/**
+ * Change the IP address of a network interface
+ *
+ * @param netif the network interface to change
+ * @param ipaddr the new IP address
+ *
+ * @note call netif_set_addr() if you also want to change netmask and
+ * default gateway
+ */
+void
+netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
+{
+  /* TODO: Handling of obsolete pcbs */
+  /* See:  http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
+#if LWIP_TCP
+  struct tcp_pcb *pcb;
+  struct tcp_pcb_listen *lpcb;
+
+  /* address is actually being changed? */
+  if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
+    /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
+    LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
+    pcb = tcp_active_pcbs;
+    while (pcb != NULL) {
+      /* PCB bound to current local interface address? */
+      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
+#if LWIP_AUTOIP
+        /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
+        && !ip_addr_islinklocal(&(pcb->local_ip))
+#endif /* LWIP_AUTOIP */
+        ) {
+        /* this connection must be aborted */
+        struct tcp_pcb *next = pcb->next;
+        LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
+        tcp_abort(pcb);
+        pcb = next;
+      } else {
+        pcb = pcb->next;
+      }
+    }
+    for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
+      /* PCB bound to current local interface address? */
+      if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
+          (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
+        /* The PCB is listening to the old ipaddr and
+         * is set to listen to the new one instead */
+        ip_addr_set(&(lpcb->local_ip), ipaddr);
+      }
+    }
+  }
+#endif
+  snmp_delete_ipaddridx_tree(netif);
+  snmp_delete_iprteidx_tree(0,netif);
+  /* set new IP address to netif */
+  ip_addr_set(&(netif->ip_addr), ipaddr);
+  snmp_insert_ipaddridx_tree(netif);
+  snmp_insert_iprteidx_tree(0,netif);
+
+  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+    netif->name[0], netif->name[1],
+    ip4_addr1_16(&netif->ip_addr),
+    ip4_addr2_16(&netif->ip_addr),
+    ip4_addr3_16(&netif->ip_addr),
+    ip4_addr4_16(&netif->ip_addr)));
+}
+
+/**
+ * Change the default gateway for a network interface
+ *
+ * @param netif the network interface to change
+ * @param gw the new default gateway
+ *
+ * @note call netif_set_addr() if you also want to change ip address and netmask
+ */
+void
+netif_set_gw(struct netif *netif, ip_addr_t *gw)
+{
+  ip_addr_set(&(netif->gw), gw);
+  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+    netif->name[0], netif->name[1],
+    ip4_addr1_16(&netif->gw),
+    ip4_addr2_16(&netif->gw),
+    ip4_addr3_16(&netif->gw),
+    ip4_addr4_16(&netif->gw)));
+}
+
+/**
+ * Change the netmask of a network interface
+ *
+ * @param netif the network interface to change
+ * @param netmask the new netmask
+ *
+ * @note call netif_set_addr() if you also want to change ip address and
+ * default gateway
+ */
+void
+netif_set_netmask(struct netif *netif, ip_addr_t *netmask)
+{
+  snmp_delete_iprteidx_tree(0, netif);
+  /* set new netmask to netif */
+  ip_addr_set(&(netif->netmask), netmask);
+  snmp_insert_iprteidx_tree(0, netif);
+  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+    netif->name[0], netif->name[1],
+    ip4_addr1_16(&netif->netmask),
+    ip4_addr2_16(&netif->netmask),
+    ip4_addr3_16(&netif->netmask),
+    ip4_addr4_16(&netif->netmask)));
+}
+
+/**
+ * Set a network interface as the default network interface
+ * (used to output all packets for which no specific route is found)
+ *
+ * @param netif the default network interface
+ */
+void
+netif_set_default(struct netif *netif)
+{
+  if (netif == NULL) {
+    /* remove default route */
+    snmp_delete_iprteidx_tree(1, netif);
+  } else {
+    /* install default route */
+    snmp_insert_iprteidx_tree(1, netif);
+  }
+  netif_default = netif;
+  LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
+           netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
+}
+
+/**
+ * Bring an interface up, available for processing
+ * traffic.
+ * 
+ * @note: Enabling DHCP on a down interface will make it come
+ * up once configured.
+ * 
+ * @see dhcp_start()
+ */ 
+void netif_set_up(struct netif *netif)
+{
+  if (!(netif->flags & NETIF_FLAG_UP)) {
+    netif->flags |= NETIF_FLAG_UP;
+    
+#if LWIP_SNMP
+    snmp_get_sysuptime(&netif->ts);
+#endif /* LWIP_SNMP */
+
+    NETIF_STATUS_CALLBACK(netif);
+
+    if (netif->flags & NETIF_FLAG_LINK_UP) {
+#if LWIP_ARP
+      /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 
+      if (netif->flags & (NETIF_FLAG_ETHARP)) {
+        etharp_gratuitous(netif);
+      }
+#endif /* LWIP_ARP */
+
+#if LWIP_IGMP
+      /* resend IGMP memberships */
+      if (netif->flags & NETIF_FLAG_IGMP) {
+        igmp_report_groups( netif);
+      }
+#endif /* LWIP_IGMP */
+    }
+  }
+}
+
+/**
+ * Bring an interface down, disabling any traffic processing.
+ *
+ * @note: Enabling DHCP on a down interface will make it come
+ * up once configured.
+ * 
+ * @see dhcp_start()
+ */ 
+void netif_set_down(struct netif *netif)
+{
+  if (netif->flags & NETIF_FLAG_UP) {
+    netif->flags &= ~NETIF_FLAG_UP;
+#if LWIP_SNMP
+    snmp_get_sysuptime(&netif->ts);
+#endif
+
+    NETIF_STATUS_CALLBACK(netif);
+  }
+}
+
+#if LWIP_NETIF_STATUS_CALLBACK
+/**
+ * Set callback to be called when interface is brought up/down
+ */
+void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)
+{
+  if (netif) {
+    netif->status_callback = status_callback;
+  }
+}
+#endif /* LWIP_NETIF_STATUS_CALLBACK */
+
+/**
+ * Called by a driver when its link goes up
+ */
+void netif_set_link_up(struct netif *netif )
+{
+  if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
+    netif->flags |= NETIF_FLAG_LINK_UP;
+
+#if LWIP_DHCP
+    if (netif->dhcp) {
+      dhcp_network_changed(netif);
+    }
+#endif /* LWIP_DHCP */
+
+#if LWIP_AUTOIP
+    if (netif->autoip) {
+      autoip_network_changed(netif);
+    }
+#endif /* LWIP_AUTOIP */
+
+    if (netif->flags & NETIF_FLAG_UP) {
+#if LWIP_ARP
+      /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 
+      if (netif->flags & NETIF_FLAG_ETHARP) {
+        etharp_gratuitous(netif);
+      }
+#endif /* LWIP_ARP */
+
+#if LWIP_IGMP
+      /* resend IGMP memberships */
+      if (netif->flags & NETIF_FLAG_IGMP) {
+        igmp_report_groups( netif);
+      }
+#endif /* LWIP_IGMP */
+    }
+    NETIF_LINK_CALLBACK(netif);
+  }
+}
+
+/**
+ * Called by a driver when its link goes down
+ */
+void netif_set_link_down(struct netif *netif )
+{
+  if (netif->flags & NETIF_FLAG_LINK_UP) {
+    netif->flags &= ~NETIF_FLAG_LINK_UP;
+    NETIF_LINK_CALLBACK(netif);
+  }
+}
+
+#if LWIP_NETIF_LINK_CALLBACK
+/**
+ * Set callback to be called when link is brought up/down
+ */
+void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)
+{
+  if (netif) {
+    netif->link_callback = link_callback;
+  }
+}
+#endif /* LWIP_NETIF_LINK_CALLBACK */
+
+#if ENABLE_LOOPBACK
+/**
+ * Send an IP packet to be received on the same netif (loopif-like).
+ * The pbuf is simply copied and handed back to netif->input.
+ * In multithreaded mode, this is done directly since netif->input must put
+ * the packet on a queue.
+ * In callback mode, the packet is put on an internal queue and is fed to
+ * netif->input by netif_poll().
+ *
+ * @param netif the lwip network interface structure
+ * @param p the (IP) packet to 'send'
+ * @param ipaddr the ip address to send the packet to (not used)
+ * @return ERR_OK if the packet has been sent
+ *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated
+ */
+err_t
+netif_loop_output(struct netif *netif, struct pbuf *p,
+       ip_addr_t *ipaddr)
+{
+  struct pbuf *r;
+  err_t err;
+  struct pbuf *last;
+#if LWIP_LOOPBACK_MAX_PBUFS
+  u8_t clen = 0;
+#endif /* LWIP_LOOPBACK_MAX_PBUFS */
+  /* If we have a loopif, SNMP counters are adjusted for it,
+   * if not they are adjusted for 'netif'. */
+#if LWIP_SNMP
+#if LWIP_HAVE_LOOPIF
+  struct netif *stats_if = &loop_netif;
+#else /* LWIP_HAVE_LOOPIF */
+  struct netif *stats_if = netif;
+#endif /* LWIP_HAVE_LOOPIF */
+#endif /* LWIP_SNMP */
+  SYS_ARCH_DECL_PROTECT(lev);
+  LWIP_UNUSED_ARG(ipaddr);
+
+  /* Allocate a new pbuf */
+  r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
+  if (r == NULL) {
+    LINK_STATS_INC(link.memerr);
+    LINK_STATS_INC(link.drop);
+    snmp_inc_ifoutdiscards(stats_if);
+    return ERR_MEM;
+  }
+#if LWIP_LOOPBACK_MAX_PBUFS
+  clen = pbuf_clen(r);
+  /* check for overflow or too many pbuf on queue */
+  if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
+     ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
+    pbuf_free(r);
+    LINK_STATS_INC(link.memerr);
+    LINK_STATS_INC(link.drop);
+    snmp_inc_ifoutdiscards(stats_if);
+    return ERR_MEM;
+  }
+  netif->loop_cnt_current += clen;
+#endif /* LWIP_LOOPBACK_MAX_PBUFS */
+
+  /* Copy the whole pbuf queue p into the single pbuf r */
+  if ((err = pbuf_copy(r, p)) != ERR_OK) {
+    pbuf_free(r);
+    LINK_STATS_INC(link.memerr);
+    LINK_STATS_INC(link.drop);
+    snmp_inc_ifoutdiscards(stats_if);
+    return err;
+  }
+
+  /* Put the packet on a linked list which gets emptied through calling
+     netif_poll(). */
+
+  /* let last point to the last pbuf in chain r */
+  for (last = r; last->next != NULL; last = last->next);
+
+  SYS_ARCH_PROTECT(lev);
+  if(netif->loop_first != NULL) {
+    LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
+    netif->loop_last->next = r;
+    netif->loop_last = last;
+  } else {
+    netif->loop_first = r;
+    netif->loop_last = last;
+  }
+  SYS_ARCH_UNPROTECT(lev);
+
+  LINK_STATS_INC(link.xmit);
+  snmp_add_ifoutoctets(stats_if, p->tot_len);
+  snmp_inc_ifoutucastpkts(stats_if);
+
+#if LWIP_NETIF_LOOPBACK_MULTITHREADING
+  /* For multithreading environment, schedule a call to netif_poll */
+  tcpip_callback((tcpip_callback_fn)netif_poll, netif);
+#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
+
+  return ERR_OK;
+}
+
+/**
+ * Call netif_poll() in the main loop of your application. This is to prevent
+ * reentering non-reentrant functions like tcp_input(). Packets passed to
+ * netif_loop_output() are put on a list that is passed to netif->input() by
+ * netif_poll().
+ */
+void
+netif_poll(struct netif *netif)
+{
+  struct pbuf *in;
+  /* If we have a loopif, SNMP counters are adjusted for it,
+   * if not they are adjusted for 'netif'. */
+#if LWIP_SNMP
+#if LWIP_HAVE_LOOPIF
+  struct netif *stats_if = &loop_netif;
+#else /* LWIP_HAVE_LOOPIF */
+  struct netif *stats_if = netif;
+#endif /* LWIP_HAVE_LOOPIF */
+#endif /* LWIP_SNMP */
+  SYS_ARCH_DECL_PROTECT(lev);
+
+  do {
+    /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
+    SYS_ARCH_PROTECT(lev);
+    in = netif->loop_first;
+    if (in != NULL) {
+      struct pbuf *in_end = in;
+#if LWIP_LOOPBACK_MAX_PBUFS
+      u8_t clen = pbuf_clen(in);
+      /* adjust the number of pbufs on queue */
+      LWIP_ASSERT("netif->loop_cnt_current underflow",
+        ((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
+      netif->loop_cnt_current -= clen;
+#endif /* LWIP_LOOPBACK_MAX_PBUFS */
+      while (in_end->len != in_end->tot_len) {
+        LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
+        in_end = in_end->next;
+      }
+      /* 'in_end' now points to the last pbuf from 'in' */
+      if (in_end == netif->loop_last) {
+        /* this was the last pbuf in the list */
+        netif->loop_first = netif->loop_last = NULL;
+      } else {
+        /* pop the pbuf off the list */
+        netif->loop_first = in_end->next;
+        LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
+      }
+      /* De-queue the pbuf from its successors on the 'loop_' list. */
+      in_end->next = NULL;
+    }
+    SYS_ARCH_UNPROTECT(lev);
+
+    if (in != NULL) {
+      LINK_STATS_INC(link.recv);
+      snmp_add_ifinoctets(stats_if, in->tot_len);
+      snmp_inc_ifinucastpkts(stats_if);
+      /* loopback packets are always IP packets! */
+      if (ip_input(in, netif) != ERR_OK) {
+        pbuf_free(in);
+      }
+      /* Don't reference the packet any more! */
+      in = NULL;
+    }
+  /* go on while there is a packet on the list */
+  } while (netif->loop_first != NULL);
+}
+
+#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
+/**
+ * Calls netif_poll() for every netif on the netif_list.
+ */
+void
+netif_poll_all(void)
+{
+  struct netif *netif = netif_list;
+  /* loop through netifs */
+  while (netif != NULL) {
+    netif_poll(netif);
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+}
+#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
+#endif /* ENABLE_LOOPBACK */
diff -r 000000000000 -r 350011bf8be7 lwip/core/pbuf.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/pbuf.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,1156 @@
+/**
+ * @file
+ * Packet buffer management
+ *
+ * Packets are built from the pbuf data structure. It supports dynamic
+ * memory allocation for packet contents or can reference externally
+ * managed packet contents both in RAM and ROM. Quick allocation for
+ * incoming packets is provided through pools with fixed sized pbufs.
+ *
+ * A packet may span over multiple pbufs, chained as a singly linked
+ * list. This is called a "pbuf chain".
+ *
+ * Multiple packets may be queued, also using this singly linked list.
+ * This is called a "packet queue".
+ * 
+ * So, a packet queue consists of one or more pbuf chains, each of
+ * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE
+ * NOT SUPPORTED!!! Use helper structs to queue multiple packets.
+ * 
+ * The differences between a pbuf chain and a packet queue are very
+ * precise but subtle. 
+ *
+ * The last pbuf of a packet has a ->tot_len field that equals the
+ * ->len field. It can be found by traversing the list. If the last
+ * pbuf of a packet has a ->next field other than NULL, more packets
+ * are on the queue.
+ *
+ * Therefore, looping through a pbuf of a single packet, has an
+ * loop end condition (tot_len == p->len), NOT (next == NULL).
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/stats.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+#include "arch/perf.h"
+#if TCP_QUEUE_OOSEQ
+#include "lwip/tcp_impl.h"
+#endif
+#if LWIP_CHECKSUM_ON_COPY
+#include "lwip/inet_chksum.h"
+#endif
+
+#include <string.h>
+
+#define SIZEOF_STRUCT_PBUF        LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
+/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically
+   aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
+#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
+
+#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
+#define PBUF_POOL_IS_EMPTY()
+#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
+/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
+#ifndef PBUF_POOL_FREE_OOSEQ
+#define PBUF_POOL_FREE_OOSEQ 1
+#endif /* PBUF_POOL_FREE_OOSEQ */
+
+#if PBUF_POOL_FREE_OOSEQ
+#include "lwip/tcpip.h"
+#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
+static u8_t pbuf_free_ooseq_queued;
+/**
+ * Attempt to reclaim some memory from queued out-of-sequence TCP segments
+ * if we run out of pool pbufs. It's better to give priority to new packets
+ * if we're running out.
+ *
+ * This must be done in the correct thread context therefore this function
+ * can only be used with NO_SYS=0 and through tcpip_callback.
+ */
+static void
+pbuf_free_ooseq(void* arg)
+{
+  struct tcp_pcb* pcb;
+  SYS_ARCH_DECL_PROTECT(old_level);
+  LWIP_UNUSED_ARG(arg);
+
+  SYS_ARCH_PROTECT(old_level);
+  pbuf_free_ooseq_queued = 0;
+  SYS_ARCH_UNPROTECT(old_level);
+
+  for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
+    if (NULL != pcb->ooseq) {
+      /** Free the ooseq pbufs of one PCB only */
+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
+      tcp_segs_free(pcb->ooseq);
+      pcb->ooseq = NULL;
+      return;
+    }
+  }
+}
+
+/** Queue a call to pbuf_free_ooseq if not already queued. */
+static void
+pbuf_pool_is_empty(void)
+{
+  u8_t queued;
+  SYS_ARCH_DECL_PROTECT(old_level);
+
+  SYS_ARCH_PROTECT(old_level);
+  queued = pbuf_free_ooseq_queued;
+  pbuf_free_ooseq_queued = 1;
+  SYS_ARCH_UNPROTECT(old_level);
+
+  if(!queued) {
+    /* queue a call to pbuf_free_ooseq if not already queued */
+    if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
+      SYS_ARCH_PROTECT(old_level);
+      pbuf_free_ooseq_queued = 0;
+      SYS_ARCH_UNPROTECT(old_level);
+    }
+  }
+}
+#endif /* PBUF_POOL_FREE_OOSEQ */
+#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
+
+/**
+ * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
+ *
+ * The actual memory allocated for the pbuf is determined by the
+ * layer at which the pbuf is allocated and the requested size
+ * (from the size parameter).
+ *
+ * @param layer flag to define header size
+ * @param length size of the pbuf's payload
+ * @param type this parameter decides how and where the pbuf
+ * should be allocated as follows:
+ *
+ * - PBUF_RAM: buffer memory for pbuf is allocated as one large
+ *             chunk. This includes protocol headers as well.
+ * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
+ *             protocol headers. Additional headers must be prepended
+ *             by allocating another pbuf and chain in to the front of
+ *             the ROM pbuf. It is assumed that the memory used is really
+ *             similar to ROM in that it is immutable and will not be
+ *             changed. Memory which is dynamic should generally not
+ *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
+ * - PBUF_REF: no buffer memory is allocated for the pbuf, even for
+ *             protocol headers. It is assumed that the pbuf is only
+ *             being used in a single thread. If the pbuf gets queued,
+ *             then pbuf_take should be called to copy the buffer.
+ * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
+ *              the pbuf pool that is allocated during pbuf_init().
+ *
+ * @return the allocated pbuf. If multiple pbufs where allocated, this
+ * is the first pbuf of a pbuf chain.
+ */
+struct pbuf *
+pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
+{
+  struct pbuf *p, *q, *r;
+  u16_t offset;
+  s32_t rem_len; /* remaining length */
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
+
+  /* determine header offset */
+  offset = 0;
+  switch (layer) {
+  case PBUF_TRANSPORT:
+    /* add room for transport (often TCP) layer header */
+    offset += PBUF_TRANSPORT_HLEN;
+    /* FALLTHROUGH */
+  case PBUF_IP:
+    /* add room for IP layer header */
+    offset += PBUF_IP_HLEN;
+    /* FALLTHROUGH */
+  case PBUF_LINK:
+    /* add room for link layer header */
+    offset += PBUF_LINK_HLEN;
+    break;
+  case PBUF_RAW:
+    break;
+  default:
+    LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
+    return NULL;
+  }
+
+  switch (type) {
+  case PBUF_POOL:
+    /* allocate head of pbuf chain into p */
+    p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
+    if (p == NULL) {
+      PBUF_POOL_IS_EMPTY();
+      return NULL;
+    }
+    p->type = type;
+    p->next = NULL;
+
+    /* make the payload pointer point 'offset' bytes into pbuf data memory */
+    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
+    LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
+            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
+    /* the total length of the pbuf chain is the requested size */
+    p->tot_len = length;
+    /* set the length of the first pbuf in the chain */
+    p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));
+    LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
+                ((u8_t*)p->payload + p->len <=
+                 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
+    LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
+      (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
+    /* set reference count (needed here in case we fail) */
+    p->ref = 1;
+
+    /* now allocate the tail of the pbuf chain */
+
+    /* remember first pbuf for linkage in next iteration */
+    r = p;
+    /* remaining length to be allocated */
+    rem_len = length - p->len;
+    /* any remaining pbufs to be allocated? */
+    while (rem_len > 0) {
+      q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
+      if (q == NULL) {
+        PBUF_POOL_IS_EMPTY();
+        /* free chain so far allocated */
+        pbuf_free(p);
+        /* bail out unsuccesfully */
+        return NULL;
+      }
+      q->type = type;
+      q->flags = 0;
+      q->next = NULL;
+      /* make previous pbuf point to this pbuf */
+      r->next = q;
+      /* set total length of this pbuf and next in chain */
+      LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
+      q->tot_len = (u16_t)rem_len;
+      /* this pbuf length is pool size, unless smaller sized tail */
+      q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
+      q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
+      LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
+              ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
+      LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
+                  ((u8_t*)p->payload + p->len <=
+                   (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
+      q->ref = 1;
+      /* calculate remaining length to be allocated */
+      rem_len -= q->len;
+      /* remember this pbuf for linkage in next iteration */
+      r = q;
+    }
+    /* end of chain */
+    /*r->next = NULL;*/
+
+    break;
+  case PBUF_RAM:
+    /* If pbuf is to be allocated in RAM, allocate memory for it. */
+    p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
+    if (p == NULL) {
+      return NULL;
+    }
+    /* Set up internal structure of the pbuf. */
+    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
+    p->len = p->tot_len = length;
+    p->next = NULL;
+    p->type = type;
+
+    LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
+           ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
+    break;
+  /* pbuf references existing (non-volatile static constant) ROM payload? */
+  case PBUF_ROM:
+  /* pbuf references existing (externally allocated) RAM payload? */
+  case PBUF_REF:
+    /* only allocate memory for the pbuf structure */
+    p = (struct pbuf *)memp_malloc(MEMP_PBUF);
+    if (p == NULL) {
+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+                  ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
+                  (type == PBUF_ROM) ? "ROM" : "REF"));
+      return NULL;
+    }
+    /* caller must set this field properly, afterwards */
+    p->payload = NULL;
+    p->len = p->tot_len = length;
+    p->next = NULL;
+    p->type = type;
+    break;
+  default:
+    LWIP_ASSERT("pbuf_alloc: erroneous type", 0);
+    return NULL;
+  }
+  /* set reference count */
+  p->ref = 1;
+  /* set flags */
+  p->flags = 0;
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
+  return p;
+}
+
+#if LWIP_SUPPORT_CUSTOM_PBUF
+/** Initialize a custom pbuf (already allocated).
+ *
+ * @param layer flag to define header size
+ * @param length size of the pbuf's payload
+ * @param type type of the pbuf (only used to treat the pbuf accordingly, as
+ *        this function allocates no memory)
+ * @param p pointer to the custom pbuf to initialize (already allocated)
+ * @param payload_mem pointer to the buffer that is used for payload and headers,
+ *        must be at least big enough to hold 'length' plus the header size,
+ *        may be NULL if set later
+ * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
+ *        big enough to hold 'length' plus the header size
+ */
+struct pbuf*
+pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p,
+                    void *payload_mem, u16_t payload_mem_len)
+{
+  u16_t offset;
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
+
+  /* determine header offset */
+  offset = 0;
+  switch (l) {
+  case PBUF_TRANSPORT:
+    /* add room for transport (often TCP) layer header */
+    offset += PBUF_TRANSPORT_HLEN;
+    /* FALLTHROUGH */
+  case PBUF_IP:
+    /* add room for IP layer header */
+    offset += PBUF_IP_HLEN;
+    /* FALLTHROUGH */
+  case PBUF_LINK:
+    /* add room for link layer header */
+    offset += PBUF_LINK_HLEN;
+    break;
+  case PBUF_RAW:
+    break;
+  default:
+    LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
+    return NULL;
+  }
+
+  if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
+    return NULL;
+  }
+
+  p->pbuf.next = NULL;
+  if (payload_mem != NULL) {
+    p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset));
+  } else {
+    p->pbuf.payload = NULL;
+  }
+  p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
+  p->pbuf.len = p->pbuf.tot_len = length;
+  p->pbuf.type = type;
+  p->pbuf.ref = 1;
+  return &p->pbuf;
+}
+#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
+
+/**
+ * Shrink a pbuf chain to a desired length.
+ *
+ * @param p pbuf to shrink.
+ * @param new_len desired new length of pbuf chain
+ *
+ * Depending on the desired length, the first few pbufs in a chain might
+ * be skipped and left unchanged. The new last pbuf in the chain will be
+ * resized, and any remaining pbufs will be freed.
+ *
+ * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
+ * @note May not be called on a packet queue.
+ *
+ * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).
+ */
+void
+pbuf_realloc(struct pbuf *p, u16_t new_len)
+{
+  struct pbuf *q;
+  u16_t rem_len; /* remaining length */
+  s32_t grow;
+
+  LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
+  LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
+              p->type == PBUF_ROM ||
+              p->type == PBUF_RAM ||
+              p->type == PBUF_REF);
+
+  /* desired length larger than current length? */
+  if (new_len >= p->tot_len) {
+    /* enlarging not yet supported */
+    return;
+  }
+
+  /* the pbuf chain grows by (new_len - p->tot_len) bytes
+   * (which may be negative in case of shrinking) */
+  grow = new_len - p->tot_len;
+
+  /* first, step over any pbufs that should remain in the chain */
+  rem_len = new_len;
+  q = p;
+  /* should this pbuf be kept? */
+  while (rem_len > q->len) {
+    /* decrease remaining length by pbuf length */
+    rem_len -= q->len;
+    /* decrease total length indicator */
+    LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
+    q->tot_len += (u16_t)grow;
+    /* proceed to next pbuf in chain */
+    q = q->next;
+    LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
+  }
+  /* we have now reached the new last pbuf (in q) */
+  /* rem_len == desired length for pbuf q */
+
+  /* shrink allocated memory for PBUF_RAM */
+  /* (other types merely adjust their length fields */
+  if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
+    /* reallocate and adjust the length of the pbuf that will be split */
+    q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);
+    LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
+  }
+  /* adjust length fields for new last pbuf */
+  q->len = rem_len;
+  q->tot_len = q->len;
+
+  /* any remaining pbufs in chain? */
+  if (q->next != NULL) {
+    /* free remaining pbufs in chain */
+    pbuf_free(q->next);
+  }
+  /* q is last packet in chain */
+  q->next = NULL;
+
+}
+
+/**
+ * Adjusts the payload pointer to hide or reveal headers in the payload.
+ *
+ * Adjusts the ->payload pointer so that space for a header
+ * (dis)appears in the pbuf payload.
+ *
+ * The ->payload, ->tot_len and ->len fields are adjusted.
+ *
+ * @param p pbuf to change the header size.
+ * @param header_size_increment Number of bytes to increment header size which
+ * increases the size of the pbuf. New space is on the front.
+ * (Using a negative value decreases the header size.)
+ * If hdr_size_inc is 0, this function does nothing and returns succesful.
+ *
+ * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
+ * the call will fail. A check is made that the increase in header size does
+ * not move the payload pointer in front of the start of the buffer.
+ * @return non-zero on failure, zero on success.
+ *
+ */
+u8_t
+pbuf_header(struct pbuf *p, s16_t header_size_increment)
+{
+  u16_t type;
+  void *payload;
+  u16_t increment_magnitude;
+
+  LWIP_ASSERT("p != NULL", p != NULL);
+  if ((header_size_increment == 0) || (p == NULL)) {
+    return 0;
+  }
+ 
+  if (header_size_increment < 0){
+    increment_magnitude = -header_size_increment;
+    /* Check that we aren't going to move off the end of the pbuf */
+    LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
+  } else {
+    increment_magnitude = header_size_increment;
+#if 0
+    /* Can't assert these as some callers speculatively call
+         pbuf_header() to see if it's OK.  Will return 1 below instead. */
+    /* Check that we've got the correct type of pbuf to work with */
+    LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", 
+                p->type == PBUF_RAM || p->type == PBUF_POOL);
+    /* Check that we aren't going to move off the beginning of the pbuf */
+    LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
+                (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);
+#endif
+  }
+
+  type = p->type;
+  /* remember current payload pointer */
+  payload = p->payload;
+
+  /* pbuf types containing payloads? */
+  if (type == PBUF_RAM || type == PBUF_POOL) {
+    /* set new payload pointer */
+    p->payload = (u8_t *)p->payload - header_size_increment;
+    /* boundary check fails? */
+    if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
+      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
+        (void *)p->payload, (void *)(p + 1)));
+      /* restore old payload pointer */
+      p->payload = payload;
+      /* bail out unsuccesfully */
+      return 1;
+    }
+  /* pbuf types refering to external payloads? */
+  } else if (type == PBUF_REF || type == PBUF_ROM) {
+    /* hide a header in the payload? */
+    if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
+      /* increase payload pointer */
+      p->payload = (u8_t *)p->payload - header_size_increment;
+    } else {
+      /* cannot expand payload to front (yet!)
+       * bail out unsuccesfully */
+      return 1;
+    }
+  } else {
+    /* Unknown type */
+    LWIP_ASSERT("bad pbuf type", 0);
+    return 1;
+  }
+  /* modify pbuf length fields */
+  p->len += header_size_increment;
+  p->tot_len += header_size_increment;
+
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
+    (void *)payload, (void *)p->payload, header_size_increment));
+
+  return 0;
+}
+
+/**
+ * Dereference a pbuf chain or queue and deallocate any no-longer-used
+ * pbufs at the head of this chain or queue.
+ *
+ * Decrements the pbuf reference count. If it reaches zero, the pbuf is
+ * deallocated.
+ *
+ * For a pbuf chain, this is repeated for each pbuf in the chain,
+ * up to the first pbuf which has a non-zero reference count after
+ * decrementing. So, when all reference counts are one, the whole
+ * chain is free'd.
+ *
+ * @param p The pbuf (chain) to be dereferenced.
+ *
+ * @return the number of pbufs that were de-allocated
+ * from the head of the chain.
+ *
+ * @note MUST NOT be called on a packet queue (Not verified to work yet).
+ * @note the reference counter of a pbuf equals the number of pointers
+ * that refer to the pbuf (or into the pbuf).
+ *
+ * @internal examples:
+ *
+ * Assuming existing chains a->b->c with the following reference
+ * counts, calling pbuf_free(a) results in:
+ * 
+ * 1->2->3 becomes ...1->3
+ * 3->3->3 becomes 2->3->3
+ * 1->1->2 becomes ......1
+ * 2->1->1 becomes 1->1->1
+ * 1->1->1 becomes .......
+ *
+ */
+u8_t
+pbuf_free(struct pbuf *p)
+{
+  u16_t type;
+  struct pbuf *q;
+  u8_t count;
+
+  if (p == NULL) {
+    LWIP_ASSERT("p != NULL", p != NULL);
+    /* if assertions are disabled, proceed with debug output */
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+      ("pbuf_free(p == NULL) was called.\n"));
+    return 0;
+  }
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
+
+  PERF_START;
+
+  LWIP_ASSERT("pbuf_free: sane type",
+    p->type == PBUF_RAM || p->type == PBUF_ROM ||
+    p->type == PBUF_REF || p->type == PBUF_POOL);
+
+  count = 0;
+  /* de-allocate all consecutive pbufs from the head of the chain that
+   * obtain a zero reference count after decrementing*/
+  while (p != NULL) {
+    u16_t ref;
+    SYS_ARCH_DECL_PROTECT(old_level);
+    /* Since decrementing ref cannot be guaranteed to be a single machine operation
+     * we must protect it. We put the new ref into a local variable to prevent
+     * further protection. */
+    SYS_ARCH_PROTECT(old_level);
+    /* all pbufs in a chain are referenced at least once */
+    LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
+    /* decrease reference count (number of pointers to pbuf) */
+    ref = --(p->ref);
+    SYS_ARCH_UNPROTECT(old_level);
+    /* this pbuf is no longer referenced to? */
+    if (ref == 0) {
+      /* remember next pbuf in chain for next iteration */
+      q = p->next;
+      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
+      type = p->type;
+#if LWIP_SUPPORT_CUSTOM_PBUF
+      /* is this a custom pbuf? */
+      if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
+        struct pbuf_custom *pc = (struct pbuf_custom*)p;
+        LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL);
+        pc->custom_free_function(p);
+      } else
+#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
+      {
+        /* is this a pbuf from the pool? */
+        if (type == PBUF_POOL) {
+          memp_free(MEMP_PBUF_POOL, p);
+        /* is this a ROM or RAM referencing pbuf? */
+        } else if (type == PBUF_ROM || type == PBUF_REF) {
+          memp_free(MEMP_PBUF, p);
+        /* type == PBUF_RAM */
+        } else {
+          mem_free(p);
+        }
+      }
+      count++;
+      /* proceed to next pbuf */
+      p = q;
+    /* p->ref > 0, this pbuf is still referenced to */
+    /* (and so the remaining pbufs in chain as well) */
+    } else {
+      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
+      /* stop walking through the chain */
+      p = NULL;
+    }
+  }
+  PERF_STOP("pbuf_free");
+  /* return number of de-allocated pbufs */
+  return count;
+}
+
+/**
+ * Count number of pbufs in a chain
+ *
+ * @param p first pbuf of chain
+ * @return the number of pbufs in a chain
+ */
+
+u8_t
+pbuf_clen(struct pbuf *p)
+{
+  u8_t len;
+
+  len = 0;
+  while (p != NULL) {
+    ++len;
+    p = p->next;
+  }
+  return len;
+}
+
+/**
+ * Increment the reference count of the pbuf.
+ *
+ * @param p pbuf to increase reference counter of
+ *
+ */
+void
+pbuf_ref(struct pbuf *p)
+{
+  SYS_ARCH_DECL_PROTECT(old_level);
+  /* pbuf given? */
+  if (p != NULL) {
+    SYS_ARCH_PROTECT(old_level);
+    ++(p->ref);
+    SYS_ARCH_UNPROTECT(old_level);
+  }
+}
+
+/**
+ * Concatenate two pbufs (each may be a pbuf chain) and take over
+ * the caller's reference of the tail pbuf.
+ * 
+ * @note The caller MAY NOT reference the tail pbuf afterwards.
+ * Use pbuf_chain() for that purpose.
+ * 
+ * @see pbuf_chain()
+ */
+
+void
+pbuf_cat(struct pbuf *h, struct pbuf *t)
+{
+  struct pbuf *p;
+
+  LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
+             ((h != NULL) && (t != NULL)), return;);
+
+  /* proceed to last pbuf of chain */
+  for (p = h; p->next != NULL; p = p->next) {
+    /* add total length of second chain to all totals of first chain */
+    p->tot_len += t->tot_len;
+  }
+  /* { p is last pbuf of first h chain, p->next == NULL } */
+  LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
+  LWIP_ASSERT("p->next == NULL", p->next == NULL);
+  /* add total length of second chain to last pbuf total of first chain */
+  p->tot_len += t->tot_len;
+  /* chain last pbuf of head (p) with first of tail (t) */
+  p->next = t;
+  /* p->next now references t, but the caller will drop its reference to t,
+   * so netto there is no change to the reference count of t.
+   */
+}
+
+/**
+ * Chain two pbufs (or pbuf chains) together.
+ * 
+ * The caller MUST call pbuf_free(t) once it has stopped
+ * using it. Use pbuf_cat() instead if you no longer use t.
+ * 
+ * @param h head pbuf (chain)
+ * @param t tail pbuf (chain)
+ * @note The pbufs MUST belong to the same packet.
+ * @note MAY NOT be called on a packet queue.
+ *
+ * The ->tot_len fields of all pbufs of the head chain are adjusted.
+ * The ->next field of the last pbuf of the head chain is adjusted.
+ * The ->ref field of the first pbuf of the tail chain is adjusted.
+ *
+ */
+void
+pbuf_chain(struct pbuf *h, struct pbuf *t)
+{
+  pbuf_cat(h, t);
+  /* t is now referenced by h */
+  pbuf_ref(t);
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
+}
+
+/**
+ * Dechains the first pbuf from its succeeding pbufs in the chain.
+ *
+ * Makes p->tot_len field equal to p->len.
+ * @param p pbuf to dechain
+ * @return remainder of the pbuf chain, or NULL if it was de-allocated.
+ * @note May not be called on a packet queue.
+ */
+struct pbuf *
+pbuf_dechain(struct pbuf *p)
+{
+  struct pbuf *q;
+  u8_t tail_gone = 1;
+  /* tail */
+  q = p->next;
+  /* pbuf has successor in chain? */
+  if (q != NULL) {
+    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
+    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
+    /* enforce invariant if assertion is disabled */
+    q->tot_len = p->tot_len - p->len;
+    /* decouple pbuf from remainder */
+    p->next = NULL;
+    /* total length of pbuf p is its own length only */
+    p->tot_len = p->len;
+    /* q is no longer referenced by p, free it */
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
+    tail_gone = pbuf_free(q);
+    if (tail_gone > 0) {
+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
+                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
+    }
+    /* return remaining tail or NULL if deallocated */
+  }
+  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
+  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
+  return ((tail_gone > 0) ? NULL : q);
+}
+
+/**
+ *
+ * Create PBUF_RAM copies of pbufs.
+ *
+ * Used to queue packets on behalf of the lwIP stack, such as
+ * ARP based queueing.
+ *
+ * @note You MUST explicitly use p = pbuf_take(p);
+ *
+ * @note Only one packet is copied, no packet queue!
+ *
+ * @param p_to pbuf destination of the copy
+ * @param p_from pbuf source of the copy
+ *
+ * @return ERR_OK if pbuf was copied
+ *         ERR_ARG if one of the pbufs is NULL or p_to is not big
+ *                 enough to hold p_from
+ */
+err_t
+pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
+{
+  u16_t offset_to=0, offset_from=0, len;
+
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
+    (void*)p_to, (void*)p_from));
+
+  /* is the target big enough to hold the source? */
+  LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
+             (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
+
+  /* iterate through pbuf chain */
+  do
+  {
+    LWIP_ASSERT("p_to != NULL", p_to != NULL);
+    /* copy one part of the original chain */
+    if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
+      /* complete current p_from fits into current p_to */
+      len = p_from->len - offset_from;
+    } else {
+      /* current p_from does not fit into current p_to */
+      len = p_to->len - offset_to;
+    }
+    MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);
+    offset_to += len;
+    offset_from += len;
+    LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
+    if (offset_to == p_to->len) {
+      /* on to next p_to (if any) */
+      offset_to = 0;
+      p_to = p_to->next;
+    }
+    LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
+    if (offset_from >= p_from->len) {
+      /* on to next p_from (if any) */
+      offset_from = 0;
+      p_from = p_from->next;
+    }
+
+    if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
+      /* don't copy more than one packet! */
+      LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
+                 (p_from->next == NULL), return ERR_VAL;);
+    }
+    if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
+      /* don't copy more than one packet! */
+      LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
+                  (p_to->next == NULL), return ERR_VAL;);
+    }
+  } while (p_from);
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
+  return ERR_OK;
+}
+
+/**
+ * Copy (part of) the contents of a packet buffer
+ * to an application supplied buffer.
+ *
+ * @param buf the pbuf from which to copy data
+ * @param dataptr the application supplied buffer
+ * @param len length of data to copy (dataptr must be big enough). No more 
+ * than buf->tot_len will be copied, irrespective of len
+ * @param offset offset into the packet buffer from where to begin copying len bytes
+ * @return the number of bytes copied, or 0 on failure
+ */
+u16_t
+pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
+{
+  struct pbuf *p;
+  u16_t left;
+  u16_t buf_copy_len;
+  u16_t copied_total = 0;
+
+  LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
+  LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
+
+  left = 0;
+
+  if((buf == NULL) || (dataptr == NULL)) {
+    return 0;
+  }
+
+  /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
+  for(p = buf; len != 0 && p != NULL; p = p->next) {
+    if ((offset != 0) && (offset >= p->len)) {
+      /* don't copy from this buffer -> on to the next */
+      offset -= p->len;
+    } else {
+      /* copy from this buffer. maybe only partially. */
+      buf_copy_len = p->len - offset;
+      if (buf_copy_len > len)
+          buf_copy_len = len;
+      /* copy the necessary parts of the buffer */
+      MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
+      copied_total += buf_copy_len;
+      left += buf_copy_len;
+      len -= buf_copy_len;
+      offset = 0;
+    }
+  }
+  return copied_total;
+}
+
+/**
+ * Copy application supplied data into a pbuf.
+ * This function can only be used to copy the equivalent of buf->tot_len data.
+ *
+ * @param buf pbuf to fill with data
+ * @param dataptr application supplied data buffer
+ * @param len length of the application supplied data buffer
+ *
+ * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
+ */
+err_t
+pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
+{
+  struct pbuf *p;
+  u16_t buf_copy_len;
+  u16_t total_copy_len = len;
+  u16_t copied_total = 0;
+
+  LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
+  LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
+
+  if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
+    return ERR_ARG;
+  }
+
+  /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
+  for(p = buf; total_copy_len != 0; p = p->next) {
+    LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
+    buf_copy_len = total_copy_len;
+    if (buf_copy_len > p->len) {
+      /* this pbuf cannot hold all remaining data */
+      buf_copy_len = p->len;
+    }
+    /* copy the necessary parts of the buffer */
+    MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
+    total_copy_len -= buf_copy_len;
+    copied_total += buf_copy_len;
+  }
+  LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
+  return ERR_OK;
+}
+
+/**
+ * Creates a single pbuf out of a queue of pbufs.
+ *
+ * @remark: Either the source pbuf 'p' is freed by this function or the original
+ *          pbuf 'p' is returned, therefore the caller has to check the result!
+ *
+ * @param p the source pbuf
+ * @param layer pbuf_layer of the new pbuf
+ *
+ * @return a new, single pbuf (p->next is NULL)
+ *         or the old pbuf if allocation fails
+ */
+struct pbuf*
+pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
+{
+  struct pbuf *q;
+  err_t err;
+  if (p->next == NULL) {
+    return p;
+  }
+  q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
+  if (q == NULL) {
+    /* @todo: what do we do now? */
+    return p;
+  }
+  err = pbuf_copy(q, p);
+  LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
+  pbuf_free(p);
+  return q;
+}
+
+#if LWIP_CHECKSUM_ON_COPY
+/**
+ * Copies data into a single pbuf (*not* into a pbuf queue!) and updates
+ * the checksum while copying
+ *
+ * @param p the pbuf to copy data into
+ * @param start_offset offset of p->payload where to copy the data to
+ * @param dataptr data to copy into the pbuf
+ * @param len length of data to copy into the pbuf
+ * @param chksum pointer to the checksum which is updated
+ * @return ERR_OK if successful, another error if the data does not fit
+ *         within the (first) pbuf (no pbuf queues!)
+ */
+err_t
+pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
+                 u16_t len, u16_t *chksum)
+{
+  u32_t acc;
+  u16_t copy_chksum;
+  char *dst_ptr;
+  LWIP_ASSERT("p != NULL", p != NULL);
+  LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
+  LWIP_ASSERT("chksum != NULL", chksum != NULL);
+  LWIP_ASSERT("len != 0", len != 0);
+
+  if ((start_offset >= p->len) || (start_offset + len > p->len)) {
+    return ERR_ARG;
+  }
+
+  dst_ptr = ((char*)p->payload) + start_offset;
+  copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
+  if ((start_offset & 1) != 0) {
+    copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
+  }
+  acc = *chksum;
+  acc += copy_chksum;
+  *chksum = FOLD_U32T(acc);
+  return ERR_OK;
+}
+#endif /* LWIP_CHECKSUM_ON_COPY */
+
+ /** Get one byte from the specified position in a pbuf
+ * WARNING: returns zero for offset >= p->tot_len
+ *
+ * @param p pbuf to parse
+ * @param offset offset into p of the byte to return
+ * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
+ */
+u8_t
+pbuf_get_at(struct pbuf* p, u16_t offset)
+{
+  u16_t copy_from = offset;
+  struct pbuf* q = p;
+
+  /* get the correct pbuf */
+  while ((q != NULL) && (q->len <= copy_from)) {
+    copy_from -= q->len;
+    q = q->next;
+  }
+  /* return requested data if pbuf is OK */
+  if ((q != NULL) && (q->len > copy_from)) {
+    return ((u8_t*)q->payload)[copy_from];
+  }
+  return 0;
+}
+
+/** Compare pbuf contents at specified offset with memory s2, both of length n
+ *
+ * @param p pbuf to compare
+ * @param offset offset into p at wich to start comparing
+ * @param s2 buffer to compare
+ * @param n length of buffer to compare
+ * @return zero if equal, nonzero otherwise
+ *         (0xffff if p is too short, diffoffset+1 otherwise)
+ */
+u16_t
+pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
+{
+  u16_t start = offset;
+  struct pbuf* q = p;
+
+  /* get the correct pbuf */
+  while ((q != NULL) && (q->len <= start)) {
+    start -= q->len;
+    q = q->next;
+  }
+  /* return requested data if pbuf is OK */
+  if ((q != NULL) && (q->len > start)) {
+    u16_t i;
+    for(i = 0; i < n; i++) {
+      u8_t a = pbuf_get_at(q, start + i);
+      u8_t b = ((u8_t*)s2)[i];
+      if (a != b) {
+        return i+1;
+      }
+    }
+    return 0;
+  }
+  return 0xffff;
+}
+
+/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
+ * start_offset.
+ *
+ * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
+ *        return value 'not found'
+ * @param mem search for the contents of this buffer
+ * @param mem_len length of 'mem'
+ * @param start_offset offset into p at which to start searching
+ * @return 0xFFFF if substr was not found in p or the index where it was found
+ */
+u16_t
+pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
+{
+  u16_t i;
+  u16_t max = p->tot_len - mem_len;
+  if (p->tot_len >= mem_len + start_offset) {
+    for(i = start_offset; i <= max; ) {
+      u16_t plus = pbuf_memcmp(p, i, mem, mem_len);
+      if (plus == 0) {
+        return i;
+      } else {
+        i += plus;
+      }
+    }
+  }
+  return 0xFFFF;
+}
+
+/** Find occurrence of substr with length substr_len in pbuf p, start at offset
+ * start_offset
+ * WARNING: in contrast to strstr(), this one does not stop at the first \0 in
+ * the pbuf/source string!
+ *
+ * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
+ *        return value 'not found'
+ * @param substr string to search for in p, maximum length is 0xFFFE
+ * @return 0xFFFF if substr was not found in p or the index where it was found
+ */
+u16_t
+pbuf_strstr(struct pbuf* p, const char* substr)
+{
+  size_t substr_len;
+  if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
+    return 0xFFFF;
+  }
+  substr_len = strlen(substr);
+  if (substr_len >= 0xFFFF) {
+    return 0xFFFF;
+  }
+  return pbuf_memfind(p, substr, (u16_t)substr_len, 0);
+}
diff -r 000000000000 -r 350011bf8be7 lwip/core/raw.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/raw.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,352 @@
+/**
+ * @file
+ * Implementation of raw protocol PCBs for low-level handling of
+ * different types of protocols besides (or overriding) those
+ * already available in lwIP.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/def.h"
+#include "lwip/memp.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+#include "lwip/raw.h"
+#include "lwip/stats.h"
+#include "arch/perf.h"
+
+#include <string.h>
+
+/** The list of RAW PCBs */
+static struct raw_pcb *raw_pcbs;
+
+/**
+ * Determine if in incoming IP packet is covered by a RAW PCB
+ * and if so, pass it to a user-provided receive callback function.
+ *
+ * Given an incoming IP datagram (as a chain of pbufs) this function
+ * finds a corresponding RAW PCB and calls the corresponding receive
+ * callback function.
+ *
+ * @param p pbuf to be demultiplexed to a RAW PCB.
+ * @param inp network interface on which the datagram was received.
+ * @return - 1 if the packet has been eaten by a RAW PCB receive
+ *           callback function. The caller MAY NOT not reference the
+ *           packet any longer, and MAY NOT call pbuf_free().
+ * @return - 0 if packet is not eaten (pbuf is still referenced by the
+ *           caller).
+ *
+ */
+u8_t
+raw_input(struct pbuf *p, struct netif *inp)
+{
+  struct raw_pcb *pcb, *prev;
+  struct ip_hdr *iphdr;
+  s16_t proto;
+  u8_t eaten = 0;
+
+  LWIP_UNUSED_ARG(inp);
+
+  iphdr = (struct ip_hdr *)p->payload;
+  proto = IPH_PROTO(iphdr);
+
+  prev = NULL;
+  pcb = raw_pcbs;
+  /* loop through all raw pcbs until the packet is eaten by one */
+  /* this allows multiple pcbs to match against the packet by design */
+  while ((eaten == 0) && (pcb != NULL)) {
+    if ((pcb->protocol == proto) &&
+        (ip_addr_isany(&pcb->local_ip) ||
+         ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest))) {
+#if IP_SOF_BROADCAST_RECV
+      /* broadcast filter? */
+      if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&current_iphdr_dest, inp))
+#endif /* IP_SOF_BROADCAST_RECV */
+      {
+        /* receive callback function available? */
+        if (pcb->recv != NULL) {
+          /* the receive callback function did not eat the packet? */
+          if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) {
+            /* receive function ate the packet */
+            p = NULL;
+            eaten = 1;
+            if (prev != NULL) {
+            /* move the pcb to the front of raw_pcbs so that is
+               found faster next time */
+              prev->next = pcb->next;
+              pcb->next = raw_pcbs;
+              raw_pcbs = pcb;
+            }
+          }
+        }
+        /* no receive callback function was set for this raw PCB */
+      }
+      /* drop the packet */
+    }
+    prev = pcb;
+    pcb = pcb->next;
+  }
+  return eaten;
+}
+
+/**
+ * Bind a RAW PCB.
+ *
+ * @param pcb RAW PCB to be bound with a local address ipaddr.
+ * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
+ * bind to all local interfaces.
+ *
+ * @return lwIP error code.
+ * - ERR_OK. Successful. No error occured.
+ * - ERR_USE. The specified IP address is already bound to by
+ * another RAW PCB.
+ *
+ * @see raw_disconnect()
+ */
+err_t
+raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
+{
+  ip_addr_set(&pcb->local_ip, ipaddr);
+  return ERR_OK;
+}
+
+/**
+ * Connect an RAW PCB. This function is required by upper layers
+ * of lwip. Using the raw api you could use raw_sendto() instead
+ *
+ * This will associate the RAW PCB with the remote address.
+ *
+ * @param pcb RAW PCB to be connected with remote address ipaddr and port.
+ * @param ipaddr remote IP address to connect with.
+ *
+ * @return lwIP error code
+ *
+ * @see raw_disconnect() and raw_sendto()
+ */
+err_t
+raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
+{
+  ip_addr_set(&pcb->remote_ip, ipaddr);
+  return ERR_OK;
+}
+
+
+/**
+ * Set the callback function for received packets that match the
+ * raw PCB's protocol and binding. 
+ * 
+ * The callback function MUST either
+ * - eat the packet by calling pbuf_free() and returning non-zero. The
+ *   packet will not be passed to other raw PCBs or other protocol layers.
+ * - not free the packet, and return zero. The packet will be matched
+ *   against further PCBs and/or forwarded to another protocol layers.
+ * 
+ * @return non-zero if the packet was free()d, zero if the packet remains
+ * available for others.
+ */
+void
+raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
+{
+  /* remember recv() callback and user data */
+  pcb->recv = recv;
+  pcb->recv_arg = recv_arg;
+}
+
+/**
+ * Send the raw IP packet to the given address. Note that actually you cannot
+ * modify the IP headers (this is inconsistent with the receive callback where
+ * you actually get the IP headers), you can only specify the IP payload here.
+ * It requires some more changes in lwIP. (there will be a raw_send() function
+ * then.)
+ *
+ * @param pcb the raw pcb which to send
+ * @param p the IP payload to send
+ * @param ipaddr the destination address of the IP packet
+ *
+ */
+err_t
+raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
+{
+  err_t err;
+  struct netif *netif;
+  ip_addr_t *src_ip;
+  struct pbuf *q; /* q will be sent down the stack */
+  
+  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
+  
+  /* not enough space to add an IP header to first pbuf in given p chain? */
+  if (pbuf_header(p, IP_HLEN)) {
+    /* allocate header in new pbuf */
+    q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
+    /* new header pbuf could not be allocated? */
+    if (q == NULL) {
+      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
+      return ERR_MEM;
+    }
+    /* chain header q in front of given pbuf p */
+    pbuf_chain(q, p);
+    /* { first pbuf q points to header pbuf } */
+    LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
+  }  else {
+    /* first pbuf q equals given pbuf */
+    q = p;
+    if(pbuf_header(q, -IP_HLEN)) {
+      LWIP_ASSERT("Can't restore header we just removed!", 0);
+      return ERR_MEM;
+    }
+  }
+
+  if ((netif = ip_route(ipaddr)) == NULL) {
+    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
+    /* free any temporary header pbuf allocated by pbuf_header() */
+    if (q != p) {
+      pbuf_free(q);
+    }
+    return ERR_RTE;
+  }
+
+#if IP_SOF_BROADCAST
+  /* broadcast filter? */
+  if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
+    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
+    /* free any temporary header pbuf allocated by pbuf_header() */
+    if (q != p) {
+      pbuf_free(q);
+    }
+    return ERR_VAL;
+  }
+#endif /* IP_SOF_BROADCAST */
+
+  if (ip_addr_isany(&pcb->local_ip)) {
+    /* use outgoing network interface IP address as source address */
+    src_ip = &(netif->ip_addr);
+  } else {
+    /* use RAW PCB local IP address as source address */
+    src_ip = &(pcb->local_ip);
+  }
+
+#if LWIP_NETIF_HWADDRHINT
+  netif->addr_hint = &(pcb->addr_hint);
+#endif /* LWIP_NETIF_HWADDRHINT*/
+  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
+#if LWIP_NETIF_HWADDRHINT
+  netif->addr_hint = NULL;
+#endif /* LWIP_NETIF_HWADDRHINT*/
+
+  /* did we chain a header earlier? */
+  if (q != p) {
+    /* free the header */
+    pbuf_free(q);
+  }
+  return err;
+}
+
+/**
+ * Send the raw IP packet to the address given by raw_connect()
+ *
+ * @param pcb the raw pcb which to send
+ * @param p the IP payload to send
+ *
+ */
+err_t
+raw_send(struct raw_pcb *pcb, struct pbuf *p)
+{
+  return raw_sendto(pcb, p, &pcb->remote_ip);
+}
+
+/**
+ * Remove an RAW PCB.
+ *
+ * @param pcb RAW PCB to be removed. The PCB is removed from the list of
+ * RAW PCB's and the data structure is freed from memory.
+ *
+ * @see raw_new()
+ */
+void
+raw_remove(struct raw_pcb *pcb)
+{
+  struct raw_pcb *pcb2;
+  /* pcb to be removed is first in list? */
+  if (raw_pcbs == pcb) {
+    /* make list start at 2nd pcb */
+    raw_pcbs = raw_pcbs->next;
+    /* pcb not 1st in list */
+  } else {
+    for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
+      /* find pcb in raw_pcbs list */
+      if (pcb2->next != NULL && pcb2->next == pcb) {
+        /* remove pcb from list */
+        pcb2->next = pcb->next;
+      }
+    }
+  }
+  memp_free(MEMP_RAW_PCB, pcb);
+}
+
+/**
+ * Create a RAW PCB.
+ *
+ * @return The RAW PCB which was created. NULL if the PCB data structure
+ * could not be allocated.
+ *
+ * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
+ *
+ * @see raw_remove()
+ */
+struct raw_pcb *
+raw_new(u8_t proto)
+{
+  struct raw_pcb *pcb;
+
+  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
+
+  pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
+  /* could allocate RAW PCB? */
+  if (pcb != NULL) {
+    /* initialize PCB to all zeroes */
+    memset(pcb, 0, sizeof(struct raw_pcb));
+    pcb->protocol = proto;
+    pcb->ttl = RAW_TTL;
+    pcb->next = raw_pcbs;
+    raw_pcbs = pcb;
+  }
+  return pcb;
+}
+
+#endif /* LWIP_RAW */
diff -r 000000000000 -r 350011bf8be7 lwip/core/snmp/asn1_dec.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/snmp/asn1_dec.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,657 @@
+/**
+ * @file
+ * Abstract Syntax Notation One (ISO 8824, 8825) decoding
+ *
+ * @todo not optimised (yet), favor correctness over speed, favor speed over size
+ */
+
+/*
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
+ * 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: Christiaan Simons <christiaan.simons@axon.tv>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/snmp_asn1.h"
+
+/**
+ * Retrieves type field from incoming pbuf chain.
+ *
+ * @param p points to a pbuf holding an ASN1 coded type field
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field
+ * @param type return ASN1 type
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ */
+err_t
+snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+      *type = *msg_ptr;
+      return ERR_OK;
+    }
+    p = p->next;
+  }
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+/**
+ * Decodes length field from incoming pbuf chain into host length.
+ *
+ * @param p points to a pbuf holding an ASN1 coded length
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded length
+ * @param octets_used returns number of octets used by the length code
+ * @param length return host order length, upto 64k
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ */
+err_t
+snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+
+      if (*msg_ptr < 0x80)
+      {
+        /* primitive definite length format */
+        *octets_used = 1;
+        *length = *msg_ptr;
+        return ERR_OK;
+      }
+      else if (*msg_ptr == 0x80)
+      {
+        /* constructed indefinite length format, termination with two zero octets */
+        u8_t zeros;
+        u8_t i;
+
+        *length = 0;
+        zeros = 0;
+        while (zeros != 2)
+        {
+          i = 2;
+          while (i > 0)
+          {
+            i--;
+            (*length) += 1;
+            ofs += 1;
+            if (ofs >= plen)
+            {
+              /* next octet in next pbuf */
+              p = p->next;
+              if (p == NULL) { return ERR_ARG; }
+              msg_ptr = (u8_t*)p->payload;
+              plen += p->len;
+            }
+            else
+            {
+              /* next octet in same pbuf */
+              msg_ptr++;
+            }
+            if (*msg_ptr == 0)
+            {
+              zeros++;
+              if (zeros == 2)
+              {
+                /* stop while (i > 0) */
+                i = 0;
+              }
+            }
+            else
+            {
+              zeros = 0;
+            }
+          }
+        }
+        *octets_used = 1;
+        return ERR_OK;
+      }
+      else if (*msg_ptr == 0x81)
+      {
+        /* constructed definite length format, one octet */
+        ofs += 1;
+        if (ofs >= plen)
+        {
+          /* next octet in next pbuf */
+          p = p->next;
+          if (p == NULL) { return ERR_ARG; }
+          msg_ptr = (u8_t*)p->payload;
+        }
+        else
+        {
+          /* next octet in same pbuf */
+          msg_ptr++;
+        }
+        *length = *msg_ptr;
+        *octets_used = 2;
+        return ERR_OK;
+      }
+      else if (*msg_ptr == 0x82)
+      {
+        u8_t i;
+
+        /* constructed definite length format, two octets */
+        i = 2;
+        while (i > 0)
+        {
+          i--;
+          ofs += 1;
+          if (ofs >= plen)
+          {
+            /* next octet in next pbuf */
+            p = p->next;
+            if (p == NULL) { return ERR_ARG; }
+            msg_ptr = (u8_t*)p->payload;
+            plen += p->len;
+          }
+          else
+          {
+            /* next octet in same pbuf */
+            msg_ptr++;
+          }
+          if (i == 0)
+          {
+            /* least significant length octet */
+            *length |= *msg_ptr;
+          }
+          else
+          {
+            /* most significant length octet */
+            *length = (*msg_ptr) << 8;
+          }
+        }
+        *octets_used = 3;
+        return ERR_OK;
+      }
+      else
+      {
+        /* constructed definite length format 3..127 octets, this is too big (>64k) */
+        /**  @todo: do we need to accept inefficient codings with many leading zero's? */
+        *octets_used = 1 + ((*msg_ptr) & 0x7f);
+        return ERR_ARG;
+      }
+    }
+    p = p->next;
+  }
+
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+/**
+ * Decodes positive integer (counter, gauge, timeticks) into u32_t.
+ *
+ * @param p points to a pbuf holding an ASN1 coded integer
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
+ * @param len length of the coded integer field
+ * @param value return host order integer
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ *
+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
+ */
+err_t
+snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+      if ((len > 0) && (len < 6))
+      {
+        /* start from zero */
+        *value = 0;
+        if (*msg_ptr & 0x80)
+        {
+          /* negative, expecting zero sign bit! */
+          return ERR_ARG;
+        }
+        else
+        {
+          /* positive */
+          if ((len > 1) && (*msg_ptr == 0))
+          {
+            /* skip leading "sign byte" octet 0x00 */
+            len--;
+            ofs += 1;
+            if (ofs >= plen)
+            {
+              /* next octet in next pbuf */
+              p = p->next;
+              if (p == NULL) { return ERR_ARG; }
+              msg_ptr = (u8_t*)p->payload;
+              plen += p->len;
+            }
+            else
+            {
+              /* next octet in same pbuf */
+              msg_ptr++;
+            }
+          }
+        }
+        /* OR octets with value */
+        while (len > 1)
+        {
+          len--;
+          *value |= *msg_ptr;
+          *value <<= 8;
+          ofs += 1;
+          if (ofs >= plen)
+          {
+            /* next octet in next pbuf */
+            p = p->next;
+            if (p == NULL) { return ERR_ARG; }
+            msg_ptr = (u8_t*)p->payload;
+            plen += p->len;
+          }
+          else
+          {
+            /* next octet in same pbuf */
+            msg_ptr++;
+          }
+        }
+        *value |= *msg_ptr;
+        return ERR_OK;
+      }
+      else
+      {
+        return ERR_ARG;
+      }
+    }
+    p = p->next;
+  }
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+/**
+ * Decodes integer into s32_t.
+ *
+ * @param p points to a pbuf holding an ASN1 coded integer
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
+ * @param len length of the coded integer field
+ * @param value return host order integer
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ *
+ * @note ASN coded integers are _always_ signed!
+ */
+err_t
+snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+#if BYTE_ORDER == LITTLE_ENDIAN
+  u8_t *lsb_ptr = (u8_t*)value;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+  u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
+#endif
+  u8_t sign;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+      if ((len > 0) && (len < 5))
+      {
+        if (*msg_ptr & 0x80)
+        {
+          /* negative, start from -1 */
+          *value = -1;
+          sign = 1;
+        }
+        else
+        {
+          /* positive, start from 0 */
+          *value = 0;
+          sign = 0;
+        }
+        /* OR/AND octets with value */
+        while (len > 1)
+        {
+          len--;
+          if (sign)
+          {
+            *lsb_ptr &= *msg_ptr;
+            *value <<= 8;
+            *lsb_ptr |= 255;
+          }
+          else
+          {
+            *lsb_ptr |= *msg_ptr;
+            *value <<= 8;
+          }
+          ofs += 1;
+          if (ofs >= plen)
+          {
+            /* next octet in next pbuf */
+            p = p->next;
+            if (p == NULL) { return ERR_ARG; }
+            msg_ptr = (u8_t*)p->payload;
+            plen += p->len;
+          }
+          else
+          {
+            /* next octet in same pbuf */
+            msg_ptr++;
+          }
+        }
+        if (sign)
+        {
+          *lsb_ptr &= *msg_ptr;
+        }
+        else
+        {
+          *lsb_ptr |= *msg_ptr;
+        }
+        return ERR_OK;
+      }
+      else
+      {
+        return ERR_ARG;
+      }
+    }
+    p = p->next;
+  }
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+/**
+ * Decodes object identifier from incoming message into array of s32_t.
+ *
+ * @param p points to a pbuf holding an ASN1 coded object identifier
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
+ * @param len length of the coded object identifier
+ * @param oid return object identifier struct
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ */
+err_t
+snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+  s32_t *oid_ptr;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+
+      oid->len = 0;
+      oid_ptr = &oid->id[0];
+      if (len > 0)
+      {
+        /* first compressed octet */
+        if (*msg_ptr == 0x2B)
+        {
+          /* (most) common case 1.3 (iso.org) */
+          *oid_ptr = 1;
+          oid_ptr++;
+          *oid_ptr = 3;
+          oid_ptr++;
+        }
+        else if (*msg_ptr < 40)
+        {
+          *oid_ptr = 0;
+          oid_ptr++;
+          *oid_ptr = *msg_ptr;
+          oid_ptr++;
+        }
+        else if (*msg_ptr < 80)
+        {
+          *oid_ptr = 1;
+          oid_ptr++;
+          *oid_ptr = (*msg_ptr) - 40;
+          oid_ptr++;
+        }
+        else
+        {
+          *oid_ptr = 2;
+          oid_ptr++;
+          *oid_ptr = (*msg_ptr) - 80;
+          oid_ptr++;
+        }
+        oid->len = 2;
+      }
+      else
+      {
+        /* accepting zero length identifiers e.g. for
+           getnext operation. uncommon but valid */
+        return ERR_OK;
+      }
+      len--;
+      if (len > 0)
+      {
+        ofs += 1;
+        if (ofs >= plen)
+        {
+          /* next octet in next pbuf */
+          p = p->next;
+          if (p == NULL) { return ERR_ARG; }
+          msg_ptr = (u8_t*)p->payload;
+          plen += p->len;
+        }
+        else
+        {
+          /* next octet in same pbuf */
+          msg_ptr++;
+        }
+      }
+      while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))
+      {
+        /* sub-identifier uses multiple octets */
+        if (*msg_ptr & 0x80)
+        {
+          s32_t sub_id = 0;
+
+          while ((*msg_ptr & 0x80) && (len > 1))
+          {
+            len--;
+            sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);
+            ofs += 1;
+            if (ofs >= plen)
+            {
+              /* next octet in next pbuf */
+              p = p->next;
+              if (p == NULL) { return ERR_ARG; }
+              msg_ptr = (u8_t*)p->payload;
+              plen += p->len;
+            }
+            else
+            {
+              /* next octet in same pbuf */
+              msg_ptr++;
+            }
+          }
+          if (!(*msg_ptr & 0x80) && (len > 0))
+          {
+            /* last octet sub-identifier */
+            len--;
+            sub_id = (sub_id << 7) + *msg_ptr;
+            *oid_ptr = sub_id;
+          }
+        }
+        else
+        {
+          /* !(*msg_ptr & 0x80) sub-identifier uses single octet */
+          len--;
+          *oid_ptr = *msg_ptr;
+        }
+        if (len > 0)
+        {
+          /* remaining oid bytes available ... */
+          ofs += 1;
+          if (ofs >= plen)
+          {
+            /* next octet in next pbuf */
+            p = p->next;
+            if (p == NULL) { return ERR_ARG; }
+            msg_ptr = (u8_t*)p->payload;
+            plen += p->len;
+          }
+          else
+          {
+            /* next octet in same pbuf */
+            msg_ptr++;
+          }
+        }
+        oid_ptr++;
+        oid->len++;
+      }
+      if (len == 0)
+      {
+        /* len == 0, end of oid */
+        return ERR_OK;
+      }
+      else
+      {
+        /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */
+        return ERR_ARG;
+      }
+
+    }
+    p = p->next;
+  }
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+/**
+ * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
+ * from incoming message into array.
+ *
+ * @param p points to a pbuf holding an ASN1 coded raw data
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
+ * @param len length of the coded raw data (zero is valid, e.g. empty string!)
+ * @param raw_len length of the raw return value
+ * @param raw return raw bytes
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
+ */
+err_t
+snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+
+  if (len > 0)
+  {
+    plen = 0;
+    while (p != NULL)
+    {
+      base = plen;
+      plen += p->len;
+      if (ofs < plen)
+      {
+        msg_ptr = (u8_t*)p->payload;
+        msg_ptr += ofs - base;
+        if (raw_len >= len)
+        {
+          while (len > 1)
+          {
+            /* copy len - 1 octets */
+            len--;
+            *raw = *msg_ptr;
+            raw++;
+            ofs += 1;
+            if (ofs >= plen)
+            {
+              /* next octet in next pbuf */
+              p = p->next;
+              if (p == NULL) { return ERR_ARG; }
+              msg_ptr = (u8_t*)p->payload;
+              plen += p->len;
+            }
+            else
+            {
+              /* next octet in same pbuf */
+              msg_ptr++;
+            }
+          }
+          /* copy last octet */
+          *raw = *msg_ptr;
+          return ERR_OK;
+        }
+        else
+        {
+          /* raw_len < len, not enough dst space */
+          return ERR_ARG;
+        }
+      }
+      p = p->next;
+    }
+    /* p == NULL, ofs >= plen */
+    return ERR_ARG;
+  }
+  else
+  {
+    /* len == 0, empty string */
+    return ERR_OK;
+  }
+}
+
+#endif /* LWIP_SNMP */
diff -r 000000000000 -r 350011bf8be7 lwip/core/snmp/asn1_enc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/snmp/asn1_enc.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,611 @@
+/**
+ * @file
+ * Abstract Syntax Notation One (ISO 8824, 8825) encoding
+ *
+ * @todo not optimised (yet), favor correctness over speed, favor speed over size
+ */
+
+/*
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
+ * 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: Christiaan Simons <christiaan.simons@axon.tv>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/snmp_asn1.h"
+
+/**
+ * Returns octet count for length.
+ *
+ * @param length
+ * @param octets_needed points to the return value
+ */
+void
+snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
+{
+  if (length < 0x80U)
+  {
+    *octets_needed = 1;
+  }
+  else if (length < 0x100U)
+  {
+    *octets_needed = 2;
+  }
+  else
+  {
+    *octets_needed = 3;
+  }
+}
+
+/**
+ * Returns octet count for an u32_t.
+ *
+ * @param value
+ * @param octets_needed points to the return value
+ *
+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
+ */
+void
+snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
+{
+  if (value < 0x80UL)
+  {
+    *octets_needed = 1;
+  }
+  else if (value < 0x8000UL)
+  {
+    *octets_needed = 2;
+  }
+  else if (value < 0x800000UL)
+  {
+    *octets_needed = 3;
+  }
+  else if (value < 0x80000000UL)
+  {
+    *octets_needed = 4;
+  }
+  else
+  {
+    *octets_needed = 5;
+  }
+}
+
+/**
+ * Returns octet count for an s32_t.
+ *
+ * @param value
+ * @param octets_needed points to the return value
+ *
+ * @note ASN coded integers are _always_ signed.
+ */
+void
+snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
+{
+  if (value < 0)
+  {
+    value = ~value;
+  }
+  if (value < 0x80L)
+  {
+    *octets_needed = 1;
+  }
+  else if (value < 0x8000L)
+  {
+    *octets_needed = 2;
+  }
+  else if (value < 0x800000L)
+  {
+    *octets_needed = 3;
+  }
+  else
+  {
+    *octets_needed = 4;
+  }
+}
+
+/**
+ * Returns octet count for an object identifier.
+ *
+ * @param ident_len object identifier array length
+ * @param ident points to object identifier array
+ * @param octets_needed points to the return value
+ */
+void
+snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed)
+{
+  s32_t sub_id;
+  u8_t cnt;
+
+  cnt = 0;
+  if (ident_len > 1)
+  {
+    /* compressed prefix in one octet */
+    cnt++;
+    ident_len -= 2;
+    ident += 2;
+  }
+  while(ident_len > 0)
+  {
+    ident_len--;
+    sub_id = *ident;
+
+    sub_id >>= 7;
+    cnt++;
+    while(sub_id > 0)
+    {
+      sub_id >>= 7;
+      cnt++;
+    }
+    ident++;
+  }
+  *octets_needed = cnt;
+}
+
+/**
+ * Encodes ASN type field into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode value into
+ * @param ofs points to the offset within the pbuf chain
+ * @param type input ASN1 type
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ */
+err_t
+snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+      *msg_ptr = type;
+      return ERR_OK;
+    }
+    p = p->next;
+  }
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+/**
+ * Encodes host order length field into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode length into
+ * @param ofs points to the offset within the pbuf chain
+ * @param length is the host order length to be encoded
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ */
+err_t
+snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+
+      if (length < 0x80)
+      {
+        *msg_ptr = (u8_t)length;
+        return ERR_OK;
+      }
+      else if (length < 0x100)
+      {
+        *msg_ptr = 0x81;
+        ofs += 1;
+        if (ofs >= plen)
+        {
+          /* next octet in next pbuf */
+          p = p->next;
+          if (p == NULL) { return ERR_ARG; }
+          msg_ptr = (u8_t*)p->payload;
+        }
+        else
+        {
+          /* next octet in same pbuf */
+          msg_ptr++;
+        }
+        *msg_ptr = (u8_t)length;
+        return ERR_OK;
+      }
+      else
+      {
+        u8_t i;
+
+        /* length >= 0x100 && length <= 0xFFFF */
+        *msg_ptr = 0x82;
+        i = 2;
+        while (i > 0)
+        {
+          i--;
+          ofs += 1;
+          if (ofs >= plen)
+          {
+            /* next octet in next pbuf */
+            p = p->next;
+            if (p == NULL) { return ERR_ARG; }
+            msg_ptr = (u8_t*)p->payload;
+            plen += p->len;
+          }
+          else
+          {
+            /* next octet in same pbuf */
+            msg_ptr++;
+          }
+          if (i == 0)
+          {
+            /* least significant length octet */
+            *msg_ptr = (u8_t)length;
+          }
+          else
+          {
+            /* most significant length octet */
+            *msg_ptr = (u8_t)(length >> 8);
+          }
+        }
+        return ERR_OK;
+      }
+    }
+    p = p->next;
+  }
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+/**
+ * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode value into
+ * @param ofs points to the offset within the pbuf chain
+ * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
+ * @param value is the host order u32_t value to be encoded
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ *
+ * @see snmp_asn1_enc_u32t_cnt()
+ */
+err_t
+snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+
+      if (octets_needed == 5)
+      {
+        /* not enough bits in 'value' add leading 0x00 */
+        octets_needed--;
+        *msg_ptr = 0x00;
+        ofs += 1;
+        if (ofs >= plen)
+        {
+          /* next octet in next pbuf */
+          p = p->next;
+          if (p == NULL) { return ERR_ARG; }
+          msg_ptr = (u8_t*)p->payload;
+          plen += p->len;
+        }
+        else
+        {
+          /* next octet in same pbuf */
+          msg_ptr++;
+        }
+      }
+      while (octets_needed > 1)
+      {
+        octets_needed--;
+        *msg_ptr = (u8_t)(value >> (octets_needed << 3));
+        ofs += 1;
+        if (ofs >= plen)
+        {
+          /* next octet in next pbuf */
+          p = p->next;
+          if (p == NULL) { return ERR_ARG; }
+          msg_ptr = (u8_t*)p->payload;
+          plen += p->len;
+        }
+        else
+        {
+          /* next octet in same pbuf */
+          msg_ptr++;
+        }
+      }
+      /* (only) one least significant octet */
+      *msg_ptr = (u8_t)value;
+      return ERR_OK;
+    }
+    p = p->next;
+  }
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+/**
+ * Encodes s32_t integer into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode value into
+ * @param ofs points to the offset within the pbuf chain
+ * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
+ * @param value is the host order s32_t value to be encoded
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ *
+ * @see snmp_asn1_enc_s32t_cnt()
+ */
+err_t
+snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+
+      while (octets_needed > 1)
+      {
+        octets_needed--;
+        *msg_ptr = (u8_t)(value >> (octets_needed << 3));
+        ofs += 1;
+        if (ofs >= plen)
+        {
+          /* next octet in next pbuf */
+          p = p->next;
+          if (p == NULL) { return ERR_ARG; }
+          msg_ptr = (u8_t*)p->payload;
+          plen += p->len;
+        }
+        else
+        {
+          /* next octet in same pbuf */
+          msg_ptr++;
+        }
+      }
+      /* (only) one least significant octet */
+      *msg_ptr = (u8_t)value;
+      return ERR_OK;
+    }
+    p = p->next;
+  }
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+/**
+ * Encodes object identifier into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode oid into
+ * @param ofs points to the offset within the pbuf chain
+ * @param ident_len object identifier array length
+ * @param ident points to object identifier array
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ */
+err_t
+snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+
+      if (ident_len > 1)
+      {
+        if ((ident[0] == 1) && (ident[1] == 3))
+        {
+          /* compressed (most common) prefix .iso.org */
+          *msg_ptr = 0x2b;
+        }
+        else
+        {
+          /* calculate prefix */
+          *msg_ptr = (u8_t)((ident[0] * 40) + ident[1]);
+        }
+        ofs += 1;
+        if (ofs >= plen)
+        {
+          /* next octet in next pbuf */
+          p = p->next;
+          if (p == NULL) { return ERR_ARG; }
+          msg_ptr = (u8_t*)p->payload;
+          plen += p->len;
+        }
+        else
+        {
+          /* next octet in same pbuf */
+          msg_ptr++;
+        }
+        ident_len -= 2;
+        ident += 2;
+      }
+      else
+      {
+/* @bug:  allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression??  */
+        /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
+        return ERR_ARG;
+      }
+      while (ident_len > 0)
+      {
+        s32_t sub_id;
+        u8_t shift, tail;
+
+        ident_len--;
+        sub_id = *ident;
+        tail = 0;
+        shift = 28;
+        while(shift > 0)
+        {
+          u8_t code;
+
+          code = (u8_t)(sub_id >> shift);
+          if ((code != 0) || (tail != 0))
+          {
+            tail = 1;
+            *msg_ptr = code | 0x80;
+            ofs += 1;
+            if (ofs >= plen)
+            {
+              /* next octet in next pbuf */
+              p = p->next;
+              if (p == NULL) { return ERR_ARG; }
+              msg_ptr = (u8_t*)p->payload;
+              plen += p->len;
+            }
+            else
+            {
+              /* next octet in same pbuf */
+              msg_ptr++;
+            }
+          }
+          shift -= 7;
+        }
+        *msg_ptr = (u8_t)sub_id & 0x7F;
+        if (ident_len > 0)
+        {
+          ofs += 1;
+          if (ofs >= plen)
+          {
+            /* next octet in next pbuf */
+            p = p->next;
+            if (p == NULL) { return ERR_ARG; }
+            msg_ptr = (u8_t*)p->payload;
+            plen += p->len;
+          }
+          else
+          {
+            /* next octet in same pbuf */
+            msg_ptr++;
+          }
+        }
+        /* proceed to next sub-identifier */
+        ident++;
+      }
+      return ERR_OK;
+    }
+    p = p->next;
+  }
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+/**
+ * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
+ *
+ * @param p points to output pbuf to encode raw data into
+ * @param ofs points to the offset within the pbuf chain
+ * @param raw_len raw data length
+ * @param raw points raw data
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
+ */
+err_t
+snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw)
+{
+  u16_t plen, base;
+  u8_t *msg_ptr;
+
+  plen = 0;
+  while (p != NULL)
+  {
+    base = plen;
+    plen += p->len;
+    if (ofs < plen)
+    {
+      msg_ptr = (u8_t*)p->payload;
+      msg_ptr += ofs - base;
+
+      while (raw_len > 1)
+      {
+        /* copy raw_len - 1 octets */
+        raw_len--;
+        *msg_ptr = *raw;
+        raw++;
+        ofs += 1;
+        if (ofs >= plen)
+        {
+          /* next octet in next pbuf */
+          p = p->next;
+          if (p == NULL) { return ERR_ARG; }
+          msg_ptr = (u8_t*)p->payload;
+          plen += p->len;
+        }
+        else
+        {
+          /* next octet in same pbuf */
+          msg_ptr++;
+        }
+      }
+      if (raw_len > 0)
+      {
+        /* copy last or single octet */
+        *msg_ptr = *raw;
+      }
+      return ERR_OK;
+    }
+    p = p->next;
+  }
+  /* p == NULL, ofs >= plen */
+  return ERR_ARG;
+}
+
+#endif /* LWIP_SNMP */
diff -r 000000000000 -r 350011bf8be7 lwip/core/snmp/mib2.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/snmp/mib2.c	Tue Nov 23 14:15:36 2010 +0000
@@ -0,0 +1,4144 @@
+/**
+ * @file
+ * Management Information Base II (RFC1213) objects and functions.
+ *
+ * @note the object identifiers for this MIB-2 and private MIB tree
+ * must be kept in sorted ascending order. This to ensure correct getnext operation.
+ */
+
+/*
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
+ * 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: Christiaan Simons <christiaan.simons@axon.tv>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/snmp.h"
+#include "lwip/netif.h"
+#include "lwip/ip.h"
+#include "lwip/ip_frag.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/udp.h"
+#include "lwip/snmp_asn1.h"
+#include "lwip/snmp_structs.h"
+#include "netif/etharp.h"
+
+/**
+ * IANA assigned enterprise ID for lwIP is 26381
+ * @see http://www.iana.org/assignments/enterprise-numbers
+ *
+ * @note this enterprise ID is assigned to the lwIP project,
+ * all object identifiers living under this ID are assigned
+ * by the lwIP maintainers (contact Christiaan Simons)!
+ * @note don't change this define, use snmp_set_sysobjid()
+ *
+ * If you need to create your own private MIB you'll need
+ * to apply for your own enterprise ID with IANA:
+ * http://www.iana.org/numbers.html
+ */
+#define SNMP_ENTERPRISE_ID 26381
+#define SNMP_SYSOBJID_LEN 7
+#define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID}
+
+#ifndef SNMP_SYSSERVICES
+#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2))
+#endif
+
+#ifndef SNMP_GET_SYSUPTIME
+#define SNMP_GET_SYSUPTIME(sysuptime)
+#endif
+
+static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void system_get_value(struct obj_def *od, u16_t len, void *value);
+static u8_t system_set_test(struct obj_def *od, u16_t len, void *value);
+static void system_set_value(struct obj_def *od, u16_t len, void *value);
+static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void interfaces_get_value(struct obj_def *od, u16_t len, void *value);
+static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void ifentry_get_value(struct obj_def *od, u16_t len, void *value);
+#if !SNMP_SAFE_REQUESTS
+static u8_t ifentry_set_test (struct obj_def *od, u16_t len, void *value);
+static void ifentry_set_value (struct obj_def *od, u16_t len, void *value);
+#endif /* SNMP_SAFE_REQUESTS */
+static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void atentry_get_value(struct obj_def *od, u16_t len, void *value);
+static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void ip_get_value(struct obj_def *od, u16_t len, void *value);
+static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value);
+static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value);
+static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value);
+static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value);
+static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void icmp_get_value(struct obj_def *od, u16_t len, void *value);
+#if LWIP_TCP
+static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void tcp_get_value(struct obj_def *od, u16_t len, void *value);
+#ifdef THIS_SEEMS_UNUSED
+static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value);
+#endif
+#endif
+static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void udp_get_value(struct obj_def *od, u16_t len, void *value);
+static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void udpentry_get_value(struct obj_def *od, u16_t len, void *value);
+static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void snmp_get_value(struct obj_def *od, u16_t len, void *value);
+static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value);
+static void snmp_set_value(struct obj_def *od, u16_t len, void *value);
+
+
+/* snmp .1.3.6.1.2.1.11 */
+const mib_scalar_node snmp_scalar = {
+  &snmp_get_object_def,
+  &snmp_get_value,
+  &snmp_set_test,
+  &snmp_set_value,
+  MIB_NODE_SC,
+  0
+};
+const s32_t snmp_ids[28] = {
+  1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+  17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30
+};
+struct mib_node* const snmp_nodes[28] = {
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar,
+  (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar
+};
+const struct mib_array_node snmp = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  28,
+  snmp_ids,
+  snmp_nodes
+};
+
+/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */
+/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */
+/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */
+
+/* udp .1.3.6.1.2.1.7 */
+/** index root node for udpTable */
+struct mib_list_rootnode udp_root = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_LR,
+  0,
+  NULL,
+  NULL,
+  0
+};
+const s32_t udpentry_ids[2] = { 1, 2 };
+struct mib_node* const udpentry_nodes[2] = {
+  (struct mib_node*)&udp_root, (struct mib_node*)&udp_root,
+};
+const struct mib_array_node udpentry = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  2,
+  udpentry_ids,
+  udpentry_nodes
+};
+
+s32_t udptable_id = 1;
+struct mib_node* udptable_node = (struct mib_node*)&udpentry;
+struct mib_ram_array_node udptable = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_RA,
+  0,
+  &udptable_id,
+  &udptable_node
+};
+
+const mib_scalar_node udp_scalar = {
+  &udp_get_object_def,
+  &udp_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_SC,
+  0
+};
+const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 };
+struct mib_node* const udp_nodes[5] = {
+  (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar,
+  (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar,
+  (struct mib_node*)&udptable
+};
+const struct mib_array_node udp = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  5,
+  udp_ids,
+  udp_nodes
+};
+
+/* tcp .1.3.6.1.2.1.6 */
+#if LWIP_TCP
+/* only if the TCP protocol is available may implement this group */
+/** index root node for tcpConnTable */
+struct mib_list_rootnode tcpconntree_root = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_LR,
+  0,
+  NULL,
+  NULL,
+  0
+};
+const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 };
+struct mib_node* const tcpconnentry_nodes[5] = {
+  (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root,
+  (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root,
+  (struct mib_node*)&tcpconntree_root
+};
+const struct mib_array_node tcpconnentry = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  5,
+  tcpconnentry_ids,
+  tcpconnentry_nodes
+};
+
+s32_t tcpconntable_id = 1;
+struct mib_node* tcpconntable_node = (struct mib_node*)&tcpconnentry;
+struct mib_ram_array_node tcpconntable = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_RA,
+/** @todo update maxlength when inserting / deleting from table
+   0 when table is empty, 1 when more than one entry */
+  0,
+  &tcpconntable_id,
+  &tcpconntable_node
+};
+
+const mib_scalar_node tcp_scalar = {
+  &tcp_get_object_def,
+  &tcp_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_SC,
+  0
+};
+const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+struct mib_node* const tcp_nodes[15] = {
+  (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+  (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+  (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+  (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+  (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+  (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar,
+  (struct mib_node*)&tcpconntable, (struct mib_node*)&tcp_scalar,
+  (struct mib_node*)&tcp_scalar
+};
+const struct mib_array_node tcp = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  15,
+  tcp_ids,
+  tcp_nodes
+};
+#endif
+
+/* icmp .1.3.6.1.2.1.5 */
+const mib_scalar_node icmp_scalar = {
+  &icmp_get_object_def,
+  &icmp_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_SC,
+  0
+};
+const s32_t icmp_ids[26] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
+struct mib_node* const icmp_nodes[26] = {
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar,
+  (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar
+};
+const struct mib_array_node icmp = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  26,
+  icmp_ids,
+  icmp_nodes
+};
+
+/** index root node for ipNetToMediaTable */
+struct mib_list_rootnode ipntomtree_root = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_LR,
+  0,
+  NULL,
+  NULL,
+  0
+};
+const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 };
+struct mib_node* const ipntomentry_nodes[4] = {
+  (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root,
+  (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root
+};
+const struct mib_array_node ipntomentry = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  4,
+  ipntomentry_ids,
+  ipntomentry_nodes
+};
+
+s32_t ipntomtable_id = 1;
+struct mib_node* ipntomtable_node = (struct mib_node*)&ipntomentry;
+struct mib_ram_array_node ipntomtable = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_RA,
+  0,
+  &ipntomtable_id,
+  &ipntomtable_node
+};
+
+/** index root node for ipRouteTable */
+struct mib_list_rootnode iprtetree_root = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_LR,
+  0,
+  NULL,
+  NULL,
+  0
+};
+const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
+struct mib_node* const iprteentry_nodes[13] = {
+  (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+  (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+  (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+  (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+  (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+  (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root,
+  (struct mib_node*)&iprtetree_root
+};
+const struct mib_array_node iprteentry = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  13,
+  iprteentry_ids,
+  iprteentry_nodes
+};
+
+s32_t iprtetable_id = 1;
+struct mib_node* iprtetable_node = (struct mib_node*)&iprteentry;
+struct mib_ram_array_node iprtetable = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_RA,
+  0,
+  &iprtetable_id,
+  &iprtetable_node
+};
+
+/** index root node for ipAddrTable */
+struct mib_list_rootnode ipaddrtree_root = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_LR,
+  0,
+  NULL,
+  NULL,
+  0
+};
+const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 };
+struct mib_node* const ipaddrentry_nodes[5] = {
+  (struct mib_node*)&ipaddrtree_root,
+  (struct mib_node*)&ipaddrtree_root,
+  (struct mib_node*)&ipaddrtree_root,
+  (struct mib_node*)&ipaddrtree_root,
+  (struct mib_node*)&ipaddrtree_root
+};
+const struct mib_array_node ipaddrentry = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  5,
+  ipaddrentry_ids,
+  ipaddrentry_nodes
+};
+
+s32_t ipaddrtable_id = 1;
+struct mib_node* ipaddrtable_node = (struct mib_node*)&ipaddrentry;
+struct mib_ram_array_node ipaddrtable = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_RA,
+  0,
+  &ipaddrtable_id,
+  &ipaddrtable_node
+};
+
+/* ip .1.3.6.1.2.1.4 */
+const mib_scalar_node ip_scalar = {
+  &ip_get_object_def,
+  &ip_get_value,
+  &ip_set_test,
+  &noleafs_set_value,
+  MIB_NODE_SC,
+  0
+};
+const s32_t ip_ids[23] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
+struct mib_node* const ip_nodes[23] = {
+  (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+  (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+  (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+  (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+  (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+  (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+  (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+  (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+  (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar,
+  (struct mib_node*)&ip_scalar, (struct mib_node*)&ipaddrtable,
+  (struct mib_node*)&iprtetable, (struct mib_node*)&ipntomtable,
+  (struct mib_node*)&ip_scalar
+};
+const struct mib_array_node mib2_ip = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  23,
+  ip_ids,
+  ip_nodes
+};
+
+/** index root node for atTable */
+struct mib_list_rootnode arptree_root = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_LR,
+  0,
+  NULL,
+  NULL,
+  0
+};
+const s32_t atentry_ids[3] = { 1, 2, 3 };
+struct mib_node* const atentry_nodes[3] = {
+  (struct mib_node*)&arptree_root,
+  (struct mib_node*)&arptree_root,
+  (struct mib_node*)&arptree_root
+};
+const struct mib_array_node atentry = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  3,
+  atentry_ids,
+  atentry_nodes
+};
+
+const s32_t attable_id = 1;
+struct mib_node* const attable_node = (struct mib_node*)&atentry;
+const struct mib_array_node attable = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  1,
+  &attable_id,
+  &attable_node
+};
+
+/* at .1.3.6.1.2.1.3 */
+s32_t at_id = 1;
+struct mib_node* mib2_at_node = (struct mib_node*)&attable;
+struct mib_ram_array_node at = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_RA,
+  0,
+  &at_id,
+  &mib2_at_node
+};
+
+/** index root node for ifTable */
+struct mib_list_rootnode iflist_root = {
+  &ifentry_get_object_def,
+  &ifentry_get_value,
+#if SNMP_SAFE_REQUESTS
+  &noleafs_set_test,
+  &noleafs_set_value,
+#else /* SNMP_SAFE_REQUESTS */
+  &ifentry_set_test,
+  &ifentry_set_value,
+#endif /* SNMP_SAFE_REQUESTS */
+  MIB_NODE_LR,
+  0,
+  NULL,
+  NULL,
+  0
+};
+const s32_t ifentry_ids[22] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 };
+struct mib_node* const ifentry_nodes[22] = {
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root,
+  (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root
+};
+const struct mib_array_node ifentry = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  22,
+  ifentry_ids,
+  ifentry_nodes
+};
+
+s32_t iftable_id = 1;
+struct mib_node* iftable_node = (struct mib_node*)&ifentry;
+struct mib_ram_array_node iftable = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_RA,
+  0,
+  &iftable_id,
+  &iftable_node
+};
+
+/* interfaces .1.3.6.1.2.1.2 */
+const mib_scalar_node interfaces_scalar = {
+  &interfaces_get_object_def,
+  &interfaces_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_SC,
+  0
+};
+const s32_t interfaces_ids[2] = { 1, 2 };
+struct mib_node* const interfaces_nodes[2] = {
+  (struct mib_node*)&interfaces_scalar, (struct mib_node*)&iftable
+};
+const struct mib_array_node interfaces = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  2,
+  interfaces_ids,
+  interfaces_nodes
+};
+
+
+/*             0 1 2 3 4 5 6 */
+/* system .1.3.6.1.2.1.1 */
+const mib_scalar_node sys_tem_scalar = {
+  &system_get_object_def,
+  &system_get_value,
+  &system_set_test,
+  &system_set_value,
+  MIB_NODE_SC,
+  0
+};
+const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 };
+struct mib_node* const sys_tem_nodes[7] = {
+  (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar,
+  (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar,
+  (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar,
+  (struct mib_node*)&sys_tem_scalar
+};
+/* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */
+const struct mib_array_node sys_tem = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  7,
+  sys_tem_ids,
+  sys_tem_nodes
+};
+
+/* mib-2 .1.3.6.1.2.1 */
+#if LWIP_TCP
+#define MIB2_GROUPS 8
+#else
+#define MIB2_GROUPS 7
+#endif
+const s32_t mib2_ids[MIB2_GROUPS] =
+{
+  1,
+  2,
+  3,
+  4,
+  5,
+#if LWIP_TCP
+  6,
+#endif
+  7,
+  11
+};
+struct mib_node* const mib2_nodes[MIB2_GROUPS] = {
+  (struct mib_node*)&sys_tem,
+  (struct mib_node*)&interfaces,
+  (struct mib_node*)&at,
+  (struct mib_node*)&mib2_ip,
+  (struct mib_node*)&icmp,
+#if LWIP_TCP
+  (struct mib_node*)&tcp,
+#endif
+  (struct mib_node*)&udp,
+  (struct mib_node*)&snmp
+};
+
+const struct mib_array_node mib2 = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  MIB2_GROUPS,
+  mib2_ids,
+  mib2_nodes
+};
+
+/* mgmt .1.3.6.1.2 */
+const s32_t mgmt_ids[1] = { 1 };
+struct mib_node* const mgmt_nodes[1] = { (struct mib_node*)&mib2 };
+const struct mib_array_node mgmt = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  1,
+  mgmt_ids,
+  mgmt_nodes
+};
+
+/* internet .1.3.6.1 */
+#if SNMP_PRIVATE_MIB
+/* When using a private MIB, you have to create a file 'private_mib.h' that contains
+ * a 'struct mib_array_node mib_private' which contains your MIB. */
+s32_t internet_ids[2] = { 2, 4 };
+struct mib_node* const internet_nodes[2] = { (struct mib_node*)&mgmt, (struct mib_node*)&mib_private };
+const struct mib_array_node internet = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  2,
+  internet_ids,
+  internet_nodes
+};
+#else
+const s32_t internet_ids[1] = { 2 };
+struct mib_node* const internet_nodes[1] = { (struct mib_node*)&mgmt };
+const struct mib_array_node internet = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  1,
+  internet_ids,
+  internet_nodes
+};
+#endif
+
+/** mib-2.system.sysObjectID  */
+static struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID};
+/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */
+static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}};
+/** mib-2.system.sysServices */
+static const s32_t sysservices = SNMP_SYSSERVICES;
+
+/** mib-2.system.sysDescr */
+static const u8_t sysdescr_len_default = 4;
+static const u8_t sysdescr_default[] = "lwIP";
+static u8_t* sysdescr_len_ptr = (u8_t*)&sysdescr_len_default;
+static u8_t* sysdescr_ptr = (u8_t*)&sysdescr_default[0];
+/** mib-2.system.sysContact */
+static const u8_t syscontact_len_default = 0;
+static const u8_t syscontact_default[] = "";
+static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default;
+static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0];
+/** mib-2.system.sysName */
+static const u8_t sysname_len_default = 8;
+static const u8_t sysname_default[] = "FQDN-unk";
+static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default;
+static u8_t* sysname_ptr = (u8_t*)&sysname_default[0];
+/** mib-2.system.sysLocation */
+static const u8_t syslocation_len_default = 0;
+static const u8_t syslocation_default[] = "";
+static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default;
+static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0];
+/** mib-2.snmp.snmpEnableAuthenTraps */
+static const u8_t snmpenableauthentraps_default = 2; /* disabled */
+static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default;
+
+/** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */
+static const struct snmp_obj_id ifspecific = {2, {0, 0}};
+/** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */
+static const struct snmp_obj_id iprouteinfo = {2, {0, 0}};
+
+
+
+/* mib-2.system counter(s) */
+static u32_t sysuptime = 0;
+
+/* mib-2.ip counter(s) */
+static u32_t ipinreceives = 0,
+             ipinhdrerrors = 0,
+             ipinaddrerrors = 0,
+             ipforwdatagrams = 0,
+             ipinunknownprotos = 0,
+             ipindiscards = 0,
+             ipindelivers = 0,
+             ipoutrequests = 0,
+             ipoutdiscards = 0,
+             ipoutnoroutes = 0,
+             ipreasmreqds = 0,
+             ipreasmoks = 0,
+             ipreasmfails = 0,
+             ipfragoks = 0,
+             ipfragfails = 0,
+             ipfragcreates = 0,
+             iproutingdiscards = 0;
+/* mib-2.icmp counter(s) */
+static u32_t icmpinmsgs = 0,
+             icmpinerrors = 0,
+             icmpindestunreachs = 0,
+             icmpintimeexcds = 0,
+             icmpinparmprobs = 0,
+             icmpinsrcquenchs = 0,
+             icmpinredirects = 0,
+             icmpinechos = 0,
+             icmpinechoreps = 0,
+             icmpintimestamps = 0,
+             icmpintimestampreps = 0,
+             icmpinaddrmasks = 0,
+             icmpinaddrmaskreps = 0,
+             icmpoutmsgs = 0,
+             icmpouterrors = 0,
+             icmpoutdestunreachs = 0,
+             icmpouttimeexcds = 0,
+             icmpoutparmprobs = 0,
+             icmpoutsrcquenchs = 0,
+             icmpoutredirects = 0,
+             icmpoutechos = 0,
+             icmpoutechoreps = 0,
+             icmpouttimestamps = 0,
+             icmpouttimestampreps = 0,
+             icmpoutaddrmasks = 0,
+             icmpoutaddrmaskreps = 0;
+/* mib-2.tcp counter(s) */
+static u32_t tcpactiveopens = 0,
+             tcppassiveopens = 0,
+             tcpattemptfails = 0,
+             tcpestabresets = 0,
+             tcpinsegs = 0,
+             tcpoutsegs = 0,
+             tcpretranssegs = 0,
+             tcpinerrs = 0,
+             tcpoutrsts = 0;
+/* mib-2.udp counter(s) */
+static u32_t udpindatagrams = 0,
+             udpnoports = 0,
+             udpinerrors = 0,
+             udpoutdatagrams = 0;
+/* mib-2.snmp counter(s) */
+static u32_t snmpinpkts = 0,
+             snmpoutpkts = 0,
+             snmpinbadversions = 0,
+             snmpinbadcommunitynames = 0,
+             snmpinbadcommunityuses = 0,
+             snmpinasnparseerrs = 0,
+             snmpintoobigs = 0,
+             snmpinnosuchnames = 0,
+             snmpinbadvalues = 0,
+             snmpinreadonlys = 0,
+             snmpingenerrs = 0,
+             snmpintotalreqvars = 0,
+             snmpintotalsetvars = 0,
+             snmpingetrequests = 0,
+             snmpingetnexts = 0,
+             snmpinsetrequests = 0,
+             snmpingetresponses = 0,
+             snmpintraps = 0,
+             snmpouttoobigs = 0,
+             snmpoutnosuchnames = 0,
+             snmpoutbadvalues = 0,
+             snmpoutgenerrs = 0,
+             snmpoutgetrequests = 0,
+             snmpoutgetnexts = 0,
+             snmpoutsetrequests = 0,
+             snmpoutgetresponses = 0,
+             snmpouttraps = 0;
+
+
+
+/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */
+/**
+ * Copy octet string.
+ *
+ * @param dst points to destination
+ * @param src points to source
+ * @param n number of octets to copy.
+ */
+static void ocstrncpy(u8_t *dst, u8_t *src, u16_t n)
+{
+  u16_t i = n;
+  while (i > 0) {
+    i--;
+    *dst++ = *src++;
+  }
+}
+
+/**
+ * Copy object identifier (s32_t) array.
+ *
+ * @param dst points to destination
+ * @param src points to source
+ * @param n number of sub identifiers to copy.
+ */
+void objectidncpy(s32_t *dst, s32_t *src, u8_t n)
+{
+  u8_t i = n;
+  while(i > 0) {
+    i--;
+    *dst++ = *src++;
+  }
+}
+
+/**
+ * Initializes sysDescr pointers.
+ *
+ * @param str if non-NULL then copy str pointer
+ * @param len points to string length, excluding zero terminator
+ */
+void snmp_set_sysdesr(u8_t *str, u8_t *len)
+{
+  if (str != NULL)
+  {
+    sysdescr_ptr = str;
+    sysdescr_len_ptr = len;
+  }
+}
+
+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid)
+{
+  *oid = &sysobjid;
+}
+
+/**
+ * Initializes sysObjectID value.
+ *
+ * @param oid points to stuct snmp_obj_id to copy
+ */
+void snmp_set_sysobjid(struct snmp_obj_id *oid)
+{
+  sysobjid = *oid;
+}
+
+/**
+ * Must be called at regular 10 msec interval from a timer interrupt
+ * or signal handler depending on your runtime environment.
+ */
+void snmp_inc_sysuptime(void)
+{
+  sysuptime++;
+}
+
+void snmp_add_sysuptime(u32_t value)
+{
+  sysuptime+=value;
+}
+
+void snmp_get_sysuptime(u32_t *value)
+{
+  SNMP_GET_SYSUPTIME(sysuptime);
+  *value = sysuptime;
+}
+
+/**
+ * Initializes sysContact pointers,
+ * e.g. ptrs to non-volatile memory external to lwIP.
+ *
+ * @param ocstr if non-NULL then copy str pointer
+ * @param ocstrlen points to string length, excluding zero terminator
+ */
+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen)
+{
+  if (ocstr != NULL)
+  {
+    syscontact_ptr = ocstr;
+    syscontact_len_ptr = ocstrlen;
+  }
+}
+
+/**
+ * Initializes sysName pointers,
+ * e.g. ptrs to non-volatile memory external to lwIP.
+ *
+ * @param ocstr if non-NULL then copy str pointer
+ * @param ocstrlen points to string length, excluding zero terminator
+ */
+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen)
+{
+  if (ocstr != NULL)
+  {
+    sysname_ptr = ocstr;
+    sysname_len_ptr = ocstrlen;
+  }
+}
+
+/**
+ * Initializes sysLocation pointers,
+ * e.g. ptrs to non-volatile memory external to lwIP.
+ *
+ * @param ocstr if non-NULL then copy str pointer
+ * @param ocstrlen points to string length, excluding zero terminator
+ */
+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen)
+{
+  if (ocstr != NULL)
+  {
+    syslocation_ptr = ocstr;
+    syslocation_len_ptr = ocstrlen;
+  }
+}
+
+
+void snmp_add_ifinoctets(struct netif *ni, u32_t value)
+{
+  ni->ifinoctets += value;
+}
+
+void snmp_inc_ifinucastpkts(struct netif *ni)
+{
+  (ni->ifinucastpkts)++;
+}
+
+void snmp_inc_ifinnucastpkts(struct netif *ni)
+{
+  (ni->ifinnucastpkts)++;
+}
+
+void snmp_inc_ifindiscards(struct netif *ni)
+{
+  (ni->ifindiscards)++;
+}
+
+void snmp_add_ifoutoctets(struct netif *ni, u32_t value)
+{
+  ni->ifoutoctets += value;
+}
+
+void snmp_inc_ifoutucastpkts(struct netif *ni)
+{
+  (ni->ifoutucastpkts)++;
+}
+
+void snmp_inc_ifoutnucastpkts(struct netif *ni)
+{
+  (ni->ifoutnucastpkts)++;
+}
+
+void snmp_inc_ifoutdiscards(struct netif *ni)
+{
+  (ni->ifoutdiscards)++;
+}
+
+void snmp_inc_iflist(void)
+{
+  struct mib_list_node *if_node = NULL;
+
+  snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node);
+  /* enable getnext traversal on filled table */
+  iftable.maxlength = 1;
+}
+
+void snmp_dec_iflist(void)
+{
+  snmp_mib_node_delete(&iflist_root, iflist_root.tail);
+  /* disable getnext traversal on empty table */
+  if(iflist_root.count == 0) iftable.maxlength = 0;
+}
+
+/**
+ * Inserts ARP table indexes (.xIfIndex.xNetAddress)
+ * into arp table index trees (both atTable and ipNetToMediaTable).
+ */
+void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip)
+{
+  struct mib_list_rootnode *at_rn;
+  struct mib_list_node *at_node;
+  s32_t arpidx[5];
+  u8_t level, tree;
+
+  LWIP_ASSERT("ni != NULL", ni != NULL);
+  snmp_netiftoifindex(ni, &arpidx[0]);
+  snmp_iptooid(ip, &arpidx[1]);
+
+  for (tree = 0; tree < 2; tree++)
+  {
+    if (tree == 0)
+    {
+      at_rn = &arptree_root;
+    }
+    else
+    {
+      at_rn = &ipntomtree_root;
+    }
+    for (level = 0; level < 5; level++)
+    {
+      at_node = NULL;
+      snmp_mib_node_insert(at_rn, arpidx[level], &at_node);
+      if ((level != 4) && (at_node != NULL))
+      {
+        if (at_node->nptr == NULL)
+        {
+          at_rn = snmp_mib_lrn_alloc();
+          at_node->nptr = (struct mib_node*)at_rn;
+          if (at_rn != NULL)
+          {
+            if (level == 3)
+            {
+              if (tree == 0)
+              {
+                at_rn->get_object_def = atentry_get_object_def;
+                at_rn->get_value = atentry_get_value;
+              }
+              else
+              {
+                at_rn->get_object_def = ip_ntomentry_get_object_def;
+                at_rn->get_value = ip_ntomentry_get_value;
+              }
+              at_rn->set_test = noleafs_set_test;
+              at_rn->set_value = noleafs_set_value;
+            }
+          }
+          else
+          {
+            /* at_rn == NULL, malloc failure */
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full"));
+            break;
+          }
+        }
+        else
+        {
+          at_rn = (struct mib_list_rootnode*)at_node->nptr;
+        }
+      }
+    }
+  }
+  /* enable getnext traversal on filled tables */
+  at.maxlength = 1;
+  ipntomtable.maxlength = 1;
+}
+
+/**
+ * Removes ARP table indexes (.xIfIndex.xNetAddress)
+ * from arp table index trees.
+ */
+void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip)
+{
+  struct mib_list_rootnode *at_rn, *next, *del_rn[5];
+  struct mib_list_node *at_n, *del_n[5];
+  s32_t arpidx[5];
+  u8_t fc, tree, level, del_cnt;
+
+  snmp_netiftoifindex(ni, &arpidx[0]);
+  snmp_iptooid(ip, &arpidx[1]);
+
+  for (tree = 0; tree < 2; tree++)
+  {
+    /* mark nodes for deletion */
+    if (tree == 0)
+    {
+      at_rn = &arptree_root;
+    }
+    else
+    {
+      at_rn = &ipntomtree_root;
+    }
+    level = 0;
+    del_cnt = 0;
+    while ((level < 5) && (at_rn != NULL))
+    {
+      fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n);
+      if (fc == 0)
+      {
+        /* arpidx[level] does not exist */
+        del_cnt = 0;
+        at_rn = NULL;
+      }
+      else if (fc == 1)
+      {
+        del_rn[del_cnt] = at_rn;
+        del_n[del_cnt] = at_n;
+        del_cnt++;
+        at_rn = (struct mib_list_rootnode*)(at_n->nptr);
+      }
+      else if (fc == 2)
+      {
+        /* reset delete (2 or more childs) */
+        del_cnt = 0;
+        at_rn = (struct mib_list_rootnode*)(at_n->nptr);
+      }
+      level++;
+    }
+    /* delete marked index nodes */
+    while (del_cnt > 0)
+    {
+      del_cnt--;
+
+      at_rn = del_rn[del_cnt];
+      at_n = del_n[del_cnt];
+
+      next = snmp_mib_node_delete(at_rn, at_n);
+      if (next != NULL)
+      {
+        LWIP_ASSERT("next_count == 0",next->count == 0);
+        snmp_mib_lrn_free(next);
+      }
+    }
+  }
+  /* disable getnext traversal on empty tables */
+  if(arptree_root.count == 0) at.maxlength = 0;
+  if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0;
+}
+
+void snmp_inc_ipinreceives(void)
+{
+  ipinreceives++;
+}
+
+void snmp_inc_ipinhdrerrors(void)
+{
+  ipinhdrerrors++;
+}
+
+void snmp_inc_ipinaddrerrors(void)
+{
+  ipinaddrerrors++;
+}
+
+void snmp_inc_ipforwdatagrams(void)
+{
+  ipforwdatagrams++;
+}
+
+void snmp_inc_ipinunknownprotos(void)
+{
+  ipinunknownprotos++;
+}
+
+void snmp_inc_ipindiscards(void)
+{
+  ipindiscards++;
+}
+
+void snmp_inc_ipindelivers(void)
+{
+  ipindelivers++;
+}
+
+void snmp_inc_ipoutrequests(void)
+{
+  ipoutrequests++;
+}
+
+void snmp_inc_ipoutdiscards(void)
+{
+  ipoutdiscards++;
+}
+
+void snmp_inc_ipoutnoroutes(void)
+{
+  ipoutnoroutes++;
+}
+
+void snmp_inc_ipreasmreqds(void)
+{
+  ipreasmreqds++;
+}
+
+void snmp_inc_ipreasmoks(void)
+{
+  ipreasmoks++;
+}
+
+void snmp_inc_ipreasmfails(void)
+{
+  ipreasmfails++;
+}
+
+void snmp_inc_ipfragoks(void)
+{
+  ipfragoks++;
+}
+
+void snmp_inc_ipfragfails(void)
+{
+  ipfragfails++;
+}
+
+void snmp_inc_ipfragcreates(void)
+{
+  ipfragcreates++;
+}
+
+void snmp_inc_iproutingdiscards(void)
+{
+  iproutingdiscards++;
+}
+
+/**
+ * Inserts ipAddrTable indexes (.ipAdEntAddr)
+ * into index tree.
+ */
+void snmp_insert_ipaddridx_tree(struct netif *ni)
+{
+  struct mib_list_rootnode *ipa_rn;
+  struct mib_list_node *ipa_node;
+  s32_t ipaddridx[4];
+  u8_t level;
+
+  LWIP_ASSERT("ni != NULL", ni != NULL);
+  snmp_iptooid(&ni->ip_addr, &ipaddridx[0]);
+
+  level = 0;
+  ipa_rn = &ipaddrtree_root;
+  while (level < 4)
+  {
+    ipa_node = NULL;
+    snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node);
+    if ((level != 3) && (ipa_node != NULL))
+    {
+      if (ipa_node->nptr == NULL)
+      {
+        ipa_rn = snmp_mib_lrn_alloc();
+        ipa_node->nptr = (struct mib_node*)ipa_rn;
+        if (ipa_rn != NULL)
+        {
+          if (level == 2)
+          {
+            ipa_rn->get_object_def = ip_addrentry_get_object_def;
+            ipa_rn->get_value = ip_addrentry_get_value;
+            ipa_rn->set_test = noleafs_set_test;
+            ipa_rn->set_value = noleafs_set_value;
+          }
+        }
+        else
+        {
+          /* ipa_rn == NULL, malloc failure */
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full"));
+          break;
+        }
+      }
+      else
+      {
+        ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr;
+      }
+    }
+    level++;
+  }
+  /* enable getnext traversal on filled table */
+  ipaddrtable.maxlength = 1;
+}
+
+/**
+ * Removes ipAddrTable indexes (.ipAdEntAddr)
+ * from index tree.
+ */
+void snmp_delete_ipaddridx_tree(struct netif *ni)
+{
+  struct mib_list_rootnode *ipa_rn, *next, *del_rn[4];
+  struct mib_list_node *ipa_n, *del_n[4];
+  s32_t ipaddridx[4];
+  u8_t fc, level, del_cnt;
+
+  LWIP_ASSERT("ni != NULL", ni != NULL);
+  snmp_iptooid(&ni->ip_addr, &ipaddridx[0]);
+
+  /* mark nodes for deletion */
+  level = 0;
+  del_cnt = 0;
+  ipa_rn = &ipaddrtree_root;
+  while ((level < 4) && (ipa_rn != NULL))
+  {
+    fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n);
+    if (fc == 0)
+    {
+      /* ipaddridx[level] does not exist */
+      del_cnt = 0;
+      ipa_rn = NULL;
+    }
+    else if (fc == 1)
+    {
+      del_rn[del_cnt] = ipa_rn;
+      del_n[del_cnt] = ipa_n;
+      del_cnt++;
+      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);
+    }
+    else if (fc == 2)
+    {
+      /* reset delete (2 or more childs) */
+      del_cnt = 0;
+      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);
+    }
+    level++;
+  }
+  /* delete marked index nodes */
+  while (del_cnt > 0)
+  {
+    del_cnt--;
+
+    ipa_rn = del_rn[del_cnt];
+    ipa_n = del_n[del_cnt];
+
+    next = snmp_mib_node_delete(ipa_rn, ipa_n);
+    if (next != NULL)
+    {
+      LWIP_ASSERT("next_count == 0",next->count == 0);
+      snmp_mib_lrn_free(next);
+    }
+  }
+  /* disable getnext traversal on empty table */
+  if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0;
+}
+
+/**
+ * Inserts ipRouteTable indexes (.ipRouteDest)
+ * into index tree.
+ *
+ * @param dflt non-zero for the default rte, zero for network rte
+ * @param ni points to network interface for this rte
+ *
+ * @todo record sysuptime for _this_ route when it is installed
+ *   (needed for ipRouteAge) in the netif.
+ */
+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni)
+{
+  u8_t insert = 0;
+  ip_addr_t dst;
+
+  if (dflt != 0)
+  {
+    /* the default route 0.0.0.0 */
+    ip_addr_set_any(&dst);
+    insert = 1;
+  }
+  else
+  {
+    /* route to the network address */
+    ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask);
+    /* exclude 0.0.0.0 network (reserved for default rte) */
+    if (!ip_addr_isany(&dst)) {
+      insert = 1;
+    }
+  }
+  if (insert)
+  {
+    struct mib_list_rootnode *iprte_rn;
+    struct mib_list_node *iprte_node;
+    s32_t iprteidx[4];
+    u8_t level;
+
+    snmp_iptooid(&dst, &iprteidx[0]);
+    level = 0;
+    iprte_rn = &iprtetree_root;
+    while (level < 4)
+    {
+      iprte_node = NULL;
+      snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node);
+      if ((level != 3) && (iprte_node != NULL))
+      {
+        if (iprte_node->nptr == NULL)
+        {
+          iprte_rn = snmp_mib_lrn_alloc();
+          iprte_node->nptr = (struct mib_node*)iprte_rn;
+          if (iprte_rn != NULL)
+          {
+            if (level == 2)
+            {
+              iprte_rn->get_object_def = ip_rteentry_get_object_def;
+              iprte_rn->get_value = ip_rteentry_get_value;
+              iprte_rn->set_test = noleafs_set_test;
+              iprte_rn->set_value = noleafs_set_value;
+            }
+          }
+          else
+          {
+            /* iprte_rn == NULL, malloc failure */
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full"));
+            break;
+          }
+        }
+        else
+        {
+          iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr;
+        }
+      }
+      level++;
+    }
+  }
+  /* enable getnext traversal on filled table */
+  iprtetable.maxlength = 1;
+}
+
+/**
+ * Removes ipRouteTable indexes (.ipRouteDest)
+ * from index tree.
+ *
+ * @param dflt non-zero for the default rte, zero for network rte
+ * @param ni points to network interface for this rte or NULL
+ *   for default route to be removed.
+ */
+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni)
+{
+  u8_t del = 0;
+  ip_addr_t dst;
+
+  if (dflt != 0)
+  {
+    /* the default route 0.0.0.0 */
+    ip_addr_set_any(&dst);
+    del = 1;
+  }
+  else
+  {
+    /* route to the network address */
+    ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask);
+    /* exclude 0.0.0.0 network (reserved for default rte) */
+    if (!ip_addr_isany(&dst)) {
+      del = 1;
+    }
+  }
+  if (del)
+  {
+    struct mib_list_rootnode *iprte_rn, *next, *del_rn[4];
+    struct mib_list_node *iprte_n, *del_n[4];
+    s32_t iprteidx[4];
+    u8_t fc, level, del_cnt;
+
+    snmp_iptooid(&dst, &iprteidx[0]);
+    /* mark nodes for deletion */
+    level = 0;
+    del_cnt = 0;
+    iprte_rn = &iprtetree_root;
+    while ((level < 4) && (iprte_rn != NULL))
+    {
+      fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n);
+      if (fc == 0)
+      {
+        /* iprteidx[level] does not exist */
+        del_cnt = 0;
+        iprte_rn = NULL;
+      }
+      else if (fc == 1)
+      {
+        del_rn[del_cnt] = iprte_rn;
+        del_n[del_cnt] = iprte_n;
+        del_cnt++;
+        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);
+      }
+      else if (fc == 2)
+      {
+        /* reset delete (2 or more childs) */
+        del_cnt = 0;
+        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);
+      }
+      level++;
+    }
+    /* delete marked index nodes */
+    while (del_cnt > 0)
+    {
+      del_cnt--;
+
+      iprte_rn = del_rn[del_cnt];
+      iprte_n = del_n[del_cnt];
+
+      next = snmp_mib_node_delete(iprte_rn, iprte_n);
+      if (next != NULL)
+      {
+        LWIP_ASSERT("next_count == 0",next->count == 0);
+        snmp_mib_lrn_free(next);
+      }
+    }
+  }
+  /* disable getnext traversal on empty table */
+  if (iprtetree_root.count == 0) iprtetable.maxlength = 0;
+}
+
+
+void snmp_inc_icmpinmsgs(void)
+{
+  icmpinmsgs++;
+}
+
+void snmp_inc_icmpinerrors(void)
+{
+  icmpinerrors++;
+}
+
+void snmp_inc_icmpindestunreachs(void)
+{
+  icmpindestunreachs++;
+}
+
+void snmp_inc_icmpintimeexcds(void)
+{
+  icmpintimeexcds++;
+}
+
+void snmp_inc_icmpinparmprobs(void)
+{
+  icmpinparmprobs++;
+}
+
+void snmp_inc_icmpinsrcquenchs(void)
+{
+  icmpinsrcquenchs++;
+}
+
+void snmp_inc_icmpinredirects(void)
+{
+  icmpinredirects++;
+}
+
+void snmp_inc_icmpinechos(void)
+{
+  icmpinechos++;
+}
+
+void snmp_inc_icmpinechoreps(void)
+{
+  icmpinechoreps++;
+}
+
+void snmp_inc_icmpintimestamps(void)
+{
+  icmpintimestamps++;
+}
+
+void snmp_inc_icmpintimestampreps(void)
+{
+  icmpintimestampreps++;
+}
+
+void snmp_inc_icmpinaddrmasks(void)
+{
+  icmpinaddrmasks++;
+}
+
+void snmp_inc_icmpinaddrmaskreps(void)
+{
+  icmpinaddrmaskreps++;
+}
+
+void snmp_inc_icmpoutmsgs(void)
+{
+  icmpoutmsgs++;
+}
+
+void snmp_inc_icmpouterrors(void)
+{
+  icmpouterrors++;
+}
+
+void snmp_inc_icmpoutdestunreachs(void)
+{
+  icmpoutdestunreachs++;
+}
+
+void snmp_inc_icmpouttimeexcds(void)
+{
+  icmpouttimeexcds++;
+}
+
+void snmp_inc_icmpoutparmprobs(void)
+{
+  icmpoutparmprobs++;
+}
+
+void snmp_inc_icmpoutsrcquenchs(void)
+{
+  icmpoutsrcquenchs++;
+}
+
+void snmp_inc_icmpoutredirects(void)
+{
+  icmpoutredirects++;
+}
+
+void snmp_inc_icmpoutechos(void)
+{
+  icmpoutechos++;
+}
+
+void snmp_inc_icmpoutechoreps(void)
+{
+  icmpoutechoreps++;
+}
+
+void snmp_inc_icmpouttimestamps(void)
+{
+  icmpouttimestamps++;
+}
+
+void snmp_inc_icmpouttimestampreps(void)
+{
+  icmpouttimestampreps++;
+}
+
+void snmp_inc_icmpoutaddrmasks(void)
+{
+  icmpoutaddrmasks++;
+}
+
+void snmp_inc_icmpoutaddrmaskreps(void)
+{
+  icmpoutaddrmaskreps++;
+}
+
+void snmp_inc_tcpactiveopens(void)
+{
+  tcpactiveopens++;
+}
+
+void snmp_inc_tcppassiveopens(void)
+{
+  tcppassiveopens++;
+}
+
+void snmp_inc_tcpattemptfails(void)
+{
+  tcpattemptfails++;
+}
+
+void snmp_inc_tcpestabresets(void)
+{
+  tcpestabresets++;
+}
+
+void snmp_inc_tcpinsegs(void)
+{
+  tcpinsegs++;
+}
+
+void snmp_inc_tcpoutsegs(void)
+{
+  tcpoutsegs++;
+}
+
+void snmp_inc_tcpretranssegs(void)
+{
+  tcpretranssegs++;
+}
+
+void snmp_inc_tcpinerrs(void)
+{
+  tcpinerrs++;
+}
+
+void snmp_inc_tcpoutrsts(void)
+{
+  tcpoutrsts++;
+}
+
+void snmp_inc_udpindatagrams(void)
+{
+  udpindatagrams++;
+}
+
+void snmp_inc_udpnoports(void)
+{
+  udpnoports++;
+}
+
+void snmp_inc_udpinerrors(void)
+{
+  udpinerrors++;
+}
+
+void snmp_inc_udpoutdatagrams(void)
+{
+  udpoutdatagrams++;
+}
+
+/**
+ * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort)
+ * into index tree.
+ */
+void snmp_insert_udpidx_tree(struct udp_pcb *pcb)
+{
+  struct mib_list_rootnode *udp_rn;
+  struct mib_list_node *udp_node;
+  s32_t udpidx[5];
+  u8_t level;
+
+  LWIP_ASSERT("pcb != NULL", pcb != NULL);
+  snmp_iptooid(&pcb->local_ip, &udpidx[0]);
+  udpidx[4] = pcb->local_port;
+
+  udp_rn = &udp_root;
+  for (level = 0; level < 5; level++)
+  {
+    udp_node = NULL;
+    snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node);
+    if ((level != 4) && (udp_node != NULL))
+    {
+      if (udp_node->nptr == NULL)
+      {
+        udp_rn = snmp_mib_lrn_alloc();
+        udp_node->nptr = (struct mib_node*)udp_rn;
+        if (udp_rn != NULL)
+        {
+          if (level == 3)
+          {
+            udp_rn->get_object_def = udpentry_get_object_def;
+            udp_rn->get_value = udpentry_get_value;
+            udp_rn->set_test = noleafs_set_test;
+            udp_rn->set_value = noleafs_set_value;
+          }
+        }
+        else
+        {
+          /* udp_rn == NULL, malloc failure */
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full"));
+          break;
+        }
+      }
+      else
+      {
+        udp_rn = (struct mib_list_rootnode*)udp_node->nptr;
+      }
+    }
+  }
+  udptable.maxlength = 1;
+}
+
+/**
+ * Removes udpTable indexes (.udpLocalAddress.udpLocalPort)
+ * from index tree.
+ */
+void snmp_delete_udpidx_tree(struct udp_pcb *pcb)
+{
+  struct udp_pcb *npcb;
+  struct mib_list_rootnode *udp_rn, *next, *del_rn[5];
+  struct mib_list_node *udp_n, *del_n[5];
+  s32_t udpidx[5];
+  u8_t bindings, fc, level, del_cnt;
+
+  LWIP_ASSERT("pcb != NULL", pcb != NULL);
+  snmp_iptooid(&pcb->local_ip, &udpidx[0]);
+  udpidx[4] = pcb->local_port;
+
+  /* count PCBs for a given binding
+     (e.g. when reusing ports or for temp output PCBs) */
+  bindings = 0;
+  npcb = udp_pcbs;
+  while ((npcb != NULL))
+  {
+    if (ip_addr_cmp(&npcb->local_ip, &pcb->local_ip) &&
+        (npcb->local_port == udpidx[4]))
+    {
+      bindings++;
+    }
+    npcb = npcb->next;
+  }
+  if (bindings == 1)
+  {
+    /* selectively remove */
+    /* mark nodes for deletion */
+    level = 0;
+    del_cnt = 0;
+    udp_rn = &udp_root;
+    while ((level < 5) && (udp_rn != NULL))
+    {
+      fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n);
+      if (fc == 0)
+      {
+        /* udpidx[level] does not exist */
+        del_cnt = 0;
+        udp_rn = NULL;
+      }
+      else if (fc == 1)
+      {
+        del_rn[del_cnt] = udp_rn;
+        del_n[del_cnt] = udp_n;
+        del_cnt++;
+        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);
+      }
+      else if (fc == 2)
+      {
+        /* reset delete (2 or more childs) */
+        del_cnt = 0;
+        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);
+      }
+      level++;
+    }
+    /* delete marked index nodes */
+    while (del_cnt > 0)
+    {
+      del_cnt--;
+
+      udp_rn = del_rn[del_cnt];
+      udp_n = del_n[del_cnt];
+
+      next = snmp_mib_node_delete(udp_rn, udp_n);
+      if (next != NULL)
+      {
+        LWIP_ASSERT("next_count == 0",next->count == 0);
+        snmp_mib_lrn_free(next);
+      }
+    }
+  }
+  /* disable getnext traversal on empty table */
+  if (udp_root.count == 0) udptable.maxlength = 0;
+}
+
+
+void snmp_inc_snmpinpkts(void)
+{
+  snmpinpkts++;
+}
+
+void snmp_inc_snmpoutpkts(void)
+{
+  snmpoutpkts++;
+}
+
+void snmp_inc_snmpinbadversions(void)
+{
+  snmpinbadversions++;
+}
+
+void snmp_inc_snmpinbadcommunitynames(void)
+{
+  snmpinbadcommunitynames++;
+}
+
+void snmp_inc_snmpinbadcommunityuses(void)
+{
+  snmpinbadcommunityuses++;
+}
+
+void snmp_inc_snmpinasnparseerrs(void)
+{
+  snmpinasnparseerrs++;
+}
+
+void snmp_inc_snmpintoobigs(void)
+{
+  snmpintoobigs++;
+}
+
+void snmp_inc_snmpinnosuchnames(void)
+{
+  snmpinnosuchnames++;
+}
+
+void snmp_inc_snmpinbadvalues(void)
+{
+  snmpinbadvalues++;
+}
+
+void snmp_inc_snmpinreadonlys(void)
+{
+  snmpinreadonlys++;
+}
+
+void snmp_inc_snmpingenerrs(void)
+{
+  snmpingenerrs++;
+}
+
+void snmp_add_snmpintotalreqvars(u8_t value)
+{
+  snmpintotalreqvars += value;
+}
+
+void snmp_add_snmpintotalsetvars(u8_t value)
+{
+  snmpintotalsetvars += value;
+}
+
+void snmp_inc_snmpingetrequests(void)
+{
+  snmpingetrequests++;
+}
+
+void snmp_inc_snmpingetnexts(void)
+{
+  snmpingetnexts++;
+}
+
+void snmp_inc_snmpinsetrequests(void)
+{
+  snmpinsetrequests++;
+}
+
+void snmp_inc_snmpingetresponses(void)
+{
+  snmpingetresponses++;
+}
+
+void snmp_inc_snmpintraps(void)
+{
+  snmpintraps++;
+}
+
+void snmp_inc_snmpouttoobigs(void)
+{
+  snmpouttoobigs++;
+}
+
+void snmp_inc_snmpoutnosuchnames(void)
+{
+  snmpoutnosuchnames++;
+}
+
+void snmp_inc_snmpoutbadvalues(void)
+{
+  snmpoutbadvalues++;
+}
+
+void snmp_inc_snmpoutgenerrs(void)
+{
+  snmpoutgenerrs++;
+}
+
+void snmp_inc_snmpoutgetrequests(void)
+{
+  snmpoutgetrequests++;
+}
+
+void snmp_inc_snmpoutgetnexts(void)
+{
+  snmpoutgetnexts++;
+}
+
+void snmp_inc_snmpoutsetrequests(void)
+{
+  snmpoutsetrequests++;
+}
+
+void snmp_inc_snmpoutgetresponses(void)
+{
+  snmpoutgetresponses++;
+}
+
+void snmp_inc_snmpouttraps(void)
+{
+  snmpouttraps++;
+}
+
+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid)
+{
+  *oid = &snmpgrp_id;
+}
+
+void snmp_set_snmpenableauthentraps(u8_t *value)
+{
+  if (value != NULL)
+  {
+    snmpenableauthentraps_ptr = value;
+  }
+}
+
+void snmp_get_snmpenableauthentraps(u8_t *value)
+{
+  *value = *snmpenableauthentraps_ptr;
+}
+
+void
+noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  LWIP_UNUSED_ARG(ident_len);
+  LWIP_UNUSED_ARG(ident);
+  od->instance = MIB_OBJECT_NONE;
+}
+
+void
+noleafs_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  LWIP_UNUSED_ARG(od);
+  LWIP_UNUSED_ARG(len);
+  LWIP_UNUSED_ARG(value);
+}
+
+u8_t
+noleafs_set_test(struct obj_def *od, u16_t len, void *value)
+{
+  LWIP_UNUSED_ARG(od);
+  LWIP_UNUSED_ARG(len);
+  LWIP_UNUSED_ARG(value);
+  /* can't set */
+  return 0;
+}
+
+void
+noleafs_set_value(struct obj_def *od, u16_t len, void *value)
+{
+  LWIP_UNUSED_ARG(od);
+  LWIP_UNUSED_ARG(len);
+  LWIP_UNUSED_ARG(value);
+}
+
+
+/**
+ * Returns systems object definitions.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.0 (object id trailer)
+ * @param od points to object definition.
+ */
+static void
+system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  u8_t id;
+
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  if (ident_len == 2)
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+    id = (u8_t)ident[0];
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id));
+    switch (id)
+    {
+      case 1: /* sysDescr */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = *sysdescr_len_ptr;
+        break;
+      case 2: /* sysObjectID */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);
+        od->v_len = sysobjid.len * sizeof(s32_t);
+        break;
+      case 3: /* sysUpTime */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);
+        od->v_len = sizeof(u32_t);
+        break;
+      case 4: /* sysContact */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = *syscontact_len_ptr;
+        break;
+      case 5: /* sysName */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = *sysname_len_ptr;
+        break;
+      case 6: /* sysLocation */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = *syslocation_len_ptr;
+        break;
+      case 7: /* sysServices */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      default:
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n"));
+        od->instance = MIB_OBJECT_NONE;
+        break;
+    };
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+/**
+ * Returns system object value.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.0 (object id trailer)
+ * @param len return value space (in bytes)
+ * @param value points to (varbind) space to copy value into.
+ */
+static void
+system_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t id;
+
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 1: /* sysDescr */
+      ocstrncpy((u8_t*)value, sysdescr_ptr, len);
+      break;
+    case 2: /* sysObjectID */
+      objectidncpy((s32_t*)value, (s32_t*)sysobjid.id, (u8_t)(len / sizeof(s32_t)));
+      break;
+    case 3: /* sysUpTime */
+      {
+        snmp_get_sysuptime((u32_t*)value);
+      }
+      break;
+    case 4: /* sysContact */
+      ocstrncpy((u8_t*)value, syscontact_ptr, len);
+      break;
+    case 5: /* sysName */
+      ocstrncpy((u8_t*)value, sysname_ptr, len);
+      break;
+    case 6: /* sysLocation */
+      ocstrncpy((u8_t*)value, syslocation_ptr, len);
+      break;
+    case 7: /* sysServices */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+        *sint_ptr = sysservices;
+      }
+      break;
+  };
+}
+
+static u8_t
+system_set_test(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t id, set_ok;
+
+  LWIP_UNUSED_ARG(value);
+  set_ok = 0;
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 4: /* sysContact */
+      if ((syscontact_ptr != syscontact_default) &&
+          (len <= 255))
+      {
+        set_ok = 1;
+      }
+      break;
+    case 5: /* sysName */
+      if ((sysname_ptr != sysname_default) &&
+          (len <= 255))
+      {
+        set_ok = 1;
+      }
+      break;
+    case 6: /* sysLocation */
+      if ((syslocation_ptr != syslocation_default) &&
+          (len <= 255))
+      {
+        set_ok = 1;
+      }
+      break;
+  };
+  return set_ok;
+}
+
+static void
+system_set_value(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t id;
+
+  LWIP_ASSERT("invalid len", len <= 0xff);
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 4: /* sysContact */
+      ocstrncpy(syscontact_ptr, (u8_t*)value, len);
+      *syscontact_len_ptr = (u8_t)len;
+      break;
+    case 5: /* sysName */
+      ocstrncpy(sysname_ptr, (u8_t*)value, len);
+      *sysname_len_ptr = (u8_t)len;
+      break;
+    case 6: /* sysLocation */
+      ocstrncpy(syslocation_ptr, (u8_t*)value, len);
+      *syslocation_len_ptr = (u8_t)len;
+      break;
+  };
+}
+
+/**
+ * Returns interfaces.ifnumber object definition.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.index
+ * @param od points to object definition.
+ */
+static void
+interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  if (ident_len == 2)
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    od->instance = MIB_OBJECT_SCALAR;
+    od->access = MIB_OBJECT_READ_ONLY;
+    od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+    od->v_len = sizeof(s32_t);
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+/**
+ * Returns interfaces.ifnumber object value.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.0 (object id trailer)
+ * @param len return value space (in bytes)
+ * @param value points to (varbind) space to copy value into.
+ */
+static void
+interfaces_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  LWIP_UNUSED_ARG(len);
+  if (od->id_inst_ptr[0] == 1)
+  {
+    s32_t *sint_ptr = (s32_t*)value;
+    *sint_ptr = iflist_root.count;
+  }
+}
+
+/**
+ * Returns ifentry object definitions.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.index
+ * @param od points to object definition.
+ */
+static void
+ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  u8_t id;
+
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  if (ident_len == 2)
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+    id = (u8_t)ident[0];
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id));
+    switch (id)
+    {
+      case 1: /* ifIndex */
+      case 3: /* ifType */
+      case 4: /* ifMtu */
+      case 8: /* ifOperStatus */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      case 2: /* ifDescr */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        /** @todo this should be some sort of sizeof(struct netif.name) */
+        od->v_len = 2;
+        break;
+      case 5: /* ifSpeed */
+      case 21: /* ifOutQLen */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);
+        od->v_len = sizeof(u32_t);
+        break;
+      case 6: /* ifPhysAddress */
+        {
+          struct netif *netif;
+
+          snmp_ifindextonetif(ident[1], &netif);
+          od->instance = MIB_OBJECT_TAB;
+          od->access = MIB_OBJECT_READ_ONLY;
+          od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+          od->v_len = netif->hwaddr_len;
+        }
+        break;
+      case 7: /* ifAdminStatus */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      case 9: /* ifLastChange */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);
+        od->v_len = sizeof(u32_t);
+        break;
+      case 10: /* ifInOctets */
+      case 11: /* ifInUcastPkts */
+      case 12: /* ifInNUcastPkts */
+      case 13: /* ifInDiscarts */
+      case 14: /* ifInErrors */
+      case 15: /* ifInUnkownProtos */
+      case 16: /* ifOutOctets */
+      case 17: /* ifOutUcastPkts */
+      case 18: /* ifOutNUcastPkts */
+      case 19: /* ifOutDiscarts */
+      case 20: /* ifOutErrors */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
+        od->v_len = sizeof(u32_t);
+        break;
+      case 22: /* ifSpecific */
+        /** @note returning zeroDotZero (0.0) no media specific MIB support */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);
+        od->v_len = ifspecific.len * sizeof(s32_t);
+        break;
+      default:
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n"));
+        od->instance = MIB_OBJECT_NONE;
+        break;
+    };
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+/**
+ * Returns ifentry object value.
+ *
+ * @param ident_len the address length (2)
+ * @param ident points to objectname.0 (object id trailer)
+ * @param len return value space (in bytes)
+ * @param value points to (varbind) space to copy value into.
+ */
+static void
+ifentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  struct netif *netif;
+  u8_t id;
+
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 1: /* ifIndex */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+        *sint_ptr = od->id_inst_ptr[1];
+      }
+      break;
+    case 2: /* ifDescr */
+      ocstrncpy((u8_t*)value, (u8_t*)netif->name, len);
+      break;
+    case 3: /* ifType */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+        *sint_ptr = netif->link_type;
+      }
+      break;
+    case 4: /* ifMtu */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+        *sint_ptr = netif->mtu;
+      }
+      break;
+    case 5: /* ifSpeed */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = netif->link_speed;
+      }
+      break;
+    case 6: /* ifPhysAddress */
+      ocstrncpy((u8_t*)value, netif->hwaddr, len);
+      break;
+    case 7: /* ifAdminStatus */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+        if (netif_is_up(netif))
+        {
+          if (netif_is_link_up(netif))
+          {
+            *sint_ptr = 1; /* up */
+          }
+          else
+          {
+            *sint_ptr = 7; /* lowerLayerDown */
+          }
+        }
+        else
+        {
+          *sint_ptr = 2; /* down */
+        }
+      }
+      break;
+    case 8: /* ifOperStatus */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+        if (netif_is_up(netif))
+        {
+          *sint_ptr = 1;
+        }
+        else
+        {
+          *sint_ptr = 2;
+        }
+      }
+      break;
+    case 9: /* ifLastChange */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = netif->ts;
+      }
+      break;
+    case 10: /* ifInOctets */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = netif->ifinoctets;
+      }
+      break;
+    case 11: /* ifInUcastPkts */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = netif->ifinucastpkts;
+      }
+      break;
+    case 12: /* ifInNUcastPkts */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = netif->ifinnucastpkts;
+      }
+      break;
+    case 13: /* ifInDiscarts */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = netif->ifindiscards;
+      }
+      break;
+    case 14: /* ifInErrors */
+    case 15: /* ifInUnkownProtos */
+      /** @todo add these counters! */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = 0;
+      }
+      break;
+    case 16: /* ifOutOctets */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = netif->ifoutoctets;
+      }
+      break;
+    case 17: /* ifOutUcastPkts */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = netif->ifoutucastpkts;
+      }
+      break;
+    case 18: /* ifOutNUcastPkts */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = netif->ifoutnucastpkts;
+      }
+      break;
+    case 19: /* ifOutDiscarts */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = netif->ifoutdiscards;
+      }
+      break;
+    case 20: /* ifOutErrors */
+       /** @todo add this counter! */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = 0;
+      }
+      break;
+    case 21: /* ifOutQLen */
+      /** @todo figure out if this must be 0 (no queue) or 1? */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = 0;
+      }
+      break;
+    case 22: /* ifSpecific */
+      objectidncpy((s32_t*)value, (s32_t*)ifspecific.id, (u8_t)(len / sizeof(s32_t)));
+      break;
+  };
+}
+
+#if !SNMP_SAFE_REQUESTS
+static u8_t
+ifentry_set_test(struct obj_def *od, u16_t len, void *value)
+{
+  struct netif *netif;
+  u8_t id, set_ok;
+  LWIP_UNUSED_ARG(len);
+
+  set_ok = 0;
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 7: /* ifAdminStatus */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+        if (*sint_ptr == 1 || *sint_ptr == 2)
+          set_ok = 1;
+      }
+      break;
+  }
+  return set_ok;
+}
+
+static void
+ifentry_set_value(struct obj_def *od, u16_t len, void *value)
+{
+  struct netif *netif;
+  u8_t id;
+  LWIP_UNUSED_ARG(len);
+
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 7: /* ifAdminStatus */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+        if (*sint_ptr == 1)
+        {
+          netif_set_up(netif);
+        }
+        else if (*sint_ptr == 2)
+        {
+          netif_set_down(netif);
+         }
+      }
+      break;
+  }
+}
+#endif /* SNMP_SAFE_REQUESTS */
+
+/**
+ * Returns atentry object definitions.
+ *
+ * @param ident_len the address length (6)
+ * @param ident points to objectname.atifindex.atnetaddress
+ * @param od points to object definition.
+ */
+static void
+atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  /* return to object name, adding index depth (5) */
+  ident_len += 5;
+  ident -= 5;
+
+  if (ident_len == 6)
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    switch (ident[0])
+    {
+      case 1: /* atIfIndex */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      case 2: /* atPhysAddress */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = 6; /** @todo try to use netif::hwaddr_len */
+        break;
+      case 3: /* atNetAddress */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+        od->v_len = 4;
+        break;
+      default:
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n"));
+        od->instance = MIB_OBJECT_NONE;
+        break;
+    }
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+static void
+atentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+#if LWIP_ARP
+  u8_t id;
+  struct eth_addr* ethaddr_ret;
+  ip_addr_t* ipaddr_ret;
+#endif /* LWIP_ARP */
+  ip_addr_t ip;
+  struct netif *netif;
+
+  LWIP_UNUSED_ARG(len);
+  LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */
+
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
+  snmp_oidtoip(&od->id_inst_ptr[2], &ip);
+
+#if LWIP_ARP /** @todo implement a netif_find_addr */
+  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)
+  {
+    LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+    id = (u8_t)od->id_inst_ptr[0];
+    switch (id)
+    {
+      case 1: /* atIfIndex */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+          *sint_ptr = od->id_inst_ptr[1];
+        }
+        break;
+      case 2: /* atPhysAddress */
+        {
+          struct eth_addr *dst = (struct eth_addr*)value;
+
+          *dst = *ethaddr_ret;
+        }
+        break;
+      case 3: /* atNetAddress */
+        {
+          ip_addr_t *dst = (ip_addr_t*)value;
+
+          *dst = *ipaddr_ret;
+        }
+        break;
+    }
+  }
+#endif /* LWIP_ARP */
+}
+
+static void
+ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  u8_t id;
+
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  if (ident_len == 2)
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+    id = (u8_t)ident[0];
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id));
+    switch (id)
+    {
+      case 1: /* ipForwarding */
+      case 2: /* ipDefaultTTL */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      case 3: /* ipInReceives */
+      case 4: /* ipInHdrErrors */
+      case 5: /* ipInAddrErrors */
+      case 6: /* ipForwDatagrams */
+      case 7: /* ipInUnknownProtos */
+      case 8: /* ipInDiscards */
+      case 9: /* ipInDelivers */
+      case 10: /* ipOutRequests */
+      case 11: /* ipOutDiscards */
+      case 12: /* ipOutNoRoutes */
+      case 14: /* ipReasmReqds */
+      case 15: /* ipReasmOKs */
+      case 16: /* ipReasmFails */
+      case 17: /* ipFragOKs */
+      case 18: /* ipFragFails */
+      case 19: /* ipFragCreates */
+      case 23: /* ipRoutingDiscards */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
+        od->v_len = sizeof(u32_t);
+        break;
+      case 13: /* ipReasmTimeout */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      default:
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n"));
+        od->instance = MIB_OBJECT_NONE;
+        break;
+    };
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+static void
+ip_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t id;
+
+  LWIP_UNUSED_ARG(len);
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 1: /* ipForwarding */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+#if IP_FORWARD
+        /* forwarding */
+        *sint_ptr = 1;
+#else
+        /* not-forwarding */
+        *sint_ptr = 2;
+#endif
+      }
+      break;
+    case 2: /* ipDefaultTTL */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+        *sint_ptr = IP_DEFAULT_TTL;
+      }
+      break;
+    case 3: /* ipInReceives */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipinreceives;
+      }
+      break;
+    case 4: /* ipInHdrErrors */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipinhdrerrors;
+      }
+      break;
+    case 5: /* ipInAddrErrors */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipinaddrerrors;
+      }
+      break;
+    case 6: /* ipForwDatagrams */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipforwdatagrams;
+      }
+      break;
+    case 7: /* ipInUnknownProtos */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipinunknownprotos;
+      }
+      break;
+    case 8: /* ipInDiscards */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipindiscards;
+      }
+      break;
+    case 9: /* ipInDelivers */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipindelivers;
+      }
+      break;
+    case 10: /* ipOutRequests */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipoutrequests;
+      }
+      break;
+    case 11: /* ipOutDiscards */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipoutdiscards;
+      }
+      break;
+    case 12: /* ipOutNoRoutes */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipoutnoroutes;
+      }
+      break;
+    case 13: /* ipReasmTimeout */
+      {
+        s32_t *sint_ptr = (s32_t*)value;
+#if IP_REASSEMBLY
+        *sint_ptr = IP_REASS_MAXAGE;
+#else
+        *sint_ptr = 0;
+#endif
+      }
+      break;
+    case 14: /* ipReasmReqds */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipreasmreqds;
+      }
+      break;
+    case 15: /* ipReasmOKs */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipreasmoks;
+      }
+      break;
+    case 16: /* ipReasmFails */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipreasmfails;
+      }
+      break;
+    case 17: /* ipFragOKs */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipfragoks;
+      }
+      break;
+    case 18: /* ipFragFails */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipfragfails;
+      }
+      break;
+    case 19: /* ipFragCreates */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = ipfragcreates;
+      }
+      break;
+    case 23: /* ipRoutingDiscards */
+      /** @todo can lwIP discard routes at all?? hardwire this to 0?? */
+      {
+        u32_t *uint_ptr = (u32_t*)value;
+        *uint_ptr = iproutingdiscards;
+      }
+      break;
+  };
+}
+
+/**
+ * Test ip object value before setting.
+ *
+ * @param od is the object definition
+ * @param len return value space (in bytes)
+ * @param value points to (varbind) space to copy value from.
+ *
+ * @note we allow set if the value matches the hardwired value,
+ *   otherwise return badvalue.
+ */
+static u8_t
+ip_set_test(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t id, set_ok;
+  s32_t *sint_ptr = (s32_t*)value;
+
+  LWIP_UNUSED_ARG(len);
+  set_ok = 0;
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 1: /* ipForwarding */
+#if IP_FORWARD
+      /* forwarding */
+      if (*sint_ptr == 1)
+#else
+      /* not-forwarding */
+      if (*sint_ptr == 2)
+#endif
+      {
+        set_ok = 1;
+      }
+      break;
+    case 2: /* ipDefaultTTL */
+      if (*sint_ptr == IP_DEFAULT_TTL)
+      {
+        set_ok = 1;
+      }
+      break;
+  };
+  return set_ok;
+}
+
+static void
+ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  /* return to object name, adding index depth (4) */
+  ident_len += 4;
+  ident -= 4;
+
+  if (ident_len == 5)
+  {
+    u8_t id;
+
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+    id = (u8_t)ident[0];
+    switch (id)
+    {
+      case 1: /* ipAdEntAddr */
+      case 3: /* ipAdEntNetMask */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+        od->v_len = 4;
+        break;
+      case 2: /* ipAdEntIfIndex */
+      case 4: /* ipAdEntBcastAddr */
+      case 5: /* ipAdEntReasmMaxSize */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      default:
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n"));
+        od->instance = MIB_OBJECT_NONE;
+        break;
+    }
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+static void
+ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t id;
+  u16_t ifidx;
+  ip_addr_t ip;
+  struct netif *netif = netif_list;
+
+  LWIP_UNUSED_ARG(len);
+  snmp_oidtoip(&od->id_inst_ptr[1], &ip);
+  ifidx = 0;
+  while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr))
+  {
+    netif = netif->next;
+    ifidx++;
+  }
+
+  if (netif != NULL)
+  {
+    LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+    id = (u8_t)od->id_inst_ptr[0];
+    switch (id)
+    {
+      case 1: /* ipAdEntAddr */
+        {
+          ip_addr_t *dst = (ip_addr_t*)value;
+          *dst = netif->ip_addr;
+        }
+        break;
+      case 2: /* ipAdEntIfIndex */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+          *sint_ptr = ifidx + 1;
+        }
+        break;
+      case 3: /* ipAdEntNetMask */
+        {
+          ip_addr_t *dst = (ip_addr_t*)value;
+          *dst = netif->netmask;
+        }
+        break;
+      case 4: /* ipAdEntBcastAddr */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+
+          /* lwIP oddity, there's no broadcast
+            address in the netif we can rely on */
+          *sint_ptr = IPADDR_BROADCAST & 1;
+        }
+        break;
+      case 5: /* ipAdEntReasmMaxSize */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+#if IP_REASSEMBLY
+          /* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs,
+           * but only if receiving one fragmented packet at a time.
+           * The current solution is to calculate for 2 simultaneous packets...
+           */
+          *sint_ptr = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) *
+            (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - IP_HLEN)));
+#else
+          /** @todo returning MTU would be a bad thing and
+             returning a wild guess like '576' isn't good either */
+          *sint_ptr = 0;
+#endif
+        }
+        break;
+    }
+  }
+}
+
+/**
+ * @note
+ * lwIP IP routing is currently using the network addresses in netif_list.
+ * if no suitable network IP is found in netif_list, the default_netif is used.
+ */
+static void
+ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  u8_t id;
+
+  /* return to object name, adding index depth (4) */
+  ident_len += 4;
+  ident -= 4;
+
+  if (ident_len == 5)
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+    id = (u8_t)ident[0];
+    switch (id)
+    {
+      case 1: /* ipRouteDest */
+      case 7: /* ipRouteNextHop */
+      case 11: /* ipRouteMask */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+        od->v_len = 4;
+        break;
+      case 2: /* ipRouteIfIndex */
+      case 3: /* ipRouteMetric1 */
+      case 4: /* ipRouteMetric2 */
+      case 5: /* ipRouteMetric3 */
+      case 6: /* ipRouteMetric4 */
+      case 8: /* ipRouteType */
+      case 10: /* ipRouteAge */
+      case 12: /* ipRouteMetric5 */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      case 9: /* ipRouteProto */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      case 13: /* ipRouteInfo */
+        /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);
+        od->v_len = iprouteinfo.len * sizeof(s32_t);
+        break;
+      default:
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n"));
+        od->instance = MIB_OBJECT_NONE;
+        break;
+    }
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+static void
+ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  struct netif *netif;
+  ip_addr_t dest;
+  s32_t *ident;
+  u8_t id;
+
+  ident = od->id_inst_ptr;
+  snmp_oidtoip(&ident[1], &dest);
+
+  if (ip_addr_isany(&dest))
+  {
+    /* ip_route() uses default netif for default route */
+    netif = netif_default;
+  }
+  else
+  {
+    /* not using ip_route(), need exact match! */
+    netif = netif_list;
+    while ((netif != NULL) &&
+            !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) )
+    {
+      netif = netif->next;
+    }
+  }
+  if (netif != NULL)
+  {
+    LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+    id = (u8_t)ident[0];
+    switch (id)
+    {
+      case 1: /* ipRouteDest */
+        {
+          ip_addr_t *dst = (ip_addr_t*)value;
+
+          if (ip_addr_isany(&dest))
+          {
+            /* default rte has 0.0.0.0 dest */
+            ip_addr_set_zero(dst);
+          }
+          else
+          {
+            /* netifs have netaddress dest */
+            ip_addr_get_network(dst, &netif->ip_addr, &netif->netmask);
+          }
+        }
+        break;
+      case 2: /* ipRouteIfIndex */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+
+          snmp_netiftoifindex(netif, sint_ptr);
+        }
+        break;
+      case 3: /* ipRouteMetric1 */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+
+          if (ip_addr_isany(&dest))
+          {
+            /* default rte has metric 1 */
+            *sint_ptr = 1;
+          }
+          else
+          {
+            /* other rtes have metric 0 */
+            *sint_ptr = 0;
+          }
+        }
+        break;
+      case 4: /* ipRouteMetric2 */
+      case 5: /* ipRouteMetric3 */
+      case 6: /* ipRouteMetric4 */
+      case 12: /* ipRouteMetric5 */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+          /* not used */
+          *sint_ptr = -1;
+        }
+        break;
+      case 7: /* ipRouteNextHop */
+        {
+          ip_addr_t *dst = (ip_addr_t*)value;
+
+          if (ip_addr_isany(&dest))
+          {
+            /* default rte: gateway */
+            *dst = netif->gw;
+          }
+          else
+          {
+            /* other rtes: netif ip_addr  */
+            *dst = netif->ip_addr;
+          }
+        }
+        break;
+      case 8: /* ipRouteType */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+
+          if (ip_addr_isany(&dest))
+          {
+            /* default rte is indirect */
+            *sint_ptr = 4;
+          }
+          else
+          {
+            /* other rtes are direct */
+            *sint_ptr = 3;
+          }
+        }
+        break;
+      case 9: /* ipRouteProto */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+          /* locally defined routes */
+          *sint_ptr = 2;
+        }
+        break;
+      case 10: /* ipRouteAge */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+          /** @todo (sysuptime - timestamp last change) / 100
+              @see snmp_insert_iprteidx_tree() */
+          *sint_ptr = 0;
+        }
+        break;
+      case 11: /* ipRouteMask */
+        {
+          ip_addr_t *dst = (ip_addr_t*)value;
+
+          if (ip_addr_isany(&dest))
+          {
+            /* default rte use 0.0.0.0 mask */
+            ip_addr_set_zero(dst);
+          }
+          else
+          {
+            /* other rtes use netmask */
+            *dst = netif->netmask;
+          }
+        }
+        break;
+      case 13: /* ipRouteInfo */
+        objectidncpy((s32_t*)value, (s32_t*)iprouteinfo.id, (u8_t)(len / sizeof(s32_t)));
+        break;
+    }
+  }
+}
+
+static void
+ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  /* return to object name, adding index depth (5) */
+  ident_len += 5;
+  ident -= 5;
+
+  if (ident_len == 6)
+  {
+    u8_t id;
+
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+    id = (u8_t)ident[0];
+    switch (id)
+    {
+      case 1: /* ipNetToMediaIfIndex */
+      case 4: /* ipNetToMediaType */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      case 2: /* ipNetToMediaPhysAddress */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = 6; /** @todo try to use netif::hwaddr_len */
+        break;
+      case 3: /* ipNetToMediaNetAddress */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+        od->v_len = 4;
+        break;
+      default:
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n"));
+        od->instance = MIB_OBJECT_NONE;
+        break;
+    }
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+static void
+ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value)
+{
+#if LWIP_ARP
+  u8_t id;
+  struct eth_addr* ethaddr_ret;
+  ip_addr_t* ipaddr_ret;
+#endif /* LWIP_ARP */
+  ip_addr_t ip;
+  struct netif *netif;
+
+  LWIP_UNUSED_ARG(len);
+  LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */
+
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);
+  snmp_oidtoip(&od->id_inst_ptr[2], &ip);
+
+#if LWIP_ARP /** @todo implement a netif_find_addr */
+  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)
+  {
+    LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+    id = (u8_t)od->id_inst_ptr[0];
+    switch (id)
+    {
+      case 1: /* ipNetToMediaIfIndex */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+          *sint_ptr = od->id_inst_ptr[1];
+        }
+        break;
+      case 2: /* ipNetToMediaPhysAddress */
+        {
+          struct eth_addr *dst = (struct eth_addr*)value;
+
+          *dst = *ethaddr_ret;
+        }
+        break;
+      case 3: /* ipNetToMediaNetAddress */
+        {
+          ip_addr_t *dst = (ip_addr_t*)value;
+
+          *dst = *ipaddr_ret;
+        }
+        break;
+      case 4: /* ipNetToMediaType */
+        {
+          s32_t *sint_ptr = (s32_t*)value;
+          /* dynamic (?) */
+          *sint_ptr = 3;
+        }
+        break;
+    }
+  }
+#endif /* LWIP_ARP */
+}
+
+static void
+icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  if ((ident_len == 2) &&
+      (ident[0] > 0) && (ident[0] < 27))
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    od->instance = MIB_OBJECT_SCALAR;
+    od->access = MIB_OBJECT_READ_ONLY;
+    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
+    od->v_len = sizeof(u32_t);
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+static void
+icmp_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  u32_t *uint_ptr = (u32_t*)value;
+  u8_t id;
+
+  LWIP_UNUSED_ARG(len);
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 1: /* icmpInMsgs */
+      *uint_ptr = icmpinmsgs;
+      break;
+    case 2: /* icmpInErrors */
+      *uint_ptr = icmpinerrors;
+      break;
+    case 3: /* icmpInDestUnreachs */
+      *uint_ptr = icmpindestunreachs;
+      break;
+    case 4: /* icmpInTimeExcds */
+      *uint_ptr = icmpintimeexcds;
+      break;
+    case 5: /* icmpInParmProbs */
+      *uint_ptr = icmpinparmprobs;
+      break;
+    case 6: /* icmpInSrcQuenchs */
+      *uint_ptr = icmpinsrcquenchs;
+      break;
+    case 7: /* icmpInRedirects */
+      *uint_ptr = icmpinredirects;
+      break;
+    case 8: /* icmpInEchos */
+      *uint_ptr = icmpinechos;
+      break;
+    case 9: /* icmpInEchoReps */
+      *uint_ptr = icmpinechoreps;
+      break;
+    case 10: /* icmpInTimestamps */
+      *uint_ptr = icmpintimestamps;
+      break;
+    case 11: /* icmpInTimestampReps */
+      *uint_ptr = icmpintimestampreps;
+      break;
+    case 12: /* icmpInAddrMasks */
+      *uint_ptr = icmpinaddrmasks;
+      break;
+    case 13: /* icmpInAddrMaskReps */
+      *uint_ptr = icmpinaddrmaskreps;
+      break;
+    case 14: /* icmpOutMsgs */
+      *uint_ptr = icmpoutmsgs;
+      break;
+    case 15: /* icmpOutErrors */
+      *uint_ptr = icmpouterrors;
+      break;
+    case 16: /* icmpOutDestUnreachs */
+      *uint_ptr = icmpoutdestunreachs;
+      break;
+    case 17: /* icmpOutTimeExcds */
+      *uint_ptr = icmpouttimeexcds;
+      break;
+    case 18: /* icmpOutParmProbs */
+      *uint_ptr = icmpoutparmprobs;
+      break;
+    case 19: /* icmpOutSrcQuenchs */
+      *uint_ptr = icmpoutsrcquenchs;
+      break;
+    case 20: /* icmpOutRedirects */
+      *uint_ptr = icmpoutredirects;
+      break;
+    case 21: /* icmpOutEchos */
+      *uint_ptr = icmpoutechos;
+      break;
+    case 22: /* icmpOutEchoReps */
+      *uint_ptr = icmpoutechoreps;
+      break;
+    case 23: /* icmpOutTimestamps */
+      *uint_ptr = icmpouttimestamps;
+      break;
+    case 24: /* icmpOutTimestampReps */
+      *uint_ptr = icmpouttimestampreps;
+      break;
+    case 25: /* icmpOutAddrMasks */
+      *uint_ptr = icmpoutaddrmasks;
+      break;
+    case 26: /* icmpOutAddrMaskReps */
+      *uint_ptr = icmpoutaddrmaskreps;
+      break;
+  }
+}
+
+#if LWIP_TCP
+/** @todo tcp grp */
+static void
+tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  u8_t id;
+
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  if (ident_len == 2)
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+    id = (u8_t)ident[0];
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));
+
+    switch (id)
+    {
+      case 1: /* tcpRtoAlgorithm */
+      case 2: /* tcpRtoMin */
+      case 3: /* tcpRtoMax */
+      case 4: /* tcpMaxConn */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      case 5: /* tcpActiveOpens */
+      case 6: /* tcpPassiveOpens */
+      case 7: /* tcpAttemptFails */
+      case 8: /* tcpEstabResets */
+      case 10: /* tcpInSegs */
+      case 11: /* tcpOutSegs */
+      case 12: /* tcpRetransSegs */
+      case 14: /* tcpInErrs */
+      case 15: /* tcpOutRsts */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);
+        od->v_len = sizeof(u32_t);
+        break;
+      case 9: /* tcpCurrEstab */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);
+        od->v_len = sizeof(u32_t);
+        break;
+      default:
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n"));
+        od->instance = MIB_OBJECT_NONE;
+        break;
+    };
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+static void
+tcp_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  u32_t *uint_ptr = (u32_t*)value;
+  s32_t *sint_ptr = (s32_t*)value;
+  u8_t id;
+
+  LWIP_UNUSED_ARG(len);
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 1: /* tcpRtoAlgorithm, vanj(4) */
+      *sint_ptr = 4;
+      break;
+    case 2: /* tcpRtoMin */
+      /* @todo not the actual value, a guess,
+          needs to be calculated */
+      *sint_ptr = 1000;
+      break;
+    case 3: /* tcpRtoMax */
+      /* @todo not the actual value, a guess,
+         needs to be calculated */
+      *sint_ptr = 60000;
+      break;
+    case 4: /* tcpMaxConn */
+      *sint_ptr = MEMP_NUM_TCP_PCB;
+      break;
+    case 5: /* tcpActiveOpens */
+      *uint_ptr = tcpactiveopens;
+      break;
+    case 6: /* tcpPassiveOpens */
+      *uint_ptr = tcppassiveopens;
+      break;
+    case 7: /* tcpAttemptFails */
+      *uint_ptr = tcpattemptfails;
+      break;
+    case 8: /* tcpEstabResets */
+      *uint_ptr = tcpestabresets;
+      break;
+    case 9: /* tcpCurrEstab */
+      {
+        u16_t tcpcurrestab = 0;
+        struct tcp_pcb *pcb = tcp_active_pcbs;
+        while (pcb != NULL)
+        {
+          if ((pcb->state == ESTABLISHED) ||
+              (pcb->state == CLOSE_WAIT))
+          {
+            tcpcurrestab++;
+          }
+          pcb = pcb->next;
+        }
+        *uint_ptr = tcpcurrestab;
+      }
+      break;
+    case 10: /* tcpInSegs */
+      *uint_ptr = tcpinsegs;
+      break;
+    case 11: /* tcpOutSegs */
+      *uint_ptr = tcpoutsegs;
+      break;
+    case 12: /* tcpRetransSegs */
+      *uint_ptr = tcpretranssegs;
+      break;
+    case 14: /* tcpInErrs */
+      *uint_ptr = tcpinerrs;
+      break;
+    case 15: /* tcpOutRsts */
+      *uint_ptr = tcpoutrsts;
+      break;
+  }
+}
+#ifdef THIS_SEEMS_UNUSED
+static void
+tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+  /* return to object name, adding index depth (10) */
+  ident_len += 10;
+  ident -= 10;
+
+  if (ident_len == 11)
+  {
+    u8_t id;
+
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    id = ident[0];
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));
+
+    switch (id)
+    {
+      case 1: /* tcpConnState */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      case 2: /* tcpConnLocalAddress */
+      case 4: /* tcpConnRemAddress */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);
+        od->v_len = 4;
+        break;
+      case 3: /* tcpConnLocalPort */
+      case 5: /* tcpConnRemPort */
+        od->instance = MIB_OBJECT_TAB;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(s32_t);
+        break;
+      default:
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));
+        od->instance = MIB_OBJECT_NONE;
+        break;
+    };
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,(