00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00185 #include <sys/thread.h>
00186 #include <sys/event.h>
00187 #include <sys/timer.h>
00188 #include <sys/confnet.h>
00189 #include <sys/confos.h>
00190
00191 #include <stdlib.h>
00192 #include <string.h>
00193 #include <time.h>
00194
00195 #include <arpa/inet.h>
00196 #include <netinet/in.h>
00197 #include <netdb.h>
00198 #include <net/route.h>
00199 #include <sys/socket.h>
00200 #include <pro/dhcp.h>
00201
00202 #ifdef NUTDEBUG
00203 #include <net/netdebug.h>
00204 #endif
00205
00206 #if 0
00207
00208 #define NUTDEBUG
00209 #include <stdio.h>
00210 #define __tcp_trs stdout
00211 static uint_fast8_t __tcp_trf = 1;
00212 #endif
00213
00218
00225
00231 #ifndef DHCP_SERVERPORT
00232 #define DHCP_SERVERPORT 67
00233 #endif
00234
00240 #ifndef DHCP_CLIENTPORT
00241 #define DHCP_CLIENTPORT 68
00242 #endif
00243
00253 #ifndef MAX_DHCP_MSGSIZE
00254 #define MAX_DHCP_MSGSIZE 576
00255 #endif
00256
00264 #ifndef MIN_DHCP_MSGSIZE
00265 #define MIN_DHCP_MSGSIZE 300
00266 #endif
00267
00283 #ifndef MAX_DHCP_BUFSIZE
00284 #define MAX_DHCP_BUFSIZE 1728
00285 #endif
00286
00296 #ifndef MIN_DHCP_WAIT
00297 #define MIN_DHCP_WAIT 4000
00298 #endif
00299
00308 #ifndef MAX_DHCP_WAIT
00309 #define MAX_DHCP_WAIT 64000
00310 #endif
00311
00320 #ifndef MAX_DCHP_RETRIES
00321 #define MAX_DCHP_RETRIES 3
00322 #endif
00323
00332 #ifndef MAX_DCHP_RELEASE_RETRIES
00333 #define MAX_DCHP_RELEASE_RETRIES 0
00334 #endif
00335
00343 #ifndef DHCP_DEFAULT_LEASE
00344 #define DHCP_DEFAULT_LEASE 43200
00345 #endif
00346
00352 #ifndef MAX_DHCP_NAPTIME
00353 #define MAX_DHCP_NAPTIME 4294967
00354 #endif
00355
00361 #ifndef NUT_THREAD_DHCPSTACK
00362 #define NUT_THREAD_DHCPSTACK 512
00363 #endif
00364
00373
00376 #define DHCP_DISCOVER 1
00377
00382 #define DHCP_OFFER 2
00383
00391 #define DHCP_REQUEST 3
00392
00397 #define DHCP_DECLINE 4
00398
00403 #define DHCP_ACK 5
00404
00409 #define DHCP_NAK 6
00410
00413 #define DHCP_RELEASE 7
00414
00419 #define DHCP_INFORM 8
00420
00430
00437 #define DHCPOPT_PAD 0
00438
00442 #define DHCPOPT_NETMASK 1
00443
00447 #define DHCPOPT_GATEWAY 3
00448
00452 #define DHCPOPT_DNS 6
00453
00457 #define DHCPOPT_HOSTNAME 12
00458
00462 #define DHCPOPT_DOMAIN 15
00463
00467 #define DHCPOPT_BROADCAST 28
00468
00472 #define DHCPOPT_REQESTIP 50
00473
00477 #define DHCPOPT_LEASETIME 51
00478
00482 #define DHCPOPT_MSGTYPE 53
00483
00487 #define DHCPOPT_SID 54
00488
00492 #define DHCPOPT_PARAMREQUEST 55
00493
00497 #define DHCPOPT_MAXMSGSIZE 57
00498
00502 #define DHCPOPT_RENEWALTIME 58
00503
00507 #define DHCPOPT_REBINDTIME 59
00508
00512 #define DHCPOPT_END 255
00513
00519 typedef struct __attribute__ ((packed)) bootp BOOTP;
00520
00524 struct __attribute__ ((packed)) bootp {
00525 uint8_t bp_op;
00526 uint8_t bp_htype;
00527 uint8_t bp_hlen;
00528 uint8_t bp_hops;
00529 uint32_t bp_xid;
00530 uint16_t bp_secs;
00531 uint16_t bp_flags;
00532 uint32_t bp_ciaddr;
00533 uint32_t bp_yiaddr;
00534 uint32_t bp_siaddr;
00535 uint32_t bp_giaddr;
00536 uint8_t bp_chaddr[16];
00537 char bp_sname[64];
00538 char bp_file[128];
00539 uint8_t bp_options[312];
00540 };
00541
00545 typedef struct dyn_cfg DYNCFG;
00546
00550 struct dyn_cfg {
00551 uint8_t dyn_msgtyp;
00552 uint32_t dyn_yiaddr;
00553 uint32_t dyn_netmask;
00554 uint32_t dyn_broadcast;
00555 uint32_t dyn_gateway;
00556 uint32_t dyn_pdns;
00557 uint32_t dyn_sdns;
00558 uint32_t dyn_sid;
00559 uint32_t dyn_renewalTime;
00560 uint32_t dyn_rebindTime;
00561 uint32_t dyn_leaseTime;
00562 uint8_t *dyn_hostname;
00563 uint8_t *dyn_domain;
00564 };
00565
00572 static DYNCFG *dhcpConfig;
00573
00580 static HANDLE dhcpThread;
00581
00585 static uint8_t dhcpState;
00586
00590 static int dhcpError;
00591
00597 static HANDLE dhcpWake;
00598
00604 static HANDLE dhcpDone;
00605
00611 static uint32_t dhcpApiTimeout;
00612
00619 static uint32_t dhcpApiStart;
00620
00627 #ifdef __arm__
00628 static NUTDEVICE *dhcpDev;
00629 #endif
00630
00642 static void copy_str(uint8_t ** dst, void *src, int len)
00643 {
00644 if (*dst) {
00645 free(*dst);
00646 }
00647 if ((*dst = malloc(len + 1)) != 0) {
00648 if (len) {
00649 memcpy(*dst, src, len);
00650 }
00651 *(*dst + len) = 0;
00652 }
00653 }
00654
00662 static void ReleaseDynCfg(DYNCFG * dyncfg)
00663 {
00664 if (dyncfg) {
00665 if (dyncfg->dyn_hostname) {
00666 free(dyncfg->dyn_hostname);
00667 }
00668 if (dyncfg->dyn_domain) {
00669 free(dyncfg->dyn_domain);
00670 }
00671 free(dyncfg);
00672 }
00673 }
00674
00686 static DYNCFG *ParseReply(BOOTP *bp, int len)
00687 {
00688 uint8_t *op;
00689 int left;
00690 DYNCFG *cfgp;
00691
00692
00693 if ((cfgp = malloc(sizeof(DYNCFG))) == 0) {
00694 return 0;
00695 }
00696 memset(cfgp, 0, sizeof(DYNCFG));
00697 cfgp->dyn_leaseTime = DHCP_DEFAULT_LEASE;
00698
00699
00700 memcpy(&cfgp->dyn_yiaddr, &bp->bp_yiaddr, 4);
00701
00702
00703
00704
00705
00706 op = bp->bp_options + 4;
00707 left = len - (sizeof(*bp) - sizeof(bp->bp_options)) - 4;
00708 while (*op != DHCPOPT_END && left > 0) {
00709 uint8_t ol;
00710
00711 #ifdef NUTDEBUG
00712 if (__tcp_trf) {
00713 fprintf(__tcp_trs, "[DHCP-Opt-%u]", *op);
00714 }
00715 #endif
00716
00717 if (*op == DHCPOPT_PAD) {
00718 op++;
00719 left--;
00720 continue;
00721 }
00722
00723
00724 if ((ol = *(op + 1)) > left) {
00725 break;
00726 }
00727
00728
00729 if (*op == DHCPOPT_MSGTYPE) {
00730 if (ol != 1) {
00731 break;
00732 }
00733 cfgp->dyn_msgtyp = *(op + 2);
00734 }
00735
00736 else if (*op == DHCPOPT_HOSTNAME) {
00737 copy_str(&cfgp->dyn_hostname, op + 2, ol);
00738 }
00739
00740 else if (*op == DHCPOPT_DOMAIN) {
00741 copy_str(&cfgp->dyn_domain, op + 2, ol);
00742 }
00743
00744
00745 else if (ol >= 4) {
00746
00747 uint32_t lval = *(op + 2);
00748 lval += (uint32_t)(*(op + 3)) << 8;
00749 lval += (uint32_t)(*(op + 4)) << 16;
00750 lval += (uint32_t)(*(op + 5)) << 24;
00751
00752
00753 if (*op == DHCPOPT_NETMASK) {
00754 cfgp->dyn_netmask = lval;
00755 }
00756
00757 else if (*op == DHCPOPT_BROADCAST) {
00758 cfgp->dyn_broadcast = lval;
00759 }
00760
00761
00762
00763 else if (*op == DHCPOPT_GATEWAY) {
00764 cfgp->dyn_gateway = lval;
00765 }
00766
00767
00768 else if (*op == DHCPOPT_DNS) {
00769 cfgp->dyn_pdns = lval;
00770 if (ol >= 8) {
00771 cfgp->dyn_sdns = *(op + 6);
00772 cfgp->dyn_sdns += (uint32_t)(*(op + 7)) << 8;
00773 cfgp->dyn_sdns += (uint32_t)(*(op + 8)) << 16;
00774 cfgp->dyn_sdns += (uint32_t)(*(op + 9)) << 24;
00775 }
00776 }
00777
00778 else if (*op == DHCPOPT_SID) {
00779 cfgp->dyn_sid = lval;
00780 }
00781
00782 else if (*op == DHCPOPT_RENEWALTIME) {
00783 cfgp->dyn_renewalTime = ntohl(lval);
00784 }
00785
00786 else if (*op == DHCPOPT_REBINDTIME) {
00787 cfgp->dyn_rebindTime = ntohl(lval);
00788 }
00789
00790 else if (*op == DHCPOPT_LEASETIME) {
00791 cfgp->dyn_leaseTime = ntohl(lval);
00792 }
00793 }
00794 op += ol + 2;
00795 left -= ol + 2;
00796 }
00797
00798
00799
00800
00801
00802 if (*op != DHCPOPT_END ||
00803 (cfgp->dyn_msgtyp != DHCP_OFFER &&
00804 cfgp->dyn_msgtyp != DHCP_ACK &&
00805 cfgp->dyn_msgtyp != DHCP_NAK)) {
00806 #ifdef NUTDEBUG
00807 if (__tcp_trf) {
00808 fprintf(__tcp_trs, "[DHCP-Parse Error]");
00809 }
00810 #endif
00811 ReleaseDynCfg(cfgp);
00812 return 0;
00813 }
00814
00815
00816 if (cfgp->dyn_renewalTime == 0) {
00817 cfgp->dyn_renewalTime = cfgp->dyn_leaseTime / 2;
00818 }
00819 if (cfgp->dyn_rebindTime == 0) {
00820 cfgp->dyn_rebindTime = cfgp->dyn_renewalTime +
00821 cfgp->dyn_renewalTime / 2 +
00822 cfgp->dyn_renewalTime / 4;
00823 }
00824 return cfgp;
00825 }
00826
00837 static size_t DhcpAddOption(uint8_t * op, uint8_t ot, void *ov, uint8_t len)
00838 {
00839 *op++ = ot;
00840 *op++ = len;
00841 memcpy(op, ov, len);
00842
00843 return 2 + len;
00844 }
00845
00855 static size_t DhcpAddByteOption(uint8_t * op, uint8_t ot, uint8_t ov)
00856 {
00857 *op++ = ot;
00858 *op++ = 1;
00859 *op++ = ov;
00860
00861 return 3;
00862 }
00863
00874 static size_t DhcpAddShortOption(uint8_t * op, uint8_t ot, uint16_t ov)
00875 {
00876 *op++ = ot;
00877 *op++ = 2;
00878 ov = htons(ov);
00879 memcpy(op, &ov, 2);
00880
00881 return 4;
00882 }
00883
00896 static size_t DhcpAddParmReqOption(uint8_t * op)
00897 {
00898 *op++ = DHCPOPT_PARAMREQUEST;
00899 *op++ = 3;
00900 *op++ = DHCPOPT_NETMASK;
00901 *op++ = DHCPOPT_GATEWAY;
00902 *op++ = DHCPOPT_DNS;
00903 return 5;
00904 }
00905
00927 static u_int DhcpPrepHeader(BOOTP *bp, uint8_t msgtyp, uint32_t xid, uint32_t ciaddr, uint16_t secs)
00928 {
00929 uint8_t *op;
00930
00931 memset(bp, 0, sizeof(*bp));
00932
00933 bp->bp_op = 1;
00934
00935 bp->bp_htype = 1;
00936 bp->bp_hlen = 6;
00937 memcpy(bp->bp_chaddr, confnet.cdn_mac, 6);
00938
00939 bp->bp_xid = xid;
00940
00941 bp->bp_secs = htons(secs);
00942
00943 #ifdef DHCP_BROADCAST_FLAG
00944
00945
00946
00947
00948
00949 bp->bp_flags = htons(0x8000);
00950 #endif
00951
00952 bp->bp_ciaddr = ciaddr;
00953
00954
00955 op = bp->bp_options;
00956 *op++ = 0x63;
00957 *op++ = 0x82;
00958 *op++ = 0x53;
00959 *op++ = 0x63;
00960
00961
00962 return DhcpAddByteOption(op, DHCPOPT_MSGTYPE, msgtyp) + 4;
00963 }
00964
00983 static int DhcpSendMessage(UDPSOCKET * sock, uint32_t addr, BOOTP *bp, size_t len)
00984 {
00985
00986 bp->bp_options[len++] = DHCPOPT_END;
00987
00988
00989
00990 if ((len += sizeof(BOOTP) - sizeof(bp->bp_options)) < MIN_DHCP_MSGSIZE) {
00991 len = MIN_DHCP_MSGSIZE;
00992 }
00993 #ifdef NUTDEBUG
00994 if (__tcp_trf) {
00995 fprintf(__tcp_trs, "[DHCP-Send to %s]", inet_ntoa(addr));
00996 }
00997 #endif
00998 if (NutUdpSendTo(sock, addr, DHCP_SERVERPORT, bp, len) < 0) {
00999 dhcpError = DHCPERR_TRANSMIT;
01000 return -1;
01001 }
01002 return 0;
01003 }
01004
01018 static int DhcpRecvMessage(UDPSOCKET * sock, uint32_t xid, BOOTP *bp, uint32_t tmo)
01019 {
01020 int rc;
01021 uint16_t port;
01022 uint32_t addr;
01023 uint32_t etim;
01024 uint32_t wtim;
01025
01026
01027 etim = NutGetMillis();
01028
01029 wtim = tmo;
01030 for (;;) {
01031 rc = NutUdpReceiveFrom(sock, &addr, &port, bp, sizeof(BOOTP), wtim);
01032 #ifdef NUTDEBUG
01033 if (__tcp_trf) {
01034 if (rc > 0) {
01035 fprintf(__tcp_trs, "[DHCP-Recv from %s]", inet_ntoa(addr));
01036 } else if (rc < 0) {
01037 fprintf(__tcp_trs, "[DHCP-Recv Error]");
01038 } else {
01039 fprintf(__tcp_trs, "[DHCP-Recv Timeout %lu]", tmo);
01040 }
01041 }
01042 #endif
01043
01044 if (rc <= 0) {
01045 if (rc < 0) {
01046 dhcpError = DHCPERR_RECEIVE;
01047 }
01048 break;
01049 }
01050
01051
01052 if (rc > sizeof(BOOTP) - sizeof(bp->bp_options) + 5) {
01053
01054 if (bp->bp_op == 2 && bp->bp_xid == xid) {
01055
01056 break;
01057 }
01058 }
01059
01060
01061 wtim = NutGetMillis() - etim;
01062 if (wtim >= tmo - 250) {
01063
01064 rc = 0;
01065 break;
01066 }
01067 wtim = tmo - wtim;
01068 }
01069 return rc;
01070 }
01071
01086 static int DhcpBroadcastDiscover(UDPSOCKET * sock, BOOTP *bp, uint32_t xid, uint32_t raddr, uint16_t secs)
01087 {
01088 size_t optlen;
01089 int len;
01090 uint8_t *op = bp->bp_options;
01091
01092 optlen = DhcpPrepHeader(bp, DHCP_DISCOVER, xid, 0, secs);
01093
01094
01095 if (raddr) {
01096 optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
01097 }
01098
01099 optlen += DhcpAddParmReqOption(op + optlen);
01100
01101
01102
01103
01104
01105 len = strlen(confos.hostname);
01106 if (len > 0) {
01107 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01108 }
01109
01110
01111 optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
01112
01113 return DhcpSendMessage(sock, INADDR_BROADCAST, bp, optlen);
01114 }
01115
01116
01136 static int DhcpSendRequest(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid,
01137 uint32_t caddr, uint32_t raddr, uint32_t sid, uint16_t secs)
01138 {
01139 size_t optlen;
01140 int len;
01141 uint8_t *op = bp->bp_options;
01142
01143
01144 optlen = DhcpPrepHeader(bp, DHCP_REQUEST, xid, caddr, secs);
01145
01146
01147 if (raddr) {
01148 optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
01149 }
01150 if (sid) {
01151 optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
01152 }
01153 optlen += DhcpAddParmReqOption(op + optlen);
01154
01155
01156
01157 len = strlen(confos.hostname);
01158 if (len > 0) {
01159 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01160 }
01161
01162 return DhcpSendMessage(sock, daddr, bp, optlen);
01163 }
01164
01183 static int DhcpBroadcastRequest(UDPSOCKET * sock, BOOTP *bp, uint32_t xid,
01184 uint32_t caddr, uint32_t raddr, uint32_t sid, uint16_t secs)
01185 {
01186 return DhcpSendRequest(sock, INADDR_BROADCAST, bp, xid, caddr, raddr, sid, secs);
01187 }
01188
01204 static int DhcpSendRelease(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, uint32_t caddr, uint32_t sid)
01205 {
01206 size_t optlen;
01207 uint8_t *op = bp->bp_options;
01208
01209
01210 optlen = DhcpPrepHeader(bp, DHCP_RELEASE, xid, caddr, 0);
01211
01212
01213 if (sid) {
01214 optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
01215 }
01216 return DhcpSendMessage(sock, daddr, bp, optlen);
01217 }
01218
01231 static int DhcpSendInform(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, uint32_t caddr)
01232 {
01233 size_t optlen;
01234 size_t len;
01235 uint8_t *op = bp->bp_options;
01236
01237
01238 optlen = DhcpPrepHeader(bp, DHCP_INFORM, xid, caddr, 0);
01239
01240
01241 optlen += DhcpAddParmReqOption(op + optlen);
01242
01243
01244 len = strlen(confos.hostname);
01245 if (len > 0) {
01246 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01247 }
01248
01249
01250 optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
01251
01252 return DhcpSendMessage(sock, daddr, bp, optlen);
01253 }
01254
01255
01266 static DYNCFG *CheckOffer(DYNCFG * dyncfg, BOOTP *bp, size_t len)
01267 {
01268 DYNCFG *offer;
01269
01270
01271
01272 if ((offer = ParseReply(bp, len)) == 0) {
01273 return dyncfg;
01274 }
01275
01276
01277 if (offer->dyn_msgtyp != DHCP_OFFER) {
01278 ReleaseDynCfg(offer);
01279 return dyncfg;
01280 }
01281
01282
01283 if (dyncfg == 0) {
01284 dyncfg = offer;
01285 }
01286
01287
01288
01289
01290 else {
01291
01292
01293
01294 if (confnet.cdn_ip_addr & confnet.cdn_ip_mask) {
01295 if (dyncfg->dyn_yiaddr != confnet.cdn_ip_addr &&
01296 offer->dyn_yiaddr == confnet.cdn_ip_addr) {
01297 ReleaseDynCfg(dyncfg);
01298 dyncfg = offer;
01299 }
01300 }
01301
01302 else if (offer->dyn_leaseTime > dyncfg->dyn_leaseTime) {
01303 ReleaseDynCfg(dyncfg);
01304 dyncfg = offer;
01305 }
01306
01307 else {
01308 ReleaseDynCfg(offer);
01309 }
01310 }
01311 return dyncfg;
01312 }
01313
01327 THREAD(NutDhcpClient, arg)
01328 {
01329 DYNCFG *reply = 0;
01330 UDPSOCKET *sock = 0;
01331 BOOTP *bp = 0;
01332 int n;
01333 uint32_t xid;
01334 IFNET *nif;
01335 uint16_t secs = 0;
01336 uint32_t aqsTime = NutGetSeconds();
01337 uint32_t leaseTime = 0;
01338 uint32_t napTime;
01339 ureg_t retries;
01340 uint32_t tmo = MIN_DHCP_WAIT;
01341 uint32_t last_ip = confnet.cdn_ip_addr;
01342 uint32_t server_ip;
01343
01344
01345
01346
01347
01348 #ifdef __arm__
01349 nif = dhcpDev->dev_icb;
01350 #else
01351 nif = ((NUTDEVICE *) arg)->dev_icb;
01352 #endif
01353
01354
01355
01356
01357
01358
01359
01360
01361 xid = 0;
01362 for (retries = 0; retries < sizeof(xid); retries++) {
01363 xid <<= 8;
01364 xid += nif->if_mac[5 - retries];
01365 }
01366 retries = 0;
01367
01368 for (;;) {
01369 #ifdef NUTDEBUG
01370 if (__tcp_trf) {
01371 fprintf(__tcp_trs, "\n[%u.DHCP-", retries + 1);
01372 switch (dhcpState) {
01373 case DHCPST_INIT:
01374 fprintf(__tcp_trs, "INIT]");
01375 break;
01376 case DHCPST_SELECTING:
01377 fprintf(__tcp_trs, "SELECTING]");
01378 break;
01379 case DHCPST_REQUESTING:
01380 fprintf(__tcp_trs, "REQUESTING]");
01381 break;
01382 case DHCPST_REBOOTING:
01383 fprintf(__tcp_trs, "REBOOTING %s]", inet_ntoa(last_ip));
01384 break;
01385 case DHCPST_BOUND:
01386 fprintf(__tcp_trs, "BOUND %lu]", NutGetSeconds() - leaseTime);
01387 break;
01388 case DHCPST_RENEWING:
01389 fprintf(__tcp_trs, "RENEWING %lu]", NutGetSeconds() - leaseTime);
01390 break;
01391 case DHCPST_REBINDING:
01392 fprintf(__tcp_trs, "REBINDING %lu]", NutGetSeconds() - leaseTime);
01393 break;
01394 case DHCPST_INFORMING:
01395 fprintf(__tcp_trs, "INFORMING]");
01396 break;
01397 case DHCPST_RELEASING:
01398 fprintf(__tcp_trs, "RELEASING]");
01399 break;
01400 case DHCPST_IDLE:
01401 if (dhcpError) {
01402 fprintf(__tcp_trs, "ERROR %u]", dhcpError);
01403 } else {
01404 fprintf(__tcp_trs, "IDLE]");
01405 }
01406 break;
01407 default:
01408 fprintf(__tcp_trs, "UNKNOWN %u]", dhcpState);
01409 break;
01410 }
01411 }
01412 #endif
01413
01414
01415
01416
01417 server_ip = INADDR_BROADCAST;
01418 if (retries) {
01419
01420 tmo += tmo;
01421 if (tmo > MAX_DHCP_WAIT) {
01422 tmo = MAX_DHCP_WAIT;
01423 }
01424 } else {
01425
01426 tmo = MIN_DHCP_WAIT;
01427
01428
01429
01430
01431 if (dhcpState != DHCPST_REQUESTING) {
01432 xid++;
01433 }
01434
01435
01436
01437 if (dhcpConfig && dhcpConfig->dyn_sid) {
01438 server_ip = dhcpConfig->dyn_sid;
01439 }
01440 }
01441
01442
01443
01444
01445 if (dhcpState != DHCPST_IDLE && dhcpApiTimeout != NUT_WAIT_INFINITE) {
01446 uint32_t tt = NutGetMillis() - dhcpApiStart;
01447
01448 if (dhcpApiTimeout <= tt) {
01449 dhcpError = DHCPERR_TIMEOUT;
01450 dhcpState = DHCPST_IDLE;
01451 continue;
01452 }
01453 if ((tt = dhcpApiTimeout - tt) < tmo) {
01454 tmo = tt;
01455 }
01456 }
01457
01458
01459
01460
01461 if (dhcpState == DHCPST_SELECTING || dhcpState == DHCPST_RENEWING || dhcpState == DHCPST_REBINDING) {
01462
01463 if (retries) {
01464 if (NutGetSeconds() - aqsTime > 0xffffUL) {
01465 secs = 0xffff;
01466 } else {
01467 secs = (uint16_t) (NutGetSeconds() - aqsTime);
01468 }
01469 }
01470
01471 else {
01472 aqsTime = NutGetSeconds();
01473 secs = 0;
01474 }
01475 }
01476
01477
01478
01479
01480 if (dhcpState == DHCPST_BOUND || dhcpState == DHCPST_IDLE) {
01481 if (sock) {
01482 NutUdpDestroySocket(sock);
01483 sock = 0;
01484 }
01485 if (bp) {
01486 free(bp);
01487 bp = 0;
01488 }
01489 }
01490
01491
01492
01493
01494 else {
01495
01496
01497
01498 if (dhcpConfig == 0 && nif->if_local_ip) {
01499
01500
01501 dhcpState = DHCPST_IDLE;
01502 continue;
01503 }
01504
01505 if (sock == 0 || bp == 0) {
01506 if (sock == 0) {
01507 sock = NutUdpCreateSocket(DHCP_CLIENTPORT);
01508 }
01509 if (bp == 0) {
01510 bp = malloc(sizeof(BOOTP));
01511 }
01512 if (sock == 0 || bp == 0) {
01513
01514 dhcpError = DHCPERR_SYSTEM;
01515 dhcpState = DHCPST_IDLE;
01516
01517
01518
01519 continue;
01520 }
01521 #if MAX_DHCP_BUFSIZE
01522 {
01523 uint16_t max_ms = MAX_DHCP_BUFSIZE;
01524 NutUdpSetSockOpt(sock, SO_RCVBUF, &max_ms, sizeof(max_ms));
01525 }
01526 #endif
01527 }
01528 }
01529
01530
01531
01532
01533 if (dhcpState == DHCPST_INIT) {
01534
01535 retries = 0;
01536
01537 xid++;
01538
01539 if ((last_ip & confnet.cdn_ip_mask) == 0) {
01540
01541 dhcpState = DHCPST_SELECTING;
01542 } else {
01543
01544
01545 dhcpState = DHCPST_REBOOTING;
01546 }
01547 }
01548
01549
01550
01551
01552 else if (dhcpState == DHCPST_SELECTING) {
01553 if (retries++ > MAX_DCHP_RETRIES) {
01554
01555 dhcpError = DHCPERR_TIMEOUT;
01556 dhcpState = DHCPST_IDLE;
01557 }
01558
01559 else if (DhcpBroadcastDiscover(sock, bp, xid, last_ip, secs) < 0) {
01560
01561 dhcpState = DHCPST_IDLE;
01562 } else {
01563
01564 while ((n = DhcpRecvMessage(sock, xid, bp, tmo)) > 0) {
01565
01566 if ((dhcpConfig = CheckOffer(dhcpConfig, bp, n)) != 0) {
01567
01568
01569 if (dhcpApiTimeout < MIN_DHCP_WAIT * 3) {
01570 break;
01571 }
01572
01573
01574 tmo = MIN_DHCP_WAIT;
01575 }
01576 }
01577
01578 if (n < 0) {
01579 dhcpState = DHCPST_IDLE;
01580 }
01581
01582
01583 else if (dhcpConfig) {
01584 retries = 0;
01585 dhcpState = DHCPST_REQUESTING;
01586 }
01587 }
01588 }
01589
01590
01591
01592
01593 else if (dhcpState == DHCPST_REQUESTING) {
01594 if (retries++ > MAX_DCHP_RETRIES) {
01595
01596 dhcpState = DHCPST_INIT;
01597 }
01598
01599
01600 else if (DhcpBroadcastRequest(sock, bp, xid, 0, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid, secs) < 0) {
01601
01602 dhcpState = DHCPST_IDLE;
01603 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01604
01605 dhcpState = DHCPST_IDLE;
01606 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01607
01608 if (reply->dyn_msgtyp == DHCP_ACK) {
01609 ReleaseDynCfg(dhcpConfig);
01610 dhcpConfig = reply;
01611 reply = 0;
01612 leaseTime = aqsTime;
01613 dhcpState = DHCPST_BOUND;
01614 }
01615
01616
01617 else if (reply->dyn_msgtyp == DHCP_NAK) {
01618 dhcpState = DHCPST_INIT;
01619 }
01620 }
01621 }
01622
01623
01624
01625
01626 else if (dhcpState == DHCPST_REBOOTING) {
01627 if (++retries > MAX_DCHP_RETRIES) {
01628
01629 last_ip = 0;
01630 dhcpState = DHCPST_INIT;
01631 }
01632
01633 else if (DhcpBroadcastRequest(sock, bp, xid, 0, last_ip, 0, secs) < 0) {
01634
01635 dhcpState = DHCPST_IDLE;
01636 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01637
01638 dhcpState = DHCPST_IDLE;
01639 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01640 if (reply->dyn_msgtyp == DHCP_ACK) {
01641 ReleaseDynCfg(dhcpConfig);
01642 dhcpConfig = reply;
01643 reply = 0;
01644 leaseTime = aqsTime;
01645 dhcpState = DHCPST_BOUND;
01646 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01647
01648
01649
01650 last_ip = 0;
01651 dhcpState = DHCPST_INIT;
01652 }
01653 }
01654 }
01655
01656
01657
01658
01659 else if (dhcpState == DHCPST_BOUND) {
01660 retries = 0;
01661 NutEventBroadcast(&dhcpDone);
01662 if (dhcpConfig->dyn_renewalTime <= NutGetSeconds() - leaseTime) {
01663 dhcpState = DHCPST_RENEWING;
01664 } else {
01665
01666 napTime = dhcpConfig->dyn_renewalTime - (NutGetSeconds() - leaseTime);
01667 if (napTime > MAX_DHCP_NAPTIME) {
01668 napTime = MAX_DHCP_NAPTIME;
01669 }
01670 NutEventWait(&dhcpWake, napTime * 1000UL);
01671 }
01672 }
01673
01674
01675
01676
01677 else if (dhcpState == DHCPST_RENEWING) {
01678 retries++;
01679 if (tmo / 1000 > dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime)) {
01680 tmo = dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime) * 1000;
01681 }
01682 if (dhcpConfig->dyn_rebindTime <= NutGetSeconds() - leaseTime) {
01683 retries = 0;
01684 dhcpState = DHCPST_REBINDING;
01685 }
01686
01687
01688 else if (DhcpSendRequest(sock, dhcpConfig->dyn_sid, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) <
01689 0) {
01690
01691 retries = 0;
01692 dhcpState = DHCPST_REBINDING;
01693 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01694
01695 dhcpState = DHCPST_IDLE;
01696 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01697 if (reply->dyn_msgtyp == DHCP_ACK) {
01698
01699 ReleaseDynCfg(dhcpConfig);
01700 dhcpConfig = reply;
01701 reply = 0;
01702 leaseTime = aqsTime;
01703 dhcpState = DHCPST_BOUND;
01704 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01705
01706 retries = 0;
01707 dhcpState = DHCPST_REBINDING;
01708 }
01709 }
01710 }
01711
01712
01713
01714
01715 else if (dhcpState == DHCPST_REBINDING) {
01716 retries++;
01717 if (tmo > dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime)) {
01718 tmo = dhcpConfig->dyn_rebindTime - NutGetSeconds() - leaseTime;
01719 }
01720 if (dhcpConfig->dyn_rebindTime <= NutGetSeconds() - leaseTime) {
01721 retries = 0;
01722 dhcpState = DHCPST_REBINDING;
01723 }
01724
01725
01726 else if (DhcpBroadcastRequest(sock, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) < 0) {
01727
01728 dhcpState = DHCPST_IDLE;
01729 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01730
01731 dhcpState = DHCPST_IDLE;
01732 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01733 if (reply->dyn_msgtyp == DHCP_ACK) {
01734
01735 ReleaseDynCfg(dhcpConfig);
01736 dhcpConfig = reply;
01737 reply = 0;
01738 leaseTime = aqsTime;
01739 dhcpState = DHCPST_BOUND;
01740 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750 dhcpState = DHCPST_INIT;
01751 }
01752 }
01753 }
01754
01755
01756
01757
01758 else if (dhcpState == DHCPST_INFORMING) {
01759 if (retries++ > MAX_DCHP_RETRIES) {
01760 dhcpState = DHCPST_IDLE;
01761 } else if (DhcpSendInform(sock, server_ip, bp, xid, nif->if_local_ip) < 0) {
01762 if (server_ip == INADDR_BROADCAST) {
01763 dhcpState = DHCPST_IDLE;
01764 }
01765 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) != 0) {
01766 if (n > 0 &&
01767 (reply = ParseReply(bp, n)) != 0 &&
01768 reply->dyn_msgtyp == DHCP_ACK) {
01769
01770 ReleaseDynCfg(dhcpConfig);
01771 dhcpConfig = reply;
01772 reply = 0;
01773 }
01774 dhcpState = DHCPST_IDLE;
01775 }
01776 }
01777
01778
01779
01780
01781 else if (dhcpState == DHCPST_RELEASING) {
01782 if (dhcpConfig == 0 ||
01783 retries++ > MAX_DCHP_RELEASE_RETRIES ||
01784 DhcpSendRelease(sock, server_ip, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid) < 0) {
01785 if (server_ip == INADDR_BROADCAST) {
01786 dhcpState = DHCPST_IDLE;
01787 }
01788 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01789
01790 dhcpState = DHCPST_IDLE;
01791 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01792 if (reply->dyn_msgtyp == DHCP_ACK) {
01793 dhcpState = DHCPST_IDLE;
01794 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01795 dhcpState = DHCPST_IDLE;
01796 }
01797 }
01798 }
01799
01800
01801
01802
01803
01804
01805
01806
01807 else if (dhcpState == DHCPST_IDLE) {
01808 ReleaseDynCfg(dhcpConfig);
01809 dhcpConfig = 0;
01810 retries = 0;
01811 NutEventBroadcast(&dhcpDone);
01812 NutEventWait(&dhcpWake, NUT_WAIT_INFINITE);
01813 }
01814
01815
01816 if (reply) {
01817 ReleaseDynCfg(reply);
01818 reply = 0;
01819 }
01820 }
01821 }
01822
01837 static int DhcpKick(CONST char *name, uint8_t state, uint32_t timeout)
01838 {
01839 NUTDEVICE *dev;
01840 IFNET *nif;
01841
01842
01843 if ((dev = NutDeviceLookup(name)) == 0 ||
01844 dev->dev_type != IFTYP_NET ||
01845 (nif = dev->dev_icb) == 0 ||
01846 nif->if_type != IFT_ETHER) {
01847 dhcpError = DHCPERR_BADDEV;
01848 return -1;
01849 }
01850
01851
01852 dhcpApiStart = NutGetMillis();
01853 dhcpApiTimeout = timeout;
01854
01855 dhcpState = state;
01856 if (dhcpThread == 0) {
01857 #ifdef __arm__
01858 dhcpDev = dev;
01859 #endif
01860 dhcpThread = NutThreadCreate("dhcpc", NutDhcpClient, dev, NUT_THREAD_DHCPSTACK);
01861 }
01862 NutEventPost(&dhcpWake);
01863 NutEventWait(&dhcpDone, NUT_WAIT_INFINITE);
01864
01865 return 0;
01866 }
01867
01907 int NutDhcpIfConfig(CONST char *name, uint8_t * mac, uint32_t timeout)
01908 {
01909 uint8_t mac0[6];
01910 uint8_t macF[6];
01911 NUTDEVICE *dev;
01912 IFNET *nif;
01913
01914
01915
01916
01917 if ((dev = NutDeviceLookup(name)) == 0 ||
01918 dev->dev_type != IFTYP_NET ||
01919 (nif = dev->dev_icb) == 0 ||
01920 nif->if_type != IFT_ETHER) {
01921 dhcpError = DHCPERR_BADDEV;
01922 return -1;
01923 }
01924
01925
01926
01927
01928
01929 memset(mac0, 0x00, sizeof(mac0));
01930 memset(macF, 0xFF, sizeof(macF));
01931 if (memcmp(nif->if_mac, mac0, 6) == 0 || memcmp(nif->if_mac, macF, 6) == 0) {
01932
01933
01934
01935
01936 if (mac) {
01937 memcpy(confnet.cdn_mac, mac, sizeof(confnet.cdn_mac));
01938 }
01939
01940
01941
01942
01943
01944
01945
01946 else if (NutNetLoadConfig(name)) {
01947 dhcpError = DHCPERR_NOMAC;
01948 return -1;
01949 }
01950
01951
01952
01953
01954
01955 memcpy(nif->if_mac, confnet.cdn_mac, 6);
01956 NutSleep(500);
01957 }
01958
01959
01960
01961
01962 if ((confnet.cdn_cip_addr & confnet.cdn_ip_mask) != 0) {
01963 confnet.cdn_ip_addr = confnet.cdn_cip_addr;
01964 NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
01965 return 0;
01966 }
01967
01968
01969
01970
01971
01972
01973 if (DhcpKick(name, DHCPST_INIT, timeout) == 0) {
01974
01975
01976
01977
01978 if (dhcpState == DHCPST_BOUND) {
01979 #ifdef NUTDEBUG
01980 if (__tcp_trf) {
01981 fprintf(__tcp_trs, "[DHCP-Config %s]", inet_ntoa(dhcpConfig->dyn_yiaddr));
01982 }
01983 #endif
01984 NutNetIfSetup(dev, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_netmask, dhcpConfig->dyn_gateway);
01985 NutDnsConfig2(0, 0, dhcpConfig->dyn_pdns, dhcpConfig->dyn_sdns);
01986 return 0;
01987 }
01988
01989
01990
01991
01992
01993 if (nif->if_local_ip) {
01994 #ifdef NUTDEBUG
01995 if (__tcp_trf) {
01996 fprintf(__tcp_trs, "[DHCP-External %s]", inet_ntoa(nif->if_local_ip));
01997 }
01998 #endif
01999 return 0;
02000 }
02001
02002
02003
02004
02005
02006 if ((confnet.cdn_ip_addr & confnet.cdn_ip_mask) != 0) {
02007 #ifdef NUTDEBUG
02008 if (__tcp_trf) {
02009 fprintf(__tcp_trs, "[DHCP-Reusing %s]", inet_ntoa(confnet.cdn_ip_addr));
02010 }
02011 #endif
02012 NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
02013 return 0;
02014 }
02015 }
02016 return -1;
02017 }
02018
02035 int NutDhcpRelease(CONST char *name, uint32_t timeout)
02036 {
02037
02038 if (dhcpState != DHCPST_BOUND) {
02039 dhcpError = DHCPERR_STATE;
02040 return -1;
02041 }
02042
02043
02044 return DhcpKick(name, DHCPST_RELEASING, timeout);
02045 }
02046
02057 int NutDhcpInform(CONST char *name, uint32_t timeout)
02058 {
02059
02060 if (dhcpState != DHCPST_IDLE) {
02061 dhcpError = DHCPERR_STATE;
02062 return -1;
02063 }
02064
02065
02066 return DhcpKick(name, DHCPST_INFORMING, timeout);
02067 }
02068
02086 int NutDhcpStatus(CONST char *name)
02087 {
02088 return dhcpState;
02089 }
02090
02109 int NutDhcpError(CONST char *name)
02110 {
02111 int rc = dhcpError;
02112 dhcpError = 0;
02113 return rc;
02114 }
02115
02123 int NutDhcpIsConfigured(void)
02124 {
02125 return (dhcpState == DHCPST_BOUND);
02126 }
02127