| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092 |
- /*
- * Copyright (C) 2001-2005 by egnite Software GmbH. 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 the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE
- * COPYRIGHT OWNER 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.
- *
- * For additional information see http://www.ethernut.de/
- *
- * -
- * Portions Copyright (c) 1983, 1993 by
- * The Regents of the University of California. 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 the University 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 THE REGENTS 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 THE REGENTS 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.
- * -
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies, and that
- * the name of Digital Equipment Corporation not be used in advertising or
- * publicity pertaining to distribution of the document or software without
- * specific, written prior permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
- /*!
- * \file pro/dhcpc.c
- * \brief DHCP client.
- *
- * \verbatim
- * $Id: dhcpc.c 5131 2013-05-10 07:46:14Z haraldkipp $
- * \endverbatim
- */
- #include <cfg/os.h>
- #include <sys/thread.h>
- #include <sys/event.h>
- #include <sys/timer.h>
- #include <sys/confnet.h>
- #include <sys/confos.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <memdebug.h>
- #include <arpa/inet.h>
- #include <netinet/in.h>
- #include <netinet/if_ether.h>
- #include <netdb.h>
- #include <net/route.h>
- #include <sys/socket.h>
- #include <pro/dhcp.h>
- #ifdef NUTDEBUG
- #include <net/netdebug.h>
- #endif
- #if 0
- /* Use for local debugging. */
- #define NUTDEBUG
- #include <stdio.h>
- #define __tcp_trs stdout
- static uint_fast8_t __tcp_trf = 1;
- #endif
- /*!
- * \addtogroup xgDHCPC
- */
- /*@{*/
- /*!
- * \name DHCP Client Configuration
- *
- * The Nut/OS Configurator may be used to override the default values.
- */
- /*@{*/
- /*!
- * \brief UDP port of DHCP server.
- *
- * \showinitializer
- */
- #ifndef DHCP_SERVERPORT
- #define DHCP_SERVERPORT 67
- #endif
- /*!
- * \brief UDP port of DHCP client.
- *
- * \showinitializer
- */
- #ifndef DHCP_CLIENTPORT
- #define DHCP_CLIENTPORT 68
- #endif
- /*!
- * \brief Maximum DHCP message size we can accept.
- *
- * RFC 2131 demands, that a DHCP client must be prepared to receive DHCP
- * messages with an options field length of at least 312 octets. This
- * implies that we must be able to accept messages of up to 576 octets.
- *
- * \showinitializer
- */
- #ifndef MAX_DHCP_MSGSIZE
- #define MAX_DHCP_MSGSIZE 576
- #endif
- /*!
- * \brief Minimum DHCP message length.
- *
- * Used to maintain BOOTP compatibility of outgoing messages.
- *
- * \showinitializer
- */
- #ifndef MIN_DHCP_MSGSIZE
- #define MIN_DHCP_MSGSIZE 300
- #endif
- /*!
- * \brief Maximum UDP buffer size used by the DHCP client.
- *
- * If this item is not equal zero, the DHCP client will use its value to
- * set #SO_RCVBUF by calling NutUdpSetSockOpt().
- *
- * If this item is set to zero, NutUdpSetSockOpt() is not called and the
- * UDP socket interface will buffer the last incoming datagram on the
- * #DHCP_CLIENTPORT socket port only. Any previously received datagram is
- * silently discarded. As long as one DHCP server is expected in the local
- * network, this will be fine and save some heap memory while DHCP is
- * active.
- *
- * \showinitializer
- */
- #ifndef MAX_DHCP_BUFSIZE
- #define MAX_DHCP_BUFSIZE 1728
- #endif
- /*!
- * \brief Minimum number of milliseconds to wait for a response.
- *
- * If we receive no response from a DHCP server within this time, we
- * will double this value up to \ref MAX_DHCP_WAIT and repeat our
- * request up to \ref MAX_DCHP_RETRIES times before giving up.
- *
- * \showinitializer
- */
- #ifndef MIN_DHCP_WAIT
- #define MIN_DHCP_WAIT 4000
- #endif
- /*!
- * \brief Maximum number of milliseconds to wait for a response.
- *
- * The timeout value for receiving server responses will be doubled
- * on each retry but limited by this value.
- *
- * \showinitializer
- */
- #ifndef MAX_DHCP_WAIT
- #define MAX_DHCP_WAIT 64000
- #endif
- /*!
- * \brief Maximum number of request retries.
- *
- * We will give up after resending this number of requests without
- * receiving a response.
- *
- * \showinitializer
- */
- #ifndef MAX_DCHP_RETRIES
- #define MAX_DCHP_RETRIES 3
- #endif
- /*!
- * \brief Maximum number of release retries.
- *
- * RFC 2131 doesn't specify a server response to release messages from
- * the client. If the message gets lost, then the lease isn't released.
- *
- * \showinitializer
- */
- #ifndef MAX_DCHP_RELEASE_RETRIES
- #define MAX_DCHP_RELEASE_RETRIES 0
- #endif
- /*!
- * \brief Default lease time in seconds.
- *
- * This value is used if the server doesn't provide a lease time.
- *
- * \showinitializer
- */
- #ifndef DHCP_DEFAULT_LEASE
- #define DHCP_DEFAULT_LEASE 43200
- #endif
- /*!
- * \brief Maximum sleep time in seconds.
- *
- * \showinitializer
- */
- #ifndef MAX_DHCP_NAPTIME
- #define MAX_DHCP_NAPTIME 4294967
- #endif
- /*!
- * \brief Stack size of the DHCP client thread.
- *
- * \showinitializer
- */
- #ifndef NUT_THREAD_DHCPSTACK
- #if defined(__AVR__)
- #if defined(__GNUC__)
- /* avr-gcc size optimized code used 192 bytes. */
- #define NUT_THREAD_DHCPSTACK 288
- #else
- /* icc-avr v7.19 used 360 bytes. */
- #define NUT_THREAD_DHCPSTACK 512
- #endif
- #else
- /* arm-elf-gcc used 276 bytes with size optimized, 680 bytes with debug code. */
- /* arm-none-eabi creates stack overflow with 384 bytes on EIR 1.0 board. */
- #define NUT_THREAD_DHCPSTACK 512
- #endif
- #endif
- /*@}*/
- /*!
- * \name DHCP Message Types
- *
- * See RFC 2131.
- */
- /*@{*/
- /*! \brief Client broadcast to locate available servers.
- */
- #define DHCP_DISCOVER 1
- /*! \brief Server to client in response to DHCP_DISCOVER.
- *
- * Contains an offer of configuration parameters.
- */
- #define DHCP_OFFER 2
- /*! \brief Client message to servers.
- *
- * Used for
- * - requesting offered parameters from one server and implicitly declining offers from all others.
- * - confirming correctness of previously allocated address after, e.g., system reboot.
- * - extending the lease on a particular network address.
- */
- #define DHCP_REQUEST 3
- /*! \brief Client to server indicating network address is already in use.
- *
- * Not used by Nut/Net.
- */
- #define DHCP_DECLINE 4
- /*! \brief Server to client with configuration parameters.
- *
- * Contains committed network address.
- */
- #define DHCP_ACK 5
- /*! \brief Server to client indicating client's notion of network address is incorrect.
- *
- * May be caused by the client's move to new subnet or by expiration of the client's lease.
- */
- #define DHCP_NAK 6
- /*! \brief Client to server relinquishing network address and cancelling remaining lease.
- */
- #define DHCP_RELEASE 7
- /*! \brief Client to server, asking only for local configuration parameters.
- *
- * Used, if the client already has externally configured network address.
- */
- #define DHCP_INFORM 8
- /*@}*/
- /*!
- * \name DHCP Options
- *
- * Nut/Net recognizes a subset of options defined in RFC 2132.
- */
- /*@{*/
- /*!
- * \brief DHCP pad option.
- *
- * The pad option can be used to cause subsequent fields to align on
- * word boundaries.
- */
- #define DHCPOPT_PAD 0
- /*!
- * \brief DHCP subnet mask option.
- */
- #define DHCPOPT_NETMASK 1
- /*!
- * \brief DHCP router option.
- */
- #define DHCPOPT_GATEWAY 3
- /*!
- * \brief DHCP domain name server option.
- */
- #define DHCPOPT_DNS 6
- /*!
- * \brief DHCP host name option.
- */
- #define DHCPOPT_HOSTNAME 12
- /*!
- * \brief DHCP domain name option.
- */
- #define DHCPOPT_DOMAIN 15
- /*!
- * \brief DHCP broadcast address option.
- */
- #define DHCPOPT_BROADCAST 28
- /*!
- * \brief DHCP requested IP address option.
- */
- #define DHCPOPT_REQESTIP 50
- /*!
- * \brief DHCP IP address lease time option.
- */
- #define DHCPOPT_LEASETIME 51
- /*!
- * \brief DHCP message type option.
- */
- #define DHCPOPT_MSGTYPE 53
- /*!
- * \brief DHCP server identifier option.
- */
- #define DHCPOPT_SID 54
- /*!
- * \brief DHCP parameter request list option.
- */
- #define DHCPOPT_PARAMREQUEST 55
- /*!
- * \brief Maximum DHCP message size option.
- */
- #define DHCPOPT_MAXMSGSIZE 57
- /*!
- * \brief DHCP renewal time option.
- */
- #define DHCPOPT_RENEWALTIME 58
- /*!
- * \brief DHCP rebinding time option.
- */
- #define DHCPOPT_REBINDTIME 59
- /*!
- * \brief DHCP end option.
- */
- #define DHCPOPT_END 255
- /*@}*/
- /*!
- * \brief BOOTP message structure type.
- */
- typedef struct bootp BOOTP;
- /*!
- * \brief BOOTP message structure.
- */
- struct NUT_PACKED_TYPE bootp {
- uint8_t bp_op; /*!< \brief Packet opcode type: 1=request, 2=reply */
- uint8_t bp_htype; /*!< \brief Hardware address type: 1=Ethernet */
- uint8_t bp_hlen; /*!< \brief Hardware address length: 6 for Ethernet */
- uint8_t bp_hops; /*!< \brief Gateway hops */
- uint32_t bp_xid; /*!< \brief Transaction ID */
- uint16_t bp_secs; /*!< \brief Seconds since boot began */
- uint16_t bp_flags; /*!< \brief RFC1532 broadcast, etc. */
- uint32_t bp_ciaddr; /*!< \brief Client IP address */
- uint32_t bp_yiaddr; /*!< \brief 'Your' IP address */
- uint32_t bp_siaddr; /*!< \brief Server IP address */
- uint32_t bp_giaddr; /*!< \brief Gateway IP address */
- uint8_t bp_chaddr[16]; /*!< \brief Client hardware address */
- char bp_sname[64]; /*!< \brief Server host name */
- char bp_file[128]; /*!< \brief Boot file name */
- uint8_t bp_options[312]; /*!< \brief Vendor-specific area */
- };
- /*!
- * \brief Dynamic configuration structure type.
- */
- typedef struct dyn_cfg DYNCFG;
- /*!
- * \brief Dynamic configuration structure.
- */
- struct dyn_cfg {
- uint8_t dyn_msgtyp; /*!< \brief DHCP message type */
- uint32_t dyn_yiaddr; /*!< \brief Offered IP address. */
- uint32_t dyn_netmask; /*!< \brief Local IP netmask. */
- uint32_t dyn_broadcast; /*!< \brief Local IP broadcast address. */
- uint32_t dyn_gateway; /*!< \brief Default gate IP address. */
- uint32_t dyn_pdns; /*!< \brief Primary DNS IP address. */
- uint32_t dyn_sdns; /*!< \brief Secondary DNS IP address. */
- uint32_t dyn_sid; /*!< \brief Server identifier. */
- uint32_t dyn_renewalTime; /*!< \brief Renewal time in seconds. */
- uint32_t dyn_rebindTime; /*!< \brief Rebind time in seconds. */
- uint32_t dyn_leaseTime; /*!< \brief Offered lease time in seconds. */
- uint8_t *dyn_hostname; /*!< \brief Local hostname. */
- uint8_t *dyn_domain; /*!< \brief Name of local domain. */
- };
- /*!
- * \brief Current configuration.
- *
- * This structure is filled by parsing offer or acknowledge messages from
- * the server.
- */
- static DYNCFG *dhcpConfig;
- /*!
- * \brief Client thread identifier.
- *
- * Used to determine if the client thread is running. Zero indicates that
- * it is not.
- */
- static HANDLE dhcpThread;
- /*!
- * \brief Current state of the DHCP client state machine.
- */
- static uint8_t dhcpState;
- /*!
- * \brief Latest DHCP error code.
- */
- static int dhcpError;
- /*!
- * \brief DHCP wake up queue.
- *
- * The DHCP state machine can be woken up by posting to this queue.
- */
- static HANDLE dhcpWake;
- /*!
- * \brief DHCP waiting queue.
- *
- * Application threads wait on this queue until DHCP success or failure.
- */
- static HANDLE dhcpDone;
- /*!
- * \brief Maximum number of milliseconds to wait on \ref dhcpDone.
- *
- * Specified by the application when calling the DHCP client API.
- */
- static uint32_t dhcpApiTimeout;
- /*!
- * \brief Time at which the application started to wait.
- *
- * Used in conjunction with \ref dhcpApiTimeout to limit the maximum
- * wait time for server responses.
- */
- static uint32_t dhcpApiStart;
- /*!
- * \brief Dynamic string copy.
- *
- * \param dst Points to a string pointer. If the pointer is not NULL, it
- * is assumed that it points to a previously allocated buffer
- * and this buffer will be released first. Then a new buffer
- * will be allocated and the source string will be copied to
- * this buffer.
- * \param src The source string. No delimiter required.
- * \param len Length of the source string.
- */
- static void copy_str(uint8_t ** dst, void *src, int len)
- {
- free(*dst);
- *dst = malloc(len + 1);
- if (*dst) {
- if (len) {
- memcpy(*dst, src, len);
- }
- *(*dst + len) = 0;
- }
- }
- /*!
- * \brief Release DYNCFG structure.
- *
- * Frees all memory occupied by a \ref DYNCFG structure.
- *
- * \param dyncfg This structure will be released.
- */
- static void ReleaseDynCfg(DYNCFG * dyncfg)
- {
- if (dyncfg) {
- free(dyncfg->dyn_hostname);
- free(dyncfg->dyn_domain);
- free(dyncfg);
- }
- }
- /*!
- * \brief Parse a DHCP reply message.
- *
- * \param bp Pointer to the reply message. The caller must make sure,
- * that this contains a valid BOOTP reply header with at
- * least five bytes in the options field.
- * \param len Number of valid bytes in the reply message.
- *
- * \return Pointer to config structure. Must be released by the caller.
- * NULL is returned in case of parsing errors.
- */
- static DYNCFG *ParseReply(BOOTP *bp, int len)
- {
- uint8_t *op;
- int left;
- DYNCFG *cfgp;
- /* Allocate and initialize a new structure. */
- cfgp = malloc(sizeof(DYNCFG));
- if (cfgp == NULL) {
- return NULL;
- }
- memset(cfgp, 0, sizeof(DYNCFG));
- cfgp->dyn_leaseTime = DHCP_DEFAULT_LEASE;
- /* Set the assigned IP address. */
- memcpy(&cfgp->dyn_yiaddr, &bp->bp_yiaddr, 4);
- /*
- * Parse options until an end option is found or until we reached
- * the end of the message.
- */
- op = bp->bp_options + 4;
- left = len - (sizeof(*bp) - sizeof(bp->bp_options)) - 4;
- while (*op != DHCPOPT_END && left > 0) {
- uint8_t ol;
- #ifdef NUTDEBUG
- if (__tcp_trf) {
- fprintf(__tcp_trs, "[DHCP-Opt-%u]", *op);
- }
- #endif
- /* Pad option is used for boundary alignment. */
- if (*op == DHCPOPT_PAD) {
- op++;
- left--;
- continue;
- }
- /* Reject if option length exceeds total length. */
- ol = *(op + 1);
- if (ol > left) {
- break;
- }
- /* Type of this message. */
- if (*op == DHCPOPT_MSGTYPE) {
- if (ol != 1) {
- break;
- }
- cfgp->dyn_msgtyp = *(op + 2);
- }
- /* Our host name. May or may not include the domain. */
- else if (*op == DHCPOPT_HOSTNAME) {
- copy_str(&cfgp->dyn_hostname, op + 2, ol);
- }
- /* Name of the domain we are in. */
- else if (*op == DHCPOPT_DOMAIN) {
- copy_str(&cfgp->dyn_domain, op + 2, ol);
- }
- /* All remaining options require at least 4 octets. */
- else if (ol >= 4) {
- /* Preset most often used long value. */
- uint32_t lval = *(op + 2);
- lval += (uint32_t)(*(op + 3)) << 8;
- lval += (uint32_t)(*(op + 4)) << 16;
- lval += (uint32_t)(*(op + 5)) << 24;
- /* Our IP network mask. */
- if (*op == DHCPOPT_NETMASK) {
- cfgp->dyn_netmask = lval;
- }
- /* Our IP broadcast address. */
- else if (*op == DHCPOPT_BROADCAST) {
- cfgp->dyn_broadcast = lval;
- }
- /* Our IP default gate. More than one gateway may be
- specified. We take the fist one only and ignore the
- rest. */
- else if (*op == DHCPOPT_GATEWAY) {
- cfgp->dyn_gateway = lval;
- }
- /* Our DNS server. Updated by Jelle Martijn Kok to
- support a secondary DNS. */
- else if (*op == DHCPOPT_DNS) {
- cfgp->dyn_pdns = lval;
- if (ol >= 8) {
- cfgp->dyn_sdns = *(op + 6);
- cfgp->dyn_sdns += (uint32_t)(*(op + 7)) << 8;
- cfgp->dyn_sdns += (uint32_t)(*(op + 8)) << 16;
- cfgp->dyn_sdns += (uint32_t)(*(op + 9)) << 24;
- }
- }
- /* Server identifier. */
- else if (*op == DHCPOPT_SID) {
- cfgp->dyn_sid = lval;
- }
- /* Renewal time. */
- else if (*op == DHCPOPT_RENEWALTIME) {
- cfgp->dyn_renewalTime = ntohl(lval);
- }
- /* Rebinding time. */
- else if (*op == DHCPOPT_REBINDTIME) {
- cfgp->dyn_rebindTime = ntohl(lval);
- }
- /* Total lease time granted. */
- else if (*op == DHCPOPT_LEASETIME) {
- cfgp->dyn_leaseTime = ntohl(lval);
- }
- }
- op += ol + 2;
- left -= ol + 2;
- }
- /*
- * Discard this configuration if parsing stopped before reaching
- * the end option or if we didn't receive an expected message type.
- */
- if (*op != DHCPOPT_END || /* */
- (cfgp->dyn_msgtyp != DHCP_OFFER && /* */
- cfgp->dyn_msgtyp != DHCP_ACK && /* */
- cfgp->dyn_msgtyp != DHCP_NAK)) {
- #ifdef NUTDEBUG
- if (__tcp_trf) {
- fprintf(__tcp_trs, "[DHCP-Parse Error]");
- }
- #endif
- ReleaseDynCfg(cfgp);
- return 0;
- }
- /* Calculate renewal and rebind times. */
- if (cfgp->dyn_renewalTime == 0) {
- cfgp->dyn_renewalTime = cfgp->dyn_leaseTime / 2;
- }
- if (cfgp->dyn_rebindTime == 0) {
- cfgp->dyn_rebindTime = cfgp->dyn_renewalTime + /* */
- cfgp->dyn_renewalTime / 2 + /* */
- cfgp->dyn_renewalTime / 4;
- }
- return cfgp;
- }
- /*!
- * \brief Add variable length option.
- *
- * \param op Pointer into the option buffer.
- * \param ot Option type.
- * \param ov Pointer to buffer to copy from.
- * \param len Number of octets to copy.
- *
- * \return Total number of octets added, include type and length.
- */
- static size_t DhcpAddOption(uint8_t * op, uint8_t ot, void *ov, uint8_t len)
- {
- *op++ = ot;
- *op++ = len;
- memcpy(op, ov, len);
- return 2 + len;
- }
- /*!
- * \brief Add single octet option.
- *
- * \param op Pointer into the option buffer.
- * \param ot Option type.
- * \param ov Option value.
- *
- * \return Total number of octets added, include type and length.
- */
- static size_t DhcpAddByteOption(uint8_t * op, uint8_t ot, uint8_t ov)
- {
- *op++ = ot;
- *op++ = 1;
- *op++ = ov;
- return 3;
- }
- /*!
- * \brief Add double octet option.
- *
- * \param op Pointer into the option buffer.
- * \param ot Option type.
- * \param ov Option value in host byte order. Will be converted to network
- * byte order.
- *
- * \return Total number of octets added, include type and length.
- */
- static size_t DhcpAddShortOption(uint8_t * op, uint8_t ot, uint16_t ov)
- {
- *op++ = ot;
- *op++ = 2;
- ov = htons(ov);
- memcpy(op, &ov, 2);
- return 4;
- }
- /*!
- * \brief Add parameter request option.
- *
- * RFC 2131 demands to use the same parameter request in discover and
- * request messages.
- *
- * \param op Pointer into the option buffer.
- * \param ot Option type.
- * \param ov Option value in host byte order.
- *
- * \return Total number of octets added, include type and length.
- */
- static size_t DhcpAddParmReqOption(uint8_t * op)
- {
- *op++ = DHCPOPT_PARAMREQUEST;
- *op++ = 3; /* Adjust when adding more options! */
- *op++ = DHCPOPT_NETMASK; /* Typically sent by default, but play safe. */
- *op++ = DHCPOPT_GATEWAY; /* We want a default gateway. */
- *op++ = DHCPOPT_DNS; /* We want the DNS' IP. */
- return 5; /* Adjust when adding more options! */
- }
- /*!
- * \brief Prepare a BOOTP request message header.
- *
- * A BOOTP header will be initialized at the specified buffer address
- * and the routine will add the DHCP magic cookie (RFC 1497) and an
- * additional option containing the specified DHCP message type.
- *
- * All other fields are cleared to zero.
- *
- * \param bp Pointer to the buffer to initialize.
- * \param msgtyp DHCP message type, either \ref DHCP_DISCOVER,
- * \ref DHCP_REQUEST or \ref DHCP_RELEASE.
- * \param xid Random transaction identifier.
- * \param ciaddr Our IP address. Should be set to zero unless we are in
- * BOUND, RENEW or REBINDING state and can respond to ARP
- * requests.
- * \param secs Seconds elapsed, since we began address acquisition or
- * renewal.
- *
- * \return Total number of octets added.
- */
- static unsigned int DhcpPrepHeader(BOOTP *bp, uint8_t msgtyp, uint32_t xid, uint32_t ciaddr, uint16_t secs)
- {
- uint8_t *op;
- memset(bp, 0, sizeof(*bp));
- /* Clients send bootp requests (op code 1) only. */
- bp->bp_op = 1;
- /* Ethernet addresses are type 1 with 6 octets. */
- bp->bp_htype = 1;
- bp->bp_hlen = 6;
- memcpy(bp->bp_chaddr, confnet.cdn_mac, 6);
- /* Transaction identifier. */
- bp->bp_xid = xid;
- /* Seconds elapsed since address acquisition. */
- bp->bp_secs = htons(secs);
- #ifdef DHCP_BROADCAST_FLAG
- /*
- * We do not need the broadcast flag, because our stack accepts IP
- * messages to any destination if no local address has been assigned,
- * However, we continue supporting this compile time option.
- */
- bp->bp_flags = htons(0x8000);
- #endif
- bp->bp_ciaddr = ciaddr;
- /* Add the DHCP magic cookie according to RFC 1497. */
- op = bp->bp_options;
- *op++ = 0x63;
- *op++ = 0x82;
- *op++ = 0x53;
- *op++ = 0x63;
- /* Add the DHCP message type option. */
- return DhcpAddByteOption(op, DHCPOPT_MSGTYPE, msgtyp) + 4;
- }
- /*!
- * \brief Send a DHCP message to the server.
- *
- * This routine will also add an end of option identifier and take care,
- * that the message length will not fall below the minimum expected by
- * BOOTP.
- *
- * \param sock Socket descriptor. This pointer must have been
- * retrieved by calling NutUdpCreateSocket().
- * \param addr Destination IP addres.
- * \param bp Pointer to a buffer to be used for transmission.
- * Must contain a fully initialized header and option
- * fields.
- * \param len Total number of DHCP option octets.
- *
- * \return 0 on success. On errors -1 is returned and \ref dhcpError will
- * be set to \ref DHCPERR_TRANSMIT.
- */
- static int DhcpSendMessage(UDPSOCKET * sock, uint32_t addr, BOOTP *bp, size_t len)
- {
- /* Add 'end of options'. */
- bp->bp_options[len++] = DHCPOPT_END;
- /* Maintain a BOOTP compatible minimum packet size of 300 octets.
- Thanks to Tomohiro Haraikawa. */
- len += sizeof(BOOTP) - sizeof(bp->bp_options);
- if (len < MIN_DHCP_MSGSIZE) {
- len = MIN_DHCP_MSGSIZE;
- }
- #ifdef NUTDEBUG
- if (__tcp_trf) {
- fprintf(__tcp_trs, "[DHCP-Send to %s]", inet_ntoa(addr));
- }
- #endif
- if (NutUdpSendTo(sock, addr, DHCP_SERVERPORT, bp, len) < 0) {
- dhcpError = DHCPERR_TRANSMIT;
- return -1;
- }
- return 0;
- }
- /*!
- * \brief Receive a DHCP reply from the server.
- *
- * \param sock Socket descriptor.
- * \param xid Expected transaction identifier. Incoming messages with a
- * different identifier are silently discarded.
- * \param bp Pointer to the receive buffer.
- * \param tmo Maximum number of milliseconds to wait for a valid message.
- *
- * \return The number of bytes received, if successful. The return
- * value -1 indicates an error, in which case dhcpError is
- * set to an error code. On timeout 0 is returned.
- */
- static int DhcpRecvMessage(UDPSOCKET * sock, uint32_t xid, BOOTP *bp, uint32_t tmo)
- {
- int rc;
- uint16_t port;
- uint32_t addr;
- uint32_t etim;
- uint32_t wtim;
- /* Set our start time. */
- etim = NutGetMillis();
- /* Set the initial receive timeout. */
- wtim = tmo;
- for (;;) {
- rc = NutUdpReceiveFrom(sock, &addr, &port, bp, sizeof(BOOTP), wtim);
- #ifdef NUTDEBUG
- if (__tcp_trf) {
- if (rc > 0) {
- fprintf(__tcp_trs, "[DHCP-Recv from %s]", inet_ntoa(addr));
- } else if (rc < 0) {
- fprintf(__tcp_trs, "[DHCP-Recv Error]");
- } else {
- fprintf(__tcp_trs, "[DHCP-Recv Timeout %lu]", tmo);
- }
- }
- #endif
- /* Immediately return on receive errors and timeouts. */
- if (rc <= 0) {
- if (rc < 0) {
- dhcpError = DHCPERR_RECEIVE;
- }
- break;
- }
- /* The message must at least include the BOOTP header plus five
- bytes of options (magic and end). We are quite liberal here. */
- if (rc > sizeof(BOOTP) - sizeof(bp->bp_options) + 5) {
- /* The message must be a BOOTP reply with the expected XID. */
- if (bp->bp_op == 2 && bp->bp_xid == xid) {
- /* Message is acceptable. */
- break;
- }
- }
- /* Calculate the remaining timeout for not getting trapped here
- on a busy network, which regularly broadcasts DHCP messages. */
- wtim = NutGetMillis() - etim;
- if (wtim >= tmo - 250) {
- /* Less than 250 ms left, return timeout. */
- rc = 0;
- break;
- }
- wtim = tmo - wtim;
- }
- return rc;
- }
- /*!
- * \brief Broadcast a DHCP discover message.
- *
- * \param sock Socket descriptor. This pointer must have been retrieved
- * by calling NutUdpCreateSocket().
- * \param bp Pointer to a buffer to be used for transmission. No specific
- * initialization required.
- * \param xid Random transaction identifier.
- * \param raddr Requested IP address. Optional.
- * \param secs Seconds elapsed since start of address acquisition. Related
- * requests must use the same value.
- *
- * \return 0 on success, -1 if send failed.
- */
- static int DhcpBroadcastDiscover(UDPSOCKET * sock, BOOTP *bp, uint32_t xid, uint32_t raddr, uint16_t secs)
- {
- size_t optlen;
- int len;
- uint8_t *op = bp->bp_options;
- optlen = DhcpPrepHeader(bp, DHCP_DISCOVER, xid, 0, secs);
- /* Request a specific IP if one had been assigned previously. */
- if (raddr) {
- optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
- }
- optlen += DhcpAddParmReqOption(op + optlen);
- /* Pass host name if specified in confos structure.
- * Win2k DHCP server can register this as dynamic DNS entry.
- * Also viewing DHCP lease table shows something sensible.
- */
- len = strlen(confos.hostname);
- if (len > 0) {
- optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
- }
- /* Request a maximum message size. */
- optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
- return DhcpSendMessage(sock, INADDR_BROADCAST, bp, optlen);
- }
- /*!
- * \brief Send a DHCP request message.
- *
- * \param sock Socket descriptor. This pointer must have been retrieved by
- * calling NutUdpCreateSocket().
- * \param daddr IP address of the DHCP server or \ref INADDR_BROADCAST.
- * \param bp Pointer to a buffer to be used for transmission.
- * \param xid Random transaction identifier.
- * \param caddr Our IP address. Should be set only if we are able to respond
- * to ARP requests. Otherwise must be set to 0.
- * \param raddr Requested IP address. Required.
- * \param sid Server identifier. If this request is not an offer response,
- * then set it to zero.
- * \param secs Seconds elapsed since start of address acquisition. If this
- * request is sent in reponse to an offer, the same value must
- * be used.
- *
- * \return 0 on success, -1 if send failed.
- */
- static int DhcpSendRequest(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, /* */
- uint32_t caddr, uint32_t raddr, uint32_t sid, uint16_t secs)
- {
- size_t optlen;
- int len;
- uint8_t *op = bp->bp_options;
- /* Initialize the BOOTP header. */
- optlen = DhcpPrepHeader(bp, DHCP_REQUEST, xid, caddr, secs);
- /* Add specified options. */
- if (raddr) {
- optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
- }
- if (sid) {
- optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
- }
- optlen += DhcpAddParmReqOption(op + optlen);
- /* Pass host name if specified in confos structure. */
- /* viewing DHCP lease table shows something sensible. */
- len = strlen(confos.hostname);
- if (len > 0) {
- optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
- }
- return DhcpSendMessage(sock, daddr, bp, optlen);
- }
- /*!
- * \brief Broadcast a DHCP request message.
- *
- * \param sock Socket descriptor. This pointer must have been retrieved by
- * calling NutUdpCreateSocket().
- * \param bp Pointer to a buffer to be used for transmission.
- * \param xid Random transaction identifier.
- * \param caddr Our IP address. Should be set only if we are able to respond
- * to ARP requests. Otherwise must be set to 0.
- * \param raddr Requested IP address. Required.
- * \param sid Server identifier. If this request is not an offer response,
- * then set it to zero.
- * \param secs Seconds elapsed since start of address acquisition. If this
- * request is sent in reponse to an offer, the same value must
- * be used.
- *
- * \return 0 on success, -1 if send failed.
- */
- static int DhcpBroadcastRequest(UDPSOCKET * sock, BOOTP *bp, uint32_t xid, /* */
- uint32_t caddr, uint32_t raddr, uint32_t sid, uint16_t secs)
- {
- return DhcpSendRequest(sock, INADDR_BROADCAST, bp, xid, caddr, raddr, sid, secs);
- }
- /*!
- * \brief Relinguish our DHCP lease.
- *
- * \param sock Socket descriptor. This pointer must have been retrieved by
- * calling NutUdpCreateSocket().
- * \param daddr IP address of the DHCP server.
- * \param bp Pointer to a buffer to be used for transmission.
- * \param xid Random transaction identifier.
- * \param caddr Our IP address. Should be set only if we are able to respond
- * to ARP requests. Otherwise must be set to 0.
- * \param sid Server identifier. If this request is not an offer response,
- * then set it to zero.
- *
- * \return 0 on success, -1 if send failed.
- */
- static int DhcpSendRelease(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, uint32_t caddr, uint32_t sid)
- {
- size_t optlen;
- uint8_t *op = bp->bp_options;
- /* Prepare BOOTP header. 'secs' is set to zero. */
- optlen = DhcpPrepHeader(bp, DHCP_RELEASE, xid, caddr, 0);
- /* Optionally add server identifier. */
- if (sid) {
- optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
- }
- return DhcpSendMessage(sock, daddr, bp, optlen);
- }
- /*!
- * \brief Inform DHCP about an externally allocated address.
- *
- * \param sock Socket descriptor. This pointer must have been retrieved by
- * calling NutUdpCreateSocket().
- * \param daddr IP address of the DHCP server or INADDR_BROADCAST.
- * \param bp Pointer to a buffer to be used for transmission.
- * \param xid Random transaction identifier.
- * \param caddr Our IP address. Required.
- *
- * \return 0 on success, -1 if send failed.
- */
- static int DhcpSendInform(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, uint32_t caddr)
- {
- size_t optlen;
- size_t len;
- uint8_t *op = bp->bp_options;
- /* Prepare BOOTP header. 'secs' is set to zero. */
- optlen = DhcpPrepHeader(bp, DHCP_INFORM, xid, caddr, 0);
- /* Additional options we want. */
- optlen += DhcpAddParmReqOption(op + optlen);
- /* Add our configured host name. */
- len = strlen(confos.hostname);
- if (len > 0) {
- optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
- }
- /* We should provide the maximum message size. */
- optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
- return DhcpSendMessage(sock, daddr, bp, optlen);
- }
- /*!
- * \brief Check a new offer.
- *
- * \param dyncfg Current configuration, may be NULL.
- * \param ip DHCP server IP address.
- * \param bp DHCP offer message.
- * \param len DHCP message length.
- *
- * \return Updated configuration.
- */
- static DYNCFG *CheckOffer(DYNCFG * dyncfg, BOOTP *bp, size_t len)
- {
- DYNCFG *offer;
- /* Parse the new offer. If it's invalid, return the current
- configuration. */
- offer = ParseReply(bp, len);
- if (offer == NULL) {
- return dyncfg;
- }
- /* Discard anything which is not an offer. */
- if (offer->dyn_msgtyp != DHCP_OFFER) {
- ReleaseDynCfg(offer);
- return dyncfg;
- }
- /* First offer, take it. */
- if (dyncfg == NULL) {
- dyncfg = offer;
- }
- /*
- * Check if the new offer is better than the current configuration:
- */
- else {
- /* If we remember a previously allocated IP which isn't in the
- current configuration but in the new offer, then let's take
- the new one. */
- if (confnet.cdn_ip_addr & confnet.cdn_ip_mask) {
- if (dyncfg->dyn_yiaddr != confnet.cdn_ip_addr && /* */
- offer->dyn_yiaddr == confnet.cdn_ip_addr) {
- ReleaseDynCfg(dyncfg);
- dyncfg = offer;
- }
- }
- /* In the second place prefer long lease times. */
- else if (offer->dyn_leaseTime > dyncfg->dyn_leaseTime) {
- ReleaseDynCfg(dyncfg);
- dyncfg = offer;
- }
- /* The new one deosn't offer anything interesting. Discard it. */
- else {
- ReleaseDynCfg(offer);
- }
- }
- return dyncfg;
- }
- /*! \fn NutDhcpClient(void *arg)
- * \brief DHCP client thread.
- *
- * This thread implements a DHCP state machine and is automatically started
- * when calling NutDhcpIfConfig() or NutDhcpInform().
- *
- * \bug We are not able to shutdown our interface, which may cause problems
- * if out original DHCP server dies.
- *
- * \todo We are using a bunch of global variables, which must be associated
- * to a specific interfase if we want to support more than one
- * Ethernet port.
- */
- THREAD(NutDhcpClient, arg)
- {
- DYNCFG *reply = NULL;
- UDPSOCKET *sock = NULL;
- BOOTP *bp = NULL;
- int n;
- uint32_t xid;
- IFNET *nif;
- uint16_t secs = 0;
- uint32_t aquisStart = NutGetSeconds();
- uint32_t leaseStart = 0;
- uint32_t procStart;
- uint32_t napTime;
- ureg_t retries;
- uint32_t tmo = MIN_DHCP_WAIT;
- uint32_t last_ip = confnet.cdn_ip_addr;
- uint32_t server_ip;
- nif = ((NUTDEVICE *) arg)->dev_icb;
- /*
- * Generate a random transaction identifier based on our MAC
- * address with the least significant byte of the MAC address
- * becoming the most significant byte of the identifier. This
- * should give a sufficient unique value when several Ethernuts
- * are started concurrently.
- */
- xid = 0;
- for (retries = 0; retries < sizeof(xid); retries++) {
- xid <<= 8;
- xid += nif->if_mac[5 - retries];
- }
- retries = 0;
- for (;;) {
- procStart = NutGetSeconds();
- #ifdef NUTDEBUG
- if (__tcp_trf) {
- fprintf(__tcp_trs, "\n[%u.DHCP-", retries + 1);
- switch (dhcpState) {
- case DHCPST_INIT:
- fprintf(__tcp_trs, "INIT]");
- break;
- case DHCPST_SELECTING:
- fprintf(__tcp_trs, "SELECTING]");
- break;
- case DHCPST_REQUESTING:
- fprintf(__tcp_trs, "REQUESTING]");
- break;
- case DHCPST_REBOOTING:
- fprintf(__tcp_trs, "REBOOTING %s]", inet_ntoa(last_ip));
- break;
- case DHCPST_BOUND:
- fprintf(__tcp_trs, "BOUND %lu]", procStart - leaseStart);
- break;
- case DHCPST_RENEWING:
- fprintf(__tcp_trs, "RENEWING %lu]", procStart - leaseStart);
- break;
- case DHCPST_REBINDING:
- fprintf(__tcp_trs, "REBINDING %lu]", procStart - leaseStart);
- break;
- case DHCPST_INFORMING:
- fprintf(__tcp_trs, "INFORMING]");
- break;
- case DHCPST_RELEASING:
- fprintf(__tcp_trs, "RELEASING]");
- break;
- case DHCPST_IDLE:
- if (dhcpError) {
- fprintf(__tcp_trs, "ERROR %u]", dhcpError);
- } else {
- fprintf(__tcp_trs, "IDLE]");
- }
- break;
- default:
- fprintf(__tcp_trs, "UNKNOWN %u]", dhcpState);
- break;
- }
- }
- #endif
- /*
- * Setup some values based on the number of retry attempts.
- */
- server_ip = INADDR_BROADCAST; /* Broadcasting is default. */
- if (retries) {
- /* Double our timeout on each retry. */
- tmo += tmo;
- if (tmo > MAX_DHCP_WAIT) {
- tmo = MAX_DHCP_WAIT;
- }
- } else {
- /* Start with minimum timeout first. */
- tmo = MIN_DHCP_WAIT;
- /* Use a new xid for the first message in each state except
- * when requesting, where we should continue using the xid
- * from the offer message we received.
- */
- if (dhcpState != DHCPST_REQUESTING) {
- xid++;
- }
- /* If we know the server's IP, try to unicast on the first
- attempt. */
- if (dhcpConfig && dhcpConfig->dyn_sid) {
- server_ip = dhcpConfig->dyn_sid;
- }
- }
- /*
- * Keep track of the API timeout.
- */
- if (dhcpState != DHCPST_IDLE && dhcpState != DHCPST_BOUND && dhcpApiTimeout != NUT_WAIT_INFINITE) {
- uint32_t tt = NutGetMillis() - dhcpApiStart;
- if (dhcpApiTimeout <= tt) {
- dhcpError = DHCPERR_TIMEOUT;
- dhcpState = DHCPST_IDLE;
- continue;
- }
- tt = dhcpApiTimeout - tt;
- if (tt < tmo) {
- tmo = tt;
- }
- }
- /*
- * Keep track of acquisition time.
- */
- if (dhcpState == DHCPST_SELECTING || dhcpState == DHCPST_RENEWING || dhcpState == DHCPST_REBINDING) {
- /* For retries make sure that secs doesn't overflow. */
- if (retries) {
- if (procStart - aquisStart > 0xffffUL) {
- secs = 0xffff;
- } else {
- secs = (uint16_t) (procStart - aquisStart);
- }
- }
- /* For first transmissions make sure that secs is zero. */
- else {
- aquisStart = procStart;
- secs = 0;
- }
- }
- /*
- * Release UDP socket and buffer in states with long inactive time.
- */
- if (dhcpState == DHCPST_BOUND || dhcpState == DHCPST_IDLE) {
- if (sock) {
- NutUdpDestroySocket(sock);
- sock = NULL;
- }
- free(bp);
- bp = NULL;
- }
- /*
- * In all other states we need the socket and the buffer.
- */
- else {
- /*
- * Check if something else configured our interface.
- */
- if (dhcpConfig == NULL && nif->if_local_ip) {
- /* If we need additional configuration, we can sent
- a DHCP Inform message here. */
- dhcpState = DHCPST_IDLE;
- continue;
- }
- if (sock == NULL || bp == NULL) {
- if (sock == NULL) {
- sock = NutUdpCreateSocket(DHCP_CLIENTPORT);
- }
- if (bp == NULL) {
- bp = malloc(sizeof(BOOTP));
- }
- if (sock == NULL || bp == NULL) {
- /* Looks like we are out of memory. */
- dhcpError = DHCPERR_SYSTEM;
- dhcpState = DHCPST_IDLE;
- /* At this point either socket or buffer may be allocated.
- Thus we need to jump back to the top of our state loop
- to release it. */
- continue;
- }
- #if MAX_DHCP_BUFSIZE
- {
- uint16_t max_ms = MAX_DHCP_BUFSIZE;
- NutUdpSetSockOpt(sock, SO_RCVBUF, &max_ms, sizeof(max_ms));
- }
- #endif
- }
- }
- /*
- * (Re)Start.
- */
- if (dhcpState == DHCPST_INIT) {
- /* Clear the retry counter. */
- retries = 0;
- /* Use a new XID on each attempt. */
- xid++;
- /* Determine whether this is an initial boot or a reboot. */
- if ((last_ip & confnet.cdn_ip_mask) == 0) {
- /* No previous IP, start from ground up. */
- dhcpState = DHCPST_SELECTING;
- } else {
- /* We got a previously allocated IP configuration from
- * non-volatile configuration memory. Try to re-use it. */
- dhcpState = DHCPST_REBOOTING;
- }
- }
- /*
- * Broadcast discover and collect incoming offers.
- */
- else if (dhcpState == DHCPST_SELECTING) {
- if (retries++ > MAX_DCHP_RETRIES) {
- /* Too many retries while discovering DHCP. Give up. */
- dhcpError = DHCPERR_TIMEOUT;
- dhcpState = DHCPST_IDLE;
- }
- /* Send the discovering broadcast. */
- else if (DhcpBroadcastDiscover(sock, bp, xid, last_ip, secs) < 0) {
- /* Fatal transmit error on broadcast. */
- dhcpState = DHCPST_IDLE;
- } else {
- /* Collect incoming offers. */
- while ((n = DhcpRecvMessage(sock, xid, bp, tmo)) > 0) {
- /* Check if this is a valid offer. */
- dhcpConfig = CheckOffer(dhcpConfig, bp, n);
- if (dhcpConfig) {
- /* If the callers timeout is low, do not collect
- more than one. Thanks to Jelle Kok. */
- if (dhcpApiTimeout < MIN_DHCP_WAIT * 3) {
- break;
- }
- /* Switch to lowest timeout after we received
- a first response. */
- tmo = MIN_DHCP_WAIT;
- }
- }
- /* Change to ERROR state on fatal receive errors. */
- if (n < 0) {
- dhcpState = DHCPST_IDLE;
- }
- /* Change to REQUESTING state if we got a valid offer.
- Otherwise we stay in SELECTING state. */
- else if (dhcpConfig) {
- retries = 0;
- dhcpState = DHCPST_REQUESTING;
- }
- }
- }
- /*
- * Send request and wait for an acknowledge.
- */
- else if (dhcpState == DHCPST_REQUESTING) {
- if (retries++ > MAX_DCHP_RETRIES) {
- /* Too many retries with this server, fall back to discovery. */
- dhcpState = DHCPST_INIT;
- }
- /* Request an offered configuration. According to RFC 2131 this
- has to be broadcasted. */
- else if (DhcpBroadcastRequest(sock, bp, xid, 0, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid, secs) < 0) {
- /* Fatal transmit error on broadcast. Give up. */
- dhcpState = DHCPST_IDLE;
- } else {
- n = DhcpRecvMessage(sock, xid, bp, tmo);
- if (n < 0) {
- /* Fatal receive error. */
- dhcpState = DHCPST_IDLE;
- }
- else if (n > 0) {
- reply = ParseReply(bp, n);
- if (reply) {
- /* The server accepted our request. We are bound. */
- if (reply->dyn_msgtyp == DHCP_ACK) {
- ReleaseDynCfg(dhcpConfig);
- dhcpConfig = reply;
- reply = 0;
- leaseStart = aquisStart;
- dhcpState = DHCPST_BOUND;
- }
- /* The server declines a previously offered configuration.
- Restart discovery. */
- else if (reply->dyn_msgtyp == DHCP_NAK) {
- dhcpState = DHCPST_INIT;
- }
- }
- }
- }
- }
- /*
- * Reusing a previously allocated network address after reboot.
- */
- else if (dhcpState == DHCPST_REBOOTING) {
- if (++retries > MAX_DCHP_RETRIES) {
- /* Too many retries, fall back to discovery. */
- last_ip = 0;
- dhcpState = DHCPST_INIT;
- }
- /* Broadcast a request for our previous configuration. */
- else if (DhcpBroadcastRequest(sock, bp, xid, 0, last_ip, 0, secs) < 0) {
- /* Fatal transmit error on broadcast. Give up. */
- dhcpState = DHCPST_IDLE;
- } else {
- n = DhcpRecvMessage(sock, xid, bp, tmo);
- if (n < 0) {
- /* Fatal receive error. */
- dhcpState = DHCPST_IDLE;
- }
- else if (n > 0) {
- reply = ParseReply(bp, n);
- if (reply) {
- if (reply->dyn_msgtyp == DHCP_ACK) {
- ReleaseDynCfg(dhcpConfig);
- dhcpConfig = reply;
- reply = 0;
- leaseStart = aquisStart;
- dhcpState = DHCPST_BOUND;
- }
- else if (reply->dyn_msgtyp == DHCP_NAK) {
- /* Either our previous address had been allocated by
- someone else or we changed the network. Remove the
- previous address and restart. */
- last_ip = 0;
- dhcpState = DHCPST_INIT;
- }
- }
- }
- }
- }
- /*
- * Maintain lease time.
- */
- else if (dhcpState == DHCPST_BOUND) {
- retries = 0;
- dhcpApiTimeout = NUT_WAIT_INFINITE;
- NutEventBroadcast(&dhcpDone);
- if (dhcpConfig->dyn_renewalTime <= procStart - leaseStart) {
- dhcpState = DHCPST_RENEWING;
- } else {
- /* Calculate the remaining lease time and take a nap. */
- napTime = dhcpConfig->dyn_renewalTime - (procStart - leaseStart);
- if (napTime > MAX_DHCP_NAPTIME) {
- napTime = MAX_DHCP_NAPTIME;
- }
- NutEventWait(&dhcpWake, napTime * 1000UL);
- }
- }
- /*
- * Waiting for an acknowledge of our renewal request.
- */
- else if (dhcpState == DHCPST_RENEWING) {
- retries++;
- if (tmo / 1000 > dhcpConfig->dyn_rebindTime - (procStart - leaseStart)) {
- tmo = (dhcpConfig->dyn_rebindTime - (procStart - leaseStart)) * 1000;
- }
- if (dhcpConfig->dyn_rebindTime <= procStart - leaseStart) {
- retries = 0;
- dhcpState = DHCPST_REBINDING;
- }
- /* Send a request to our leasing server. We must not include
- the server identifier. */
- else if (DhcpSendRequest(sock, dhcpConfig->dyn_sid, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) <
- 0) {
- /* Unicast transmit error. */
- retries = 0;
- dhcpState = DHCPST_REBINDING;
- } else {
- n = DhcpRecvMessage(sock, xid, bp, tmo);
- if (n < 0) {
- /* Fatal receive error. */
- dhcpState = DHCPST_IDLE;
- }
- else if (n > 0) {
- reply = ParseReply(bp, n);
- if (reply) {
- if (reply->dyn_msgtyp == DHCP_ACK) {
- /* Got an acknowledge, return to bound state. */
- ReleaseDynCfg(dhcpConfig);
- dhcpConfig = reply;
- reply = 0;
- leaseStart = aquisStart;
- dhcpState = DHCPST_BOUND;
- }
- else if (reply->dyn_msgtyp == DHCP_NAK) {
- /* Unexpected NAK. */
- retries = 0;
- dhcpState = DHCPST_REBINDING;
- }
- }
- }
- }
- }
- /*
- * Waiting for an acknowledge of our rebind request.
- */
- else if (dhcpState == DHCPST_REBINDING) {
- retries++;
- if (tmo / 1000 > dhcpConfig->dyn_leaseTime - (procStart - leaseStart)) {
- tmo = (dhcpConfig->dyn_leaseTime - (procStart - leaseStart)) * 1000;
- }
- if (dhcpConfig->dyn_leaseTime <= procStart - leaseStart) {
- retries = 0;
- dhcpState = DHCPST_IDLE;
- }
- /* Broadcast a request for our previous configuration. We
- must not include a server identifier. */
- else if (DhcpBroadcastRequest(sock, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) < 0) {
- /* Fatal transmit error on broadcast. Give up. */
- dhcpState = DHCPST_IDLE;
- } else {
- n = DhcpRecvMessage(sock, xid, bp, tmo);
- if (n < 0) {
- /* Fatal receive error. */
- dhcpState = DHCPST_IDLE;
- }
- else if (n > 0) {
- reply = ParseReply(bp, n);
- if (reply) {
- if (reply->dyn_msgtyp == DHCP_ACK) {
- /* Got an acknowledge, return to bound state. */
- ReleaseDynCfg(dhcpConfig);
- dhcpConfig = reply;
- reply = 0;
- leaseStart = aquisStart;
- dhcpState = DHCPST_BOUND;
- }
- else if (reply->dyn_msgtyp == DHCP_NAK) {
- /*
- * We have a problem here if the last DHCP server died.
- * If a backup server exists, it may probe our IP address
- * using ARP or ICMP. Our interface is up and responding,
- * so the backup server may think that the IP address
- * is in use and respond with NAK. Without shutting
- * down our interface (not yet implemented) we are stuck.
- * We switch to discovery state, but the problem remains.
- */
- dhcpState = DHCPST_INIT;
- }
- }
- }
- }
- }
- /*
- * Send an inform and wait for its (optional) echo.
- */
- else if (dhcpState == DHCPST_INFORMING) {
- if (retries++ > MAX_DCHP_RETRIES) {
- dhcpState = DHCPST_IDLE;
- } else if (DhcpSendInform(sock, server_ip, bp, xid, nif->if_local_ip) < 0) {
- if (server_ip == INADDR_BROADCAST) {
- dhcpState = DHCPST_IDLE;
- }
- } else {
- n = DhcpRecvMessage(sock, xid, bp, tmo);
- if (n) {
- if (n > 0) {
- reply = ParseReply(bp, n);
- if (reply && reply->dyn_msgtyp == DHCP_ACK) {
- /* Take over this configuration. */
- ReleaseDynCfg(dhcpConfig);
- dhcpConfig = reply;
- reply = 0;
- }
- }
- }
- dhcpState = DHCPST_IDLE;
- }
- }
- /*
- * Send a release and wait for its (optional) echo.
- */
- else if (dhcpState == DHCPST_RELEASING) {
- if (dhcpConfig == NULL || /* Not configured. */
- retries++ > MAX_DCHP_RELEASE_RETRIES || /* Too many retries. */
- DhcpSendRelease(sock, server_ip, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid) < 0) {
- if (server_ip == INADDR_BROADCAST) {
- dhcpState = DHCPST_IDLE;
- }
- } else {
- n = DhcpRecvMessage(sock, xid, bp, tmo);
- if (n < 0) {
- /* Fatal receive error. */
- dhcpState = DHCPST_IDLE;
- }
- else if (n > 0) {
- reply = ParseReply(bp, n);
- if (reply) {
- if (reply->dyn_msgtyp == DHCP_ACK) {
- dhcpState = DHCPST_IDLE;
- }
- else if (reply->dyn_msgtyp == DHCP_NAK) {
- dhcpState = DHCPST_IDLE;
- }
- }
- }
- }
- }
- /*
- * We are done somehow. Either a fatal error occured or we
- * reached the specified timeout time or our lease has been
- * release or something else configured our interface.
- * Release all resources and wait for a new API call to
- * wake us up.
- */
- else if (dhcpState == DHCPST_IDLE) {
- ReleaseDynCfg(dhcpConfig);
- dhcpConfig = NULL;
- retries = 0;
- dhcpApiTimeout = NUT_WAIT_INFINITE;
- NutEventBroadcast(&dhcpDone);
- NutEventWait(&dhcpWake, NUT_WAIT_INFINITE);
- }
- /* Release any received reply. */
- if (reply) {
- ReleaseDynCfg(reply);
- reply = 0;
- }
- }
- }
- /*!
- * \brief Activate the DHCP client thread.
- *
- * Start the DHCP thread if not running or wake it up. Pass the caller's
- * timeout to the thread and wait an infinite time. We rely on the thread
- * to wake us up on timeout.
- *
- * \param name Name of the registered Ethernet device.
- * \param state State to start with.
- * \param timeout Maximum number of milliseconds to wait. To disable
- * timeout, set this parameter to \ref NUT_WAIT_INFINITE.
- * This value must be larger than 3 times of \ref MIN_DHCP_WAIT
- * to enable collection of offers from multiple servers.
- */
- static int DhcpKick(const char *name, uint8_t state, uint32_t timeout)
- {
- NUTDEVICE *dev;
- IFNET *nif;
- /* Lookup the Ethernet device. */
- dev = NutDeviceLookup(name);
- if (dev == NULL || dev->dev_type != IFTYP_NET) {
- dhcpError = DHCPERR_BADDEV;
- return -1;
- }
- nif = dev->dev_icb;
- if (nif == NULL || nif->if_type != IFT_ETHER) {
- dhcpError = DHCPERR_BADDEV;
- return -1;
- }
- /* Initialize timeout checking. */
- dhcpApiStart = NutGetMillis();
- dhcpApiTimeout = timeout;
- dhcpState = state;
- if (dhcpThread == NULL) {
- dhcpThread = NutThreadCreate("dhcpc", NutDhcpClient, dev,
- (NUT_THREAD_DHCPSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD);
- }
- /* Wake up the DHCP thread. Note, that we use an asynchronous post
- without context switch. This is required because the DHCP thread
- broadcasts an event to dhcpDone, which will not signal an empty
- queue. If that broadcast happens before we enter the following
- wait, then we will be trapped. Thanks to Henrik Maier for this
- important fix. */
- NutEventPostAsync(&dhcpWake);
- NutEventWait(&dhcpDone, NUT_WAIT_INFINITE);
- return 0;
- }
- /*!
- * \brief Automatically configure an Ethernet network interface.
- *
- * If no MAC address is specified, this routine will try to read a
- * previously stored configuration from the EEPROM. If this retrieves
- * a fixed IP configuration, then the network interface will be
- * immediately configured with these values by calling NutNetIfConfig().
- * If no valid IP configuration has been read, then this routine will
- * start the DHCP client thread and wait upto a given number of
- * milliseconds for an acknowledged configuration from a DHCP server.
- *
- * If a MAC address has been specified, this routine will not read the
- * EEPROM configuration. If the application has set the global
- * \ref CONFNET structure to a valid IP configuration before calling
- * this function, then the network interface will be immediately
- * configured with these values by calling NutNetIfConfig(). Otherwise
- * the DHCP client thread will be started and this routine will wait
- * upto a given number of milliseconds for an acknowledged configuration
- * from a DHCP server.
- *
- * \param name Name of the registered Ethernet device.
- * \param mac MAC address of the destination. Set NULL to use the
- * configuration stored in the EEPROM.
- * \param timeout Maximum number of milliseconds to wait. To disable
- * timeout, set this parameter to \ref NUT_WAIT_INFINITE.
- * Otherwise the value must be larger than 3 times of
- * \ref MIN_DHCP_WAIT to enable collection of offers
- * from multiple servers.
- *
- * \return 0 if the interface had been successfully configured. In most
- * cases this information is sufficient, because the application
- * will not care whether the configuration had been provided by
- * a DHCP server or EEPROM values. However, if EEPROM values had
- * been used, then no DNS servers had been set. The application
- * can call NutDhcpStatus() to check the DHCP bound state. -1 is
- * returned if the interface configuration failed. In this case
- * NutDhcpError() can be called to get a more specific error
- * code.
- */
- int NutDhcpIfConfig(const char *name, uint8_t * mac, uint32_t timeout)
- {
- NUTDEVICE *dev;
- IFNET *nif = NULL;
- /*
- * Verify the given Ethernet device.
- */
- dev = NutDeviceLookup(name);
- if (dev && dev->dev_type == IFTYP_NET) {
- nif = (IFNET *) dev->dev_icb;
- }
- if (nif == NULL || nif->if_type != IFT_ETHER) {
- /* Not a network device or wrong interface type. */
- dhcpError = DHCPERR_BADDEV;
- return -1;
- }
- /*
- * Determine the MAC address.
- */
- if (mac && !ETHER_IS_BROADCAST(mac)) {
- /* If the caller specified a valid MAC address, we use it
- to override the configuration. */
- memcpy(confnet.cdn_mac, mac, sizeof(confnet.cdn_mac));
- }
- else if (ETHER_IS_ZERO(nif->if_mac)) {
- /* The interface has not defined a MAC. Try to get one from
- non-volatile memory. */
- NutNetLoadConfig(name);
- }
- /*
- * Check if we have a valid MAC address. In order to maintain
- * backward compatibility, we accept anything which is neither
- * zero nor the broadcast address. Later versions may become more
- * restrictive and demand a valid unicast address.
- */
- if (ETHER_IS_ZERO(confnet.cdn_mac) || ETHER_IS_BROADCAST(confnet.cdn_mac)) {
- dhcpError = DHCPERR_NOMAC;
- return -1;
- }
- /*
- * Copy the MAC address to the interface structure. This will
- * magically enable the brain dead interface.
- */
- memcpy(nif->if_mac, confnet.cdn_mac, 6);
- NutSleep(500);
- /*
- * Zero out the ip address and mask. This allows to switch between
- * DHCP and static IP addresses without resetting/power cycling.
- * See patch #2903940.
- */
- nif->if_local_ip = 0;
- nif->if_mask = confnet.cdn_ip_mask;
- /*
- * If the EEPROM contains a fixed network configuration, we skip DHCP.
- */
- if (confnet.cdn_cip_addr & confnet.cdn_ip_mask) {
- /* Give up a previously allocated lease. See patch #2903940. */
- (void)NutDhcpRelease(name, (3*MIN_DHCP_WAIT));
- confnet.cdn_ip_addr = confnet.cdn_cip_addr;
- return NutNetIfConfig2(name,
- confnet.cdn_mac,
- confnet.cdn_ip_addr,
- confnet.cdn_ip_mask,
- confnet.cdn_gateway);
- }
- /*
- * Start the DHCP thread if not running or wake it up. Pass the caller's
- * timeout to the thread and wait an infinite time. We rely on the thread
- * to wake us up on timeout.
- */
- if (DhcpKick(name, DHCPST_INIT, timeout) == 0) {
- /*
- * The thread finished its task. If it reached the bound state, then
- * we got a valid configuration from DHCP.
- */
- if (dhcpState == DHCPST_BOUND) {
- #ifdef NUTDEBUG
- if (__tcp_trf) {
- fprintf(__tcp_trs, "[DHCP-Config %s]", inet_ntoa(dhcpConfig->dyn_yiaddr));
- }
- #endif
- NutNetIfSetup(dev, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_netmask, dhcpConfig->dyn_gateway);
- NutDnsConfig2(NULL, NULL, dhcpConfig->dyn_pdns, dhcpConfig->dyn_sdns);
- return 0;
- }
- /*
- * Our interface has been configured externally, possibly by auto
- * ARP or a similar function implemented by the application.
- */
- if (nif->if_local_ip) {
- #ifdef NUTDEBUG
- if (__tcp_trf) {
- fprintf(__tcp_trs, "[DHCP-External %s]", inet_ntoa(nif->if_local_ip));
- }
- #endif
- return 0;
- }
- /*
- * DHCP failed. In case we remember a previously allocated address,
- * then let's use it.
- */
- if ((confnet.cdn_ip_addr & confnet.cdn_ip_mask) != 0) {
- #ifdef NUTDEBUG
- if (__tcp_trf) {
- fprintf(__tcp_trs, "[DHCP-Reusing %s]", inet_ntoa(confnet.cdn_ip_addr));
- }
- #endif
- NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
- return 0;
- }
- }
- return -1;
- }
- /*!
- * \brief Relinguish our DHCP lease.
- *
- * This function may be called by the application if we are moving
- * to another network. It helps the DHCP server to tidy up his
- * allocation table, but is not a required DHCP function.
- *
- * Upon return, the system should be shut down within 20 seconds.
- *
- * The client must reside in state \ref DHCPST_BOUND.
- *
- * \param name Name of the registered Ethernet device, currently ignored.
- * \param timeout Maximum number of milliseconds to wait.
- *
- * \return 0 on success or -1 in case of an error.
- */
- int NutDhcpRelease(const char *name, uint32_t timeout)
- {
- /* Check the state. */
- if (dhcpState != DHCPST_BOUND) {
- dhcpError = DHCPERR_STATE;
- return -1;
- }
- /* Action! */
- return DhcpKick(name, DHCPST_RELEASING, timeout);
- }
- /*!
- * \brief Inform DHCP about an allocated address.
- *
- * The client must reside in state \ref DHCPST_IDLE.
- *
- * \param name Name of the registered Ethernet device, currently ignored.
- * \param timeout Maximum number of milliseconds to wait.
- *
- * \return 0 on success or -1 in case of an error.
- */
- int NutDhcpInform(const char *name, uint32_t timeout)
- {
- /* Check the state. */
- if (dhcpState != DHCPST_IDLE) {
- dhcpError = DHCPERR_STATE;
- return -1;
- }
- /* Action! */
- return DhcpKick(name, DHCPST_INFORMING, timeout);
- }
- /*!
- * \brief Return DHCP client status.
- *
- * \param name Name of the registered Ethernet device, currently ignored.
- *
- * \return DHCP status code, which may be any of the following:
- * - \ref DHCPST_INIT
- * - \ref DHCPST_SELECTING
- * - \ref DHCPST_REQUESTING
- * - \ref DHCPST_REBOOTING
- * - \ref DHCPST_BOUND
- * - \ref DHCPST_RENEWING
- * - \ref DHCPST_REBINDING
- * - \ref DHCPST_INFORMING
- * - \ref DHCPST_RELEASING
- * - \ref DHCPST_IDLE
- */
- int NutDhcpStatus(const char *name)
- {
- return dhcpState;
- }
- /*!
- * \brief Return DHCP error code.
- *
- * Possible error codes are
- *
- * - \ref DHCPERR_TIMEOUT
- * - \ref DHCPERR_NOMAC
- * - \ref DHCPERR_BADDEV
- * - \ref DHCPERR_SYSTEM
- * - \ref DHCPERR_TRANSMIT
- * - \ref DHCPERR_RECEIVE
- *
- * The error will be cleared upon return.
- *
- * \param name Name of the registered Ethernet device, currently ignored.
- *
- * \return DHCP error code or 0 if no error occured.
- */
- int NutDhcpError(const char *name)
- {
- int rc = dhcpError;
- dhcpError = 0;
- return rc;
- }
- /*!
- * \brief Check if DHCP has configured our interface
- *
- * \deprecated Applications should use NutDhcpStatus().
- *
- * \return 0 if DHCP is in bound state.
- */
- int NutDhcpIsConfigured(void)
- {
- return (dhcpState == DHCPST_BOUND);
- }
- /*@}*/
|