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
00199 #include <sys/thread.h>
00200 #include <sys/event.h>
00201 #include <sys/timer.h>
00202 #include <sys/confnet.h>
00203 #include <sys/confos.h>
00204
00205 #include <stdlib.h>
00206 #include <string.h>
00207 #include <time.h>
00208 #include <memdebug.h>
00209
00210 #include <arpa/inet.h>
00211 #include <netinet/in.h>
00212 #include <netdb.h>
00213 #include <net/route.h>
00214 #include <sys/socket.h>
00215 #include <pro/dhcp.h>
00216
00217 #ifdef NUTDEBUG
00218 #include <net/netdebug.h>
00219 #endif
00220
00221 #if 0
00222
00223 #define NUTDEBUG
00224 #include <stdio.h>
00225 #define __tcp_trs stdout
00226 static uint_fast8_t __tcp_trf = 1;
00227 #endif
00228
00233
00240
00246 #ifndef DHCP_SERVERPORT
00247 #define DHCP_SERVERPORT 67
00248 #endif
00249
00255 #ifndef DHCP_CLIENTPORT
00256 #define DHCP_CLIENTPORT 68
00257 #endif
00258
00268 #ifndef MAX_DHCP_MSGSIZE
00269 #define MAX_DHCP_MSGSIZE 576
00270 #endif
00271
00279 #ifndef MIN_DHCP_MSGSIZE
00280 #define MIN_DHCP_MSGSIZE 300
00281 #endif
00282
00298 #ifndef MAX_DHCP_BUFSIZE
00299 #define MAX_DHCP_BUFSIZE 1728
00300 #endif
00301
00311 #ifndef MIN_DHCP_WAIT
00312 #define MIN_DHCP_WAIT 4000
00313 #endif
00314
00323 #ifndef MAX_DHCP_WAIT
00324 #define MAX_DHCP_WAIT 64000
00325 #endif
00326
00335 #ifndef MAX_DCHP_RETRIES
00336 #define MAX_DCHP_RETRIES 3
00337 #endif
00338
00347 #ifndef MAX_DCHP_RELEASE_RETRIES
00348 #define MAX_DCHP_RELEASE_RETRIES 0
00349 #endif
00350
00358 #ifndef DHCP_DEFAULT_LEASE
00359 #define DHCP_DEFAULT_LEASE 43200
00360 #endif
00361
00367 #ifndef MAX_DHCP_NAPTIME
00368 #define MAX_DHCP_NAPTIME 4294967
00369 #endif
00370
00376 #ifndef NUT_THREAD_DHCPSTACK
00377 #if defined(__AVR__)
00378
00379 #define NUT_THREAD_DHCPSTACK 288
00380 #else
00381
00382 #define NUT_THREAD_DHCPSTACK 384
00383 #endif
00384 #endif
00385
00394
00397 #define DHCP_DISCOVER 1
00398
00403 #define DHCP_OFFER 2
00404
00412 #define DHCP_REQUEST 3
00413
00418 #define DHCP_DECLINE 4
00419
00424 #define DHCP_ACK 5
00425
00430 #define DHCP_NAK 6
00431
00434 #define DHCP_RELEASE 7
00435
00440 #define DHCP_INFORM 8
00441
00451
00458 #define DHCPOPT_PAD 0
00459
00463 #define DHCPOPT_NETMASK 1
00464
00468 #define DHCPOPT_GATEWAY 3
00469
00473 #define DHCPOPT_DNS 6
00474
00478 #define DHCPOPT_HOSTNAME 12
00479
00483 #define DHCPOPT_DOMAIN 15
00484
00488 #define DHCPOPT_BROADCAST 28
00489
00493 #define DHCPOPT_REQESTIP 50
00494
00498 #define DHCPOPT_LEASETIME 51
00499
00503 #define DHCPOPT_MSGTYPE 53
00504
00508 #define DHCPOPT_SID 54
00509
00513 #define DHCPOPT_PARAMREQUEST 55
00514
00518 #define DHCPOPT_MAXMSGSIZE 57
00519
00523 #define DHCPOPT_RENEWALTIME 58
00524
00528 #define DHCPOPT_REBINDTIME 59
00529
00533 #define DHCPOPT_END 255
00534
00540 typedef struct bootp BOOTP;
00541
00545 struct __attribute__ ((packed)) bootp {
00546 uint8_t bp_op;
00547 uint8_t bp_htype;
00548 uint8_t bp_hlen;
00549 uint8_t bp_hops;
00550 uint32_t bp_xid;
00551 uint16_t bp_secs;
00552 uint16_t bp_flags;
00553 uint32_t bp_ciaddr;
00554 uint32_t bp_yiaddr;
00555 uint32_t bp_siaddr;
00556 uint32_t bp_giaddr;
00557 uint8_t bp_chaddr[16];
00558 char bp_sname[64];
00559 char bp_file[128];
00560 uint8_t bp_options[312];
00561 };
00562
00566 typedef struct dyn_cfg DYNCFG;
00567
00571 struct dyn_cfg {
00572 uint8_t dyn_msgtyp;
00573 uint32_t dyn_yiaddr;
00574 uint32_t dyn_netmask;
00575 uint32_t dyn_broadcast;
00576 uint32_t dyn_gateway;
00577 uint32_t dyn_pdns;
00578 uint32_t dyn_sdns;
00579 uint32_t dyn_sid;
00580 uint32_t dyn_renewalTime;
00581 uint32_t dyn_rebindTime;
00582 uint32_t dyn_leaseTime;
00583 uint8_t *dyn_hostname;
00584 uint8_t *dyn_domain;
00585 };
00586
00593 static DYNCFG *dhcpConfig;
00594
00601 static HANDLE dhcpThread;
00602
00606 static uint8_t dhcpState;
00607
00611 static int dhcpError;
00612
00618 static HANDLE dhcpWake;
00619
00625 static HANDLE dhcpDone;
00626
00632 static uint32_t dhcpApiTimeout;
00633
00640 static uint32_t dhcpApiStart;
00641
00648 #ifdef __arm__
00649 static NUTDEVICE *dhcpDev;
00650 #endif
00651
00663 static void copy_str(uint8_t ** dst, void *src, int len)
00664 {
00665 if (*dst) {
00666 free(*dst);
00667 }
00668 if ((*dst = malloc(len + 1)) != 0) {
00669 if (len) {
00670 memcpy(*dst, src, len);
00671 }
00672 *(*dst + len) = 0;
00673 }
00674 }
00675
00683 static void ReleaseDynCfg(DYNCFG * dyncfg)
00684 {
00685 if (dyncfg) {
00686 if (dyncfg->dyn_hostname) {
00687 free(dyncfg->dyn_hostname);
00688 }
00689 if (dyncfg->dyn_domain) {
00690 free(dyncfg->dyn_domain);
00691 }
00692 free(dyncfg);
00693 }
00694 }
00695
00707 static DYNCFG *ParseReply(BOOTP *bp, int len)
00708 {
00709 uint8_t *op;
00710 int left;
00711 DYNCFG *cfgp;
00712
00713
00714 if ((cfgp = malloc(sizeof(DYNCFG))) == 0) {
00715 return 0;
00716 }
00717 memset(cfgp, 0, sizeof(DYNCFG));
00718 cfgp->dyn_leaseTime = DHCP_DEFAULT_LEASE;
00719
00720
00721 memcpy(&cfgp->dyn_yiaddr, &bp->bp_yiaddr, 4);
00722
00723
00724
00725
00726
00727 op = bp->bp_options + 4;
00728 left = len - (sizeof(*bp) - sizeof(bp->bp_options)) - 4;
00729 while (*op != DHCPOPT_END && left > 0) {
00730 uint8_t ol;
00731
00732 #ifdef NUTDEBUG
00733 if (__tcp_trf) {
00734 fprintf(__tcp_trs, "[DHCP-Opt-%u]", *op);
00735 }
00736 #endif
00737
00738 if (*op == DHCPOPT_PAD) {
00739 op++;
00740 left--;
00741 continue;
00742 }
00743
00744
00745 if ((ol = *(op + 1)) > left) {
00746 break;
00747 }
00748
00749
00750 if (*op == DHCPOPT_MSGTYPE) {
00751 if (ol != 1) {
00752 break;
00753 }
00754 cfgp->dyn_msgtyp = *(op + 2);
00755 }
00756
00757 else if (*op == DHCPOPT_HOSTNAME) {
00758 copy_str(&cfgp->dyn_hostname, op + 2, ol);
00759 }
00760
00761 else if (*op == DHCPOPT_DOMAIN) {
00762 copy_str(&cfgp->dyn_domain, op + 2, ol);
00763 }
00764
00765
00766 else if (ol >= 4) {
00767
00768 uint32_t lval = *(op + 2);
00769 lval += (uint32_t)(*(op + 3)) << 8;
00770 lval += (uint32_t)(*(op + 4)) << 16;
00771 lval += (uint32_t)(*(op + 5)) << 24;
00772
00773
00774 if (*op == DHCPOPT_NETMASK) {
00775 cfgp->dyn_netmask = lval;
00776 }
00777
00778 else if (*op == DHCPOPT_BROADCAST) {
00779 cfgp->dyn_broadcast = lval;
00780 }
00781
00782
00783
00784 else if (*op == DHCPOPT_GATEWAY) {
00785 cfgp->dyn_gateway = lval;
00786 }
00787
00788
00789 else if (*op == DHCPOPT_DNS) {
00790 cfgp->dyn_pdns = lval;
00791 if (ol >= 8) {
00792 cfgp->dyn_sdns = *(op + 6);
00793 cfgp->dyn_sdns += (uint32_t)(*(op + 7)) << 8;
00794 cfgp->dyn_sdns += (uint32_t)(*(op + 8)) << 16;
00795 cfgp->dyn_sdns += (uint32_t)(*(op + 9)) << 24;
00796 }
00797 }
00798
00799 else if (*op == DHCPOPT_SID) {
00800 cfgp->dyn_sid = lval;
00801 }
00802
00803 else if (*op == DHCPOPT_RENEWALTIME) {
00804 cfgp->dyn_renewalTime = ntohl(lval);
00805 }
00806
00807 else if (*op == DHCPOPT_REBINDTIME) {
00808 cfgp->dyn_rebindTime = ntohl(lval);
00809 }
00810
00811 else if (*op == DHCPOPT_LEASETIME) {
00812 cfgp->dyn_leaseTime = ntohl(lval);
00813 }
00814 }
00815 op += ol + 2;
00816 left -= ol + 2;
00817 }
00818
00819
00820
00821
00822
00823 if (*op != DHCPOPT_END ||
00824 (cfgp->dyn_msgtyp != DHCP_OFFER &&
00825 cfgp->dyn_msgtyp != DHCP_ACK &&
00826 cfgp->dyn_msgtyp != DHCP_NAK)) {
00827 #ifdef NUTDEBUG
00828 if (__tcp_trf) {
00829 fprintf(__tcp_trs, "[DHCP-Parse Error]");
00830 }
00831 #endif
00832 ReleaseDynCfg(cfgp);
00833 return 0;
00834 }
00835
00836
00837 if (cfgp->dyn_renewalTime == 0) {
00838 cfgp->dyn_renewalTime = cfgp->dyn_leaseTime / 2;
00839 }
00840 if (cfgp->dyn_rebindTime == 0) {
00841 cfgp->dyn_rebindTime = cfgp->dyn_renewalTime +
00842 cfgp->dyn_renewalTime / 2 +
00843 cfgp->dyn_renewalTime / 4;
00844 }
00845 return cfgp;
00846 }
00847
00858 static size_t DhcpAddOption(uint8_t * op, uint8_t ot, void *ov, uint8_t len)
00859 {
00860 *op++ = ot;
00861 *op++ = len;
00862 memcpy(op, ov, len);
00863
00864 return 2 + len;
00865 }
00866
00876 static size_t DhcpAddByteOption(uint8_t * op, uint8_t ot, uint8_t ov)
00877 {
00878 *op++ = ot;
00879 *op++ = 1;
00880 *op++ = ov;
00881
00882 return 3;
00883 }
00884
00895 static size_t DhcpAddShortOption(uint8_t * op, uint8_t ot, uint16_t ov)
00896 {
00897 *op++ = ot;
00898 *op++ = 2;
00899 ov = htons(ov);
00900 memcpy(op, &ov, 2);
00901
00902 return 4;
00903 }
00904
00917 static size_t DhcpAddParmReqOption(uint8_t * op)
00918 {
00919 *op++ = DHCPOPT_PARAMREQUEST;
00920 *op++ = 3;
00921 *op++ = DHCPOPT_NETMASK;
00922 *op++ = DHCPOPT_GATEWAY;
00923 *op++ = DHCPOPT_DNS;
00924 return 5;
00925 }
00926
00948 static unsigned int DhcpPrepHeader(BOOTP *bp, uint8_t msgtyp, uint32_t xid, uint32_t ciaddr, uint16_t secs)
00949 {
00950 uint8_t *op;
00951
00952 memset(bp, 0, sizeof(*bp));
00953
00954 bp->bp_op = 1;
00955
00956 bp->bp_htype = 1;
00957 bp->bp_hlen = 6;
00958 memcpy(bp->bp_chaddr, confnet.cdn_mac, 6);
00959
00960 bp->bp_xid = xid;
00961
00962 bp->bp_secs = htons(secs);
00963
00964 #ifdef DHCP_BROADCAST_FLAG
00965
00966
00967
00968
00969
00970 bp->bp_flags = htons(0x8000);
00971 #endif
00972
00973 bp->bp_ciaddr = ciaddr;
00974
00975
00976 op = bp->bp_options;
00977 *op++ = 0x63;
00978 *op++ = 0x82;
00979 *op++ = 0x53;
00980 *op++ = 0x63;
00981
00982
00983 return DhcpAddByteOption(op, DHCPOPT_MSGTYPE, msgtyp) + 4;
00984 }
00985
01004 static int DhcpSendMessage(UDPSOCKET * sock, uint32_t addr, BOOTP *bp, size_t len)
01005 {
01006
01007 bp->bp_options[len++] = DHCPOPT_END;
01008
01009
01010
01011 if ((len += sizeof(BOOTP) - sizeof(bp->bp_options)) < MIN_DHCP_MSGSIZE) {
01012 len = MIN_DHCP_MSGSIZE;
01013 }
01014 #ifdef NUTDEBUG
01015 if (__tcp_trf) {
01016 fprintf(__tcp_trs, "[DHCP-Send to %s]", inet_ntoa(addr));
01017 }
01018 #endif
01019 if (NutUdpSendTo(sock, addr, DHCP_SERVERPORT, bp, len) < 0) {
01020 dhcpError = DHCPERR_TRANSMIT;
01021 return -1;
01022 }
01023 return 0;
01024 }
01025
01039 static int DhcpRecvMessage(UDPSOCKET * sock, uint32_t xid, BOOTP *bp, uint32_t tmo)
01040 {
01041 int rc;
01042 uint16_t port;
01043 uint32_t addr;
01044 uint32_t etim;
01045 uint32_t wtim;
01046
01047
01048 etim = NutGetMillis();
01049
01050 wtim = tmo;
01051 for (;;) {
01052 rc = NutUdpReceiveFrom(sock, &addr, &port, bp, sizeof(BOOTP), wtim);
01053 #ifdef NUTDEBUG
01054 if (__tcp_trf) {
01055 if (rc > 0) {
01056 fprintf(__tcp_trs, "[DHCP-Recv from %s]", inet_ntoa(addr));
01057 } else if (rc < 0) {
01058 fprintf(__tcp_trs, "[DHCP-Recv Error]");
01059 } else {
01060 fprintf(__tcp_trs, "[DHCP-Recv Timeout %lu]", tmo);
01061 }
01062 }
01063 #endif
01064
01065 if (rc <= 0) {
01066 if (rc < 0) {
01067 dhcpError = DHCPERR_RECEIVE;
01068 }
01069 break;
01070 }
01071
01072
01073 if (rc > sizeof(BOOTP) - sizeof(bp->bp_options) + 5) {
01074
01075 if (bp->bp_op == 2 && bp->bp_xid == xid) {
01076
01077 break;
01078 }
01079 }
01080
01081
01082 wtim = NutGetMillis() - etim;
01083 if (wtim >= tmo - 250) {
01084
01085 rc = 0;
01086 break;
01087 }
01088 wtim = tmo - wtim;
01089 }
01090 return rc;
01091 }
01092
01107 static int DhcpBroadcastDiscover(UDPSOCKET * sock, BOOTP *bp, uint32_t xid, uint32_t raddr, uint16_t secs)
01108 {
01109 size_t optlen;
01110 int len;
01111 uint8_t *op = bp->bp_options;
01112
01113 optlen = DhcpPrepHeader(bp, DHCP_DISCOVER, xid, 0, secs);
01114
01115
01116 if (raddr) {
01117 optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
01118 }
01119
01120 optlen += DhcpAddParmReqOption(op + optlen);
01121
01122
01123
01124
01125
01126 len = strlen(confos.hostname);
01127 if (len > 0) {
01128 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01129 }
01130
01131
01132 optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
01133
01134 return DhcpSendMessage(sock, INADDR_BROADCAST, bp, optlen);
01135 }
01136
01137
01157 static int DhcpSendRequest(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid,
01158 uint32_t caddr, uint32_t raddr, uint32_t sid, uint16_t secs)
01159 {
01160 size_t optlen;
01161 int len;
01162 uint8_t *op = bp->bp_options;
01163
01164
01165 optlen = DhcpPrepHeader(bp, DHCP_REQUEST, xid, caddr, secs);
01166
01167
01168 if (raddr) {
01169 optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
01170 }
01171 if (sid) {
01172 optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
01173 }
01174 optlen += DhcpAddParmReqOption(op + optlen);
01175
01176
01177
01178 len = strlen(confos.hostname);
01179 if (len > 0) {
01180 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01181 }
01182
01183 return DhcpSendMessage(sock, daddr, bp, optlen);
01184 }
01185
01204 static int DhcpBroadcastRequest(UDPSOCKET * sock, BOOTP *bp, uint32_t xid,
01205 uint32_t caddr, uint32_t raddr, uint32_t sid, uint16_t secs)
01206 {
01207 return DhcpSendRequest(sock, INADDR_BROADCAST, bp, xid, caddr, raddr, sid, secs);
01208 }
01209
01225 static int DhcpSendRelease(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, uint32_t caddr, uint32_t sid)
01226 {
01227 size_t optlen;
01228 uint8_t *op = bp->bp_options;
01229
01230
01231 optlen = DhcpPrepHeader(bp, DHCP_RELEASE, xid, caddr, 0);
01232
01233
01234 if (sid) {
01235 optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
01236 }
01237 return DhcpSendMessage(sock, daddr, bp, optlen);
01238 }
01239
01252 static int DhcpSendInform(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, uint32_t caddr)
01253 {
01254 size_t optlen;
01255 size_t len;
01256 uint8_t *op = bp->bp_options;
01257
01258
01259 optlen = DhcpPrepHeader(bp, DHCP_INFORM, xid, caddr, 0);
01260
01261
01262 optlen += DhcpAddParmReqOption(op + optlen);
01263
01264
01265 len = strlen(confos.hostname);
01266 if (len > 0) {
01267 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01268 }
01269
01270
01271 optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
01272
01273 return DhcpSendMessage(sock, daddr, bp, optlen);
01274 }
01275
01276
01287 static DYNCFG *CheckOffer(DYNCFG * dyncfg, BOOTP *bp, size_t len)
01288 {
01289 DYNCFG *offer;
01290
01291
01292
01293 if ((offer = ParseReply(bp, len)) == 0) {
01294 return dyncfg;
01295 }
01296
01297
01298 if (offer->dyn_msgtyp != DHCP_OFFER) {
01299 ReleaseDynCfg(offer);
01300 return dyncfg;
01301 }
01302
01303
01304 if (dyncfg == 0) {
01305 dyncfg = offer;
01306 }
01307
01308
01309
01310
01311 else {
01312
01313
01314
01315 if (confnet.cdn_ip_addr & confnet.cdn_ip_mask) {
01316 if (dyncfg->dyn_yiaddr != confnet.cdn_ip_addr &&
01317 offer->dyn_yiaddr == confnet.cdn_ip_addr) {
01318 ReleaseDynCfg(dyncfg);
01319 dyncfg = offer;
01320 }
01321 }
01322
01323 else if (offer->dyn_leaseTime > dyncfg->dyn_leaseTime) {
01324 ReleaseDynCfg(dyncfg);
01325 dyncfg = offer;
01326 }
01327
01328 else {
01329 ReleaseDynCfg(offer);
01330 }
01331 }
01332 return dyncfg;
01333 }
01334
01348 THREAD(NutDhcpClient, arg)
01349 {
01350 DYNCFG *reply = 0;
01351 UDPSOCKET *sock = 0;
01352 BOOTP *bp = 0;
01353 int n;
01354 uint32_t xid;
01355 IFNET *nif;
01356 uint16_t secs = 0;
01357 uint32_t aqsTime = NutGetSeconds();
01358 uint32_t leaseTime = 0;
01359 uint32_t napTime;
01360 ureg_t retries;
01361 uint32_t tmo = MIN_DHCP_WAIT;
01362 uint32_t last_ip = confnet.cdn_ip_addr;
01363 uint32_t server_ip;
01364
01365
01366
01367
01368
01369 #ifdef __arm__
01370 nif = dhcpDev->dev_icb;
01371 #else
01372 nif = ((NUTDEVICE *) arg)->dev_icb;
01373 #endif
01374
01375
01376
01377
01378
01379
01380
01381
01382 xid = 0;
01383 for (retries = 0; retries < sizeof(xid); retries++) {
01384 xid <<= 8;
01385 xid += nif->if_mac[5 - retries];
01386 }
01387 retries = 0;
01388
01389 for (;;) {
01390 #ifdef NUTDEBUG
01391 if (__tcp_trf) {
01392 fprintf(__tcp_trs, "\n[%u.DHCP-", retries + 1);
01393 switch (dhcpState) {
01394 case DHCPST_INIT:
01395 fprintf(__tcp_trs, "INIT]");
01396 break;
01397 case DHCPST_SELECTING:
01398 fprintf(__tcp_trs, "SELECTING]");
01399 break;
01400 case DHCPST_REQUESTING:
01401 fprintf(__tcp_trs, "REQUESTING]");
01402 break;
01403 case DHCPST_REBOOTING:
01404 fprintf(__tcp_trs, "REBOOTING %s]", inet_ntoa(last_ip));
01405 break;
01406 case DHCPST_BOUND:
01407 fprintf(__tcp_trs, "BOUND %lu]", NutGetSeconds() - leaseTime);
01408 break;
01409 case DHCPST_RENEWING:
01410 fprintf(__tcp_trs, "RENEWING %lu]", NutGetSeconds() - leaseTime);
01411 break;
01412 case DHCPST_REBINDING:
01413 fprintf(__tcp_trs, "REBINDING %lu]", NutGetSeconds() - leaseTime);
01414 break;
01415 case DHCPST_INFORMING:
01416 fprintf(__tcp_trs, "INFORMING]");
01417 break;
01418 case DHCPST_RELEASING:
01419 fprintf(__tcp_trs, "RELEASING]");
01420 break;
01421 case DHCPST_IDLE:
01422 if (dhcpError) {
01423 fprintf(__tcp_trs, "ERROR %u]", dhcpError);
01424 } else {
01425 fprintf(__tcp_trs, "IDLE]");
01426 }
01427 break;
01428 default:
01429 fprintf(__tcp_trs, "UNKNOWN %u]", dhcpState);
01430 break;
01431 }
01432 }
01433 #endif
01434
01435
01436
01437
01438 server_ip = INADDR_BROADCAST;
01439 if (retries) {
01440
01441 tmo += tmo;
01442 if (tmo > MAX_DHCP_WAIT) {
01443 tmo = MAX_DHCP_WAIT;
01444 }
01445 } else {
01446
01447 tmo = MIN_DHCP_WAIT;
01448
01449
01450
01451
01452 if (dhcpState != DHCPST_REQUESTING) {
01453 xid++;
01454 }
01455
01456
01457
01458 if (dhcpConfig && dhcpConfig->dyn_sid) {
01459 server_ip = dhcpConfig->dyn_sid;
01460 }
01461 }
01462
01463
01464
01465
01466 if (dhcpState != DHCPST_IDLE && dhcpApiTimeout != NUT_WAIT_INFINITE) {
01467 uint32_t tt = NutGetMillis() - dhcpApiStart;
01468
01469 if (dhcpApiTimeout <= tt) {
01470 dhcpError = DHCPERR_TIMEOUT;
01471 dhcpState = DHCPST_IDLE;
01472 continue;
01473 }
01474 if ((tt = dhcpApiTimeout - tt) < tmo) {
01475 tmo = tt;
01476 }
01477 }
01478
01479
01480
01481
01482 if (dhcpState == DHCPST_SELECTING || dhcpState == DHCPST_RENEWING || dhcpState == DHCPST_REBINDING) {
01483
01484 if (retries) {
01485 if (NutGetSeconds() - aqsTime > 0xffffUL) {
01486 secs = 0xffff;
01487 } else {
01488 secs = (uint16_t) (NutGetSeconds() - aqsTime);
01489 }
01490 }
01491
01492 else {
01493 aqsTime = NutGetSeconds();
01494 secs = 0;
01495 }
01496 }
01497
01498
01499
01500
01501 if (dhcpState == DHCPST_BOUND || dhcpState == DHCPST_IDLE) {
01502 if (sock) {
01503 NutUdpDestroySocket(sock);
01504 sock = 0;
01505 }
01506 if (bp) {
01507 free(bp);
01508 bp = 0;
01509 }
01510 }
01511
01512
01513
01514
01515 else {
01516
01517
01518
01519 if (dhcpConfig == 0 && nif->if_local_ip) {
01520
01521
01522 dhcpState = DHCPST_IDLE;
01523 continue;
01524 }
01525
01526 if (sock == 0 || bp == 0) {
01527 if (sock == 0) {
01528 sock = NutUdpCreateSocket(DHCP_CLIENTPORT);
01529 }
01530 if (bp == 0) {
01531 bp = malloc(sizeof(BOOTP));
01532 }
01533 if (sock == 0 || bp == 0) {
01534
01535 dhcpError = DHCPERR_SYSTEM;
01536 dhcpState = DHCPST_IDLE;
01537
01538
01539
01540 continue;
01541 }
01542 #if MAX_DHCP_BUFSIZE
01543 {
01544 uint16_t max_ms = MAX_DHCP_BUFSIZE;
01545 NutUdpSetSockOpt(sock, SO_RCVBUF, &max_ms, sizeof(max_ms));
01546 }
01547 #endif
01548 }
01549 }
01550
01551
01552
01553
01554 if (dhcpState == DHCPST_INIT) {
01555
01556 retries = 0;
01557
01558 xid++;
01559
01560 if ((last_ip & confnet.cdn_ip_mask) == 0) {
01561
01562 dhcpState = DHCPST_SELECTING;
01563 } else {
01564
01565
01566 dhcpState = DHCPST_REBOOTING;
01567 }
01568 }
01569
01570
01571
01572
01573 else if (dhcpState == DHCPST_SELECTING) {
01574 if (retries++ > MAX_DCHP_RETRIES) {
01575
01576 dhcpError = DHCPERR_TIMEOUT;
01577 dhcpState = DHCPST_IDLE;
01578 }
01579
01580 else if (DhcpBroadcastDiscover(sock, bp, xid, last_ip, secs) < 0) {
01581
01582 dhcpState = DHCPST_IDLE;
01583 } else {
01584
01585 while ((n = DhcpRecvMessage(sock, xid, bp, tmo)) > 0) {
01586
01587 if ((dhcpConfig = CheckOffer(dhcpConfig, bp, n)) != 0) {
01588
01589
01590 if (dhcpApiTimeout < MIN_DHCP_WAIT * 3) {
01591 break;
01592 }
01593
01594
01595 tmo = MIN_DHCP_WAIT;
01596 }
01597 }
01598
01599 if (n < 0) {
01600 dhcpState = DHCPST_IDLE;
01601 }
01602
01603
01604 else if (dhcpConfig) {
01605 retries = 0;
01606 dhcpState = DHCPST_REQUESTING;
01607 }
01608 }
01609 }
01610
01611
01612
01613
01614 else if (dhcpState == DHCPST_REQUESTING) {
01615 if (retries++ > MAX_DCHP_RETRIES) {
01616
01617 dhcpState = DHCPST_INIT;
01618 }
01619
01620
01621 else if (DhcpBroadcastRequest(sock, bp, xid, 0, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid, secs) < 0) {
01622
01623 dhcpState = DHCPST_IDLE;
01624 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01625
01626 dhcpState = DHCPST_IDLE;
01627 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01628
01629 if (reply->dyn_msgtyp == DHCP_ACK) {
01630 ReleaseDynCfg(dhcpConfig);
01631 dhcpConfig = reply;
01632 reply = 0;
01633 leaseTime = aqsTime;
01634 dhcpState = DHCPST_BOUND;
01635 }
01636
01637
01638 else if (reply->dyn_msgtyp == DHCP_NAK) {
01639 dhcpState = DHCPST_INIT;
01640 }
01641 }
01642 }
01643
01644
01645
01646
01647 else if (dhcpState == DHCPST_REBOOTING) {
01648 if (++retries > MAX_DCHP_RETRIES) {
01649
01650 last_ip = 0;
01651 dhcpState = DHCPST_INIT;
01652 }
01653
01654 else if (DhcpBroadcastRequest(sock, bp, xid, 0, last_ip, 0, secs) < 0) {
01655
01656 dhcpState = DHCPST_IDLE;
01657 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01658
01659 dhcpState = DHCPST_IDLE;
01660 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01661 if (reply->dyn_msgtyp == DHCP_ACK) {
01662 ReleaseDynCfg(dhcpConfig);
01663 dhcpConfig = reply;
01664 reply = 0;
01665 leaseTime = aqsTime;
01666 dhcpState = DHCPST_BOUND;
01667 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01668
01669
01670
01671 last_ip = 0;
01672 dhcpState = DHCPST_INIT;
01673 }
01674 }
01675 }
01676
01677
01678
01679
01680 else if (dhcpState == DHCPST_BOUND) {
01681 retries = 0;
01682 NutEventBroadcast(&dhcpDone);
01683 if (dhcpConfig->dyn_renewalTime <= NutGetSeconds() - leaseTime) {
01684 dhcpState = DHCPST_RENEWING;
01685 } else {
01686
01687 napTime = dhcpConfig->dyn_renewalTime - (NutGetSeconds() - leaseTime);
01688 if (napTime > MAX_DHCP_NAPTIME) {
01689 napTime = MAX_DHCP_NAPTIME;
01690 }
01691 NutEventWait(&dhcpWake, napTime * 1000UL);
01692 }
01693 }
01694
01695
01696
01697
01698 else if (dhcpState == DHCPST_RENEWING) {
01699 retries++;
01700 if (tmo / 1000 > dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime)) {
01701 tmo = dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime) * 1000;
01702 }
01703 if (dhcpConfig->dyn_rebindTime <= NutGetSeconds() - leaseTime) {
01704 retries = 0;
01705 dhcpState = DHCPST_REBINDING;
01706 }
01707
01708
01709 else if (DhcpSendRequest(sock, dhcpConfig->dyn_sid, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) <
01710 0) {
01711
01712 retries = 0;
01713 dhcpState = DHCPST_REBINDING;
01714 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01715
01716 dhcpState = DHCPST_IDLE;
01717 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01718 if (reply->dyn_msgtyp == DHCP_ACK) {
01719
01720 ReleaseDynCfg(dhcpConfig);
01721 dhcpConfig = reply;
01722 reply = 0;
01723 leaseTime = aqsTime;
01724 dhcpState = DHCPST_BOUND;
01725 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01726
01727 retries = 0;
01728 dhcpState = DHCPST_REBINDING;
01729 }
01730 }
01731 }
01732
01733
01734
01735
01736 else if (dhcpState == DHCPST_REBINDING) {
01737 retries++;
01738 if (tmo > dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime)) {
01739 tmo = dhcpConfig->dyn_rebindTime - NutGetSeconds() - leaseTime;
01740 }
01741 if (dhcpConfig->dyn_rebindTime <= NutGetSeconds() - leaseTime) {
01742 retries = 0;
01743 dhcpState = DHCPST_REBINDING;
01744 }
01745
01746
01747 else if (DhcpBroadcastRequest(sock, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) < 0) {
01748
01749 dhcpState = DHCPST_IDLE;
01750 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01751
01752 dhcpState = DHCPST_IDLE;
01753 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01754 if (reply->dyn_msgtyp == DHCP_ACK) {
01755
01756 ReleaseDynCfg(dhcpConfig);
01757 dhcpConfig = reply;
01758 reply = 0;
01759 leaseTime = aqsTime;
01760 dhcpState = DHCPST_BOUND;
01761 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771 dhcpState = DHCPST_INIT;
01772 }
01773 }
01774 }
01775
01776
01777
01778
01779 else if (dhcpState == DHCPST_INFORMING) {
01780 if (retries++ > MAX_DCHP_RETRIES) {
01781 dhcpState = DHCPST_IDLE;
01782 } else if (DhcpSendInform(sock, server_ip, bp, xid, nif->if_local_ip) < 0) {
01783 if (server_ip == INADDR_BROADCAST) {
01784 dhcpState = DHCPST_IDLE;
01785 }
01786 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) != 0) {
01787 if (n > 0 &&
01788 (reply = ParseReply(bp, n)) != 0 &&
01789 reply->dyn_msgtyp == DHCP_ACK) {
01790
01791 ReleaseDynCfg(dhcpConfig);
01792 dhcpConfig = reply;
01793 reply = 0;
01794 }
01795 dhcpState = DHCPST_IDLE;
01796 }
01797 }
01798
01799
01800
01801
01802 else if (dhcpState == DHCPST_RELEASING) {
01803 if (dhcpConfig == 0 ||
01804 retries++ > MAX_DCHP_RELEASE_RETRIES ||
01805 DhcpSendRelease(sock, server_ip, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid) < 0) {
01806 if (server_ip == INADDR_BROADCAST) {
01807 dhcpState = DHCPST_IDLE;
01808 }
01809 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01810
01811 dhcpState = DHCPST_IDLE;
01812 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01813 if (reply->dyn_msgtyp == DHCP_ACK) {
01814 dhcpState = DHCPST_IDLE;
01815 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01816 dhcpState = DHCPST_IDLE;
01817 }
01818 }
01819 }
01820
01821
01822
01823
01824
01825
01826
01827
01828 else if (dhcpState == DHCPST_IDLE) {
01829 ReleaseDynCfg(dhcpConfig);
01830 dhcpConfig = 0;
01831 retries = 0;
01832 NutEventBroadcast(&dhcpDone);
01833 NutEventWait(&dhcpWake, NUT_WAIT_INFINITE);
01834 }
01835
01836
01837 if (reply) {
01838 ReleaseDynCfg(reply);
01839 reply = 0;
01840 }
01841 }
01842 }
01843
01858 static int DhcpKick(CONST char *name, uint8_t state, uint32_t timeout)
01859 {
01860 NUTDEVICE *dev;
01861 IFNET *nif;
01862
01863
01864 if ((dev = NutDeviceLookup(name)) == 0 ||
01865 dev->dev_type != IFTYP_NET ||
01866 (nif = dev->dev_icb) == 0 ||
01867 nif->if_type != IFT_ETHER) {
01868 dhcpError = DHCPERR_BADDEV;
01869 return -1;
01870 }
01871
01872
01873 dhcpApiStart = NutGetMillis();
01874 dhcpApiTimeout = timeout;
01875
01876 dhcpState = state;
01877 if (dhcpThread == 0) {
01878 #ifdef __arm__
01879 dhcpDev = dev;
01880 #endif
01881 dhcpThread = NutThreadCreate("dhcpc", NutDhcpClient, dev,
01882 (NUT_THREAD_DHCPSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD);
01883 }
01884 NutEventPost(&dhcpWake);
01885 NutEventWait(&dhcpDone, NUT_WAIT_INFINITE);
01886
01887 return 0;
01888 }
01889
01929 int NutDhcpIfConfig(CONST char *name, uint8_t * mac, uint32_t timeout)
01930 {
01931 uint8_t mac0[6];
01932 uint8_t macF[6];
01933 NUTDEVICE *dev;
01934 IFNET *nif;
01935
01936
01937
01938
01939 if ((dev = NutDeviceLookup(name)) == 0 ||
01940 dev->dev_type != IFTYP_NET ||
01941 (nif = dev->dev_icb) == 0 ||
01942 nif->if_type != IFT_ETHER) {
01943 dhcpError = DHCPERR_BADDEV;
01944 return -1;
01945 }
01946
01947
01948
01949
01950
01951 memset(mac0, 0x00, sizeof(mac0));
01952 memset(macF, 0xFF, sizeof(macF));
01953 if (memcmp(nif->if_mac, mac0, 6) == 0 || memcmp(nif->if_mac, macF, 6) == 0) {
01954
01955
01956
01957
01958 if (mac) {
01959 memcpy(confnet.cdn_mac, mac, sizeof(confnet.cdn_mac));
01960 }
01961
01962
01963
01964
01965
01966
01967
01968 else if (NutNetLoadConfig(name)) {
01969 dhcpError = DHCPERR_NOMAC;
01970 return -1;
01971 }
01972
01973
01974
01975
01976
01977 memcpy(nif->if_mac, confnet.cdn_mac, 6);
01978 NutSleep(500);
01979 }
01980
01981
01982
01983
01984 if ((confnet.cdn_cip_addr & confnet.cdn_ip_mask) != 0) {
01985 confnet.cdn_ip_addr = confnet.cdn_cip_addr;
01986 NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
01987 return 0;
01988 }
01989
01990
01991
01992
01993
01994
01995 if (DhcpKick(name, DHCPST_INIT, timeout) == 0) {
01996
01997
01998
01999
02000 if (dhcpState == DHCPST_BOUND) {
02001 #ifdef NUTDEBUG
02002 if (__tcp_trf) {
02003 fprintf(__tcp_trs, "[DHCP-Config %s]", inet_ntoa(dhcpConfig->dyn_yiaddr));
02004 }
02005 #endif
02006 NutNetIfSetup(dev, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_netmask, dhcpConfig->dyn_gateway);
02007 NutDnsConfig2(0, 0, dhcpConfig->dyn_pdns, dhcpConfig->dyn_sdns);
02008 return 0;
02009 }
02010
02011
02012
02013
02014
02015 if (nif->if_local_ip) {
02016 #ifdef NUTDEBUG
02017 if (__tcp_trf) {
02018 fprintf(__tcp_trs, "[DHCP-External %s]", inet_ntoa(nif->if_local_ip));
02019 }
02020 #endif
02021 return 0;
02022 }
02023
02024
02025
02026
02027
02028 if ((confnet.cdn_ip_addr & confnet.cdn_ip_mask) != 0) {
02029 #ifdef NUTDEBUG
02030 if (__tcp_trf) {
02031 fprintf(__tcp_trs, "[DHCP-Reusing %s]", inet_ntoa(confnet.cdn_ip_addr));
02032 }
02033 #endif
02034 NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
02035 return 0;
02036 }
02037 }
02038 return -1;
02039 }
02040
02057 int NutDhcpRelease(CONST char *name, uint32_t timeout)
02058 {
02059
02060 if (dhcpState != DHCPST_BOUND) {
02061 dhcpError = DHCPERR_STATE;
02062 return -1;
02063 }
02064
02065
02066 return DhcpKick(name, DHCPST_RELEASING, timeout);
02067 }
02068
02079 int NutDhcpInform(CONST char *name, uint32_t timeout)
02080 {
02081
02082 if (dhcpState != DHCPST_IDLE) {
02083 dhcpError = DHCPERR_STATE;
02084 return -1;
02085 }
02086
02087
02088 return DhcpKick(name, DHCPST_INFORMING, timeout);
02089 }
02090
02108 int NutDhcpStatus(CONST char *name)
02109 {
02110 return dhcpState;
02111 }
02112
02131 int NutDhcpError(CONST char *name)
02132 {
02133 int rc = dhcpError;
02134 dhcpError = 0;
02135 return rc;
02136 }
02137
02145 int NutDhcpIsConfigured(void)
02146 {
02147 return (dhcpState == DHCPST_BOUND);
02148 }
02149