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 #if defined(__GNUC__)
00379
00380 #define NUT_THREAD_DHCPSTACK 288
00381 #else
00382
00383 #define NUT_THREAD_DHCPSTACK 512
00384 #endif
00385 #else
00386
00387 #define NUT_THREAD_DHCPSTACK 384
00388 #endif
00389 #endif
00390
00399
00402 #define DHCP_DISCOVER 1
00403
00408 #define DHCP_OFFER 2
00409
00417 #define DHCP_REQUEST 3
00418
00423 #define DHCP_DECLINE 4
00424
00429 #define DHCP_ACK 5
00430
00435 #define DHCP_NAK 6
00436
00439 #define DHCP_RELEASE 7
00440
00445 #define DHCP_INFORM 8
00446
00456
00463 #define DHCPOPT_PAD 0
00464
00468 #define DHCPOPT_NETMASK 1
00469
00473 #define DHCPOPT_GATEWAY 3
00474
00478 #define DHCPOPT_DNS 6
00479
00483 #define DHCPOPT_HOSTNAME 12
00484
00488 #define DHCPOPT_DOMAIN 15
00489
00493 #define DHCPOPT_BROADCAST 28
00494
00498 #define DHCPOPT_REQESTIP 50
00499
00503 #define DHCPOPT_LEASETIME 51
00504
00508 #define DHCPOPT_MSGTYPE 53
00509
00513 #define DHCPOPT_SID 54
00514
00518 #define DHCPOPT_PARAMREQUEST 55
00519
00523 #define DHCPOPT_MAXMSGSIZE 57
00524
00528 #define DHCPOPT_RENEWALTIME 58
00529
00533 #define DHCPOPT_REBINDTIME 59
00534
00538 #define DHCPOPT_END 255
00539
00545 typedef struct bootp BOOTP;
00546
00550 struct __attribute__ ((packed)) bootp {
00551 uint8_t bp_op;
00552 uint8_t bp_htype;
00553 uint8_t bp_hlen;
00554 uint8_t bp_hops;
00555 uint32_t bp_xid;
00556 uint16_t bp_secs;
00557 uint16_t bp_flags;
00558 uint32_t bp_ciaddr;
00559 uint32_t bp_yiaddr;
00560 uint32_t bp_siaddr;
00561 uint32_t bp_giaddr;
00562 uint8_t bp_chaddr[16];
00563 char bp_sname[64];
00564 char bp_file[128];
00565 uint8_t bp_options[312];
00566 };
00567
00571 typedef struct dyn_cfg DYNCFG;
00572
00576 struct dyn_cfg {
00577 uint8_t dyn_msgtyp;
00578 uint32_t dyn_yiaddr;
00579 uint32_t dyn_netmask;
00580 uint32_t dyn_broadcast;
00581 uint32_t dyn_gateway;
00582 uint32_t dyn_pdns;
00583 uint32_t dyn_sdns;
00584 uint32_t dyn_sid;
00585 uint32_t dyn_renewalTime;
00586 uint32_t dyn_rebindTime;
00587 uint32_t dyn_leaseTime;
00588 uint8_t *dyn_hostname;
00589 uint8_t *dyn_domain;
00590 };
00591
00598 static DYNCFG *dhcpConfig;
00599
00606 static HANDLE dhcpThread;
00607
00611 static uint8_t dhcpState;
00612
00616 static int dhcpError;
00617
00623 static HANDLE dhcpWake;
00624
00630 static HANDLE dhcpDone;
00631
00637 static uint32_t dhcpApiTimeout;
00638
00645 static uint32_t dhcpApiStart;
00646
00653 #ifdef __arm__
00654 static NUTDEVICE *dhcpDev;
00655 #endif
00656
00668 static void copy_str(uint8_t ** dst, void *src, int len)
00669 {
00670 if (*dst) {
00671 free(*dst);
00672 }
00673 if ((*dst = malloc(len + 1)) != 0) {
00674 if (len) {
00675 memcpy(*dst, src, len);
00676 }
00677 *(*dst + len) = 0;
00678 }
00679 }
00680
00688 static void ReleaseDynCfg(DYNCFG * dyncfg)
00689 {
00690 if (dyncfg) {
00691 if (dyncfg->dyn_hostname) {
00692 free(dyncfg->dyn_hostname);
00693 }
00694 if (dyncfg->dyn_domain) {
00695 free(dyncfg->dyn_domain);
00696 }
00697 free(dyncfg);
00698 }
00699 }
00700
00712 static DYNCFG *ParseReply(BOOTP *bp, int len)
00713 {
00714 uint8_t *op;
00715 int left;
00716 DYNCFG *cfgp;
00717
00718
00719 if ((cfgp = malloc(sizeof(DYNCFG))) == 0) {
00720 return 0;
00721 }
00722 memset(cfgp, 0, sizeof(DYNCFG));
00723 cfgp->dyn_leaseTime = DHCP_DEFAULT_LEASE;
00724
00725
00726 memcpy(&cfgp->dyn_yiaddr, &bp->bp_yiaddr, 4);
00727
00728
00729
00730
00731
00732 op = bp->bp_options + 4;
00733 left = len - (sizeof(*bp) - sizeof(bp->bp_options)) - 4;
00734 while (*op != DHCPOPT_END && left > 0) {
00735 uint8_t ol;
00736
00737 #ifdef NUTDEBUG
00738 if (__tcp_trf) {
00739 fprintf(__tcp_trs, "[DHCP-Opt-%u]", *op);
00740 }
00741 #endif
00742
00743 if (*op == DHCPOPT_PAD) {
00744 op++;
00745 left--;
00746 continue;
00747 }
00748
00749
00750 if ((ol = *(op + 1)) > left) {
00751 break;
00752 }
00753
00754
00755 if (*op == DHCPOPT_MSGTYPE) {
00756 if (ol != 1) {
00757 break;
00758 }
00759 cfgp->dyn_msgtyp = *(op + 2);
00760 }
00761
00762 else if (*op == DHCPOPT_HOSTNAME) {
00763 copy_str(&cfgp->dyn_hostname, op + 2, ol);
00764 }
00765
00766 else if (*op == DHCPOPT_DOMAIN) {
00767 copy_str(&cfgp->dyn_domain, op + 2, ol);
00768 }
00769
00770
00771 else if (ol >= 4) {
00772
00773 uint32_t lval = *(op + 2);
00774 lval += (uint32_t)(*(op + 3)) << 8;
00775 lval += (uint32_t)(*(op + 4)) << 16;
00776 lval += (uint32_t)(*(op + 5)) << 24;
00777
00778
00779 if (*op == DHCPOPT_NETMASK) {
00780 cfgp->dyn_netmask = lval;
00781 }
00782
00783 else if (*op == DHCPOPT_BROADCAST) {
00784 cfgp->dyn_broadcast = lval;
00785 }
00786
00787
00788
00789 else if (*op == DHCPOPT_GATEWAY) {
00790 cfgp->dyn_gateway = lval;
00791 }
00792
00793
00794 else if (*op == DHCPOPT_DNS) {
00795 cfgp->dyn_pdns = lval;
00796 if (ol >= 8) {
00797 cfgp->dyn_sdns = *(op + 6);
00798 cfgp->dyn_sdns += (uint32_t)(*(op + 7)) << 8;
00799 cfgp->dyn_sdns += (uint32_t)(*(op + 8)) << 16;
00800 cfgp->dyn_sdns += (uint32_t)(*(op + 9)) << 24;
00801 }
00802 }
00803
00804 else if (*op == DHCPOPT_SID) {
00805 cfgp->dyn_sid = lval;
00806 }
00807
00808 else if (*op == DHCPOPT_RENEWALTIME) {
00809 cfgp->dyn_renewalTime = ntohl(lval);
00810 }
00811
00812 else if (*op == DHCPOPT_REBINDTIME) {
00813 cfgp->dyn_rebindTime = ntohl(lval);
00814 }
00815
00816 else if (*op == DHCPOPT_LEASETIME) {
00817 cfgp->dyn_leaseTime = ntohl(lval);
00818 }
00819 }
00820 op += ol + 2;
00821 left -= ol + 2;
00822 }
00823
00824
00825
00826
00827
00828 if (*op != DHCPOPT_END ||
00829 (cfgp->dyn_msgtyp != DHCP_OFFER &&
00830 cfgp->dyn_msgtyp != DHCP_ACK &&
00831 cfgp->dyn_msgtyp != DHCP_NAK)) {
00832 #ifdef NUTDEBUG
00833 if (__tcp_trf) {
00834 fprintf(__tcp_trs, "[DHCP-Parse Error]");
00835 }
00836 #endif
00837 ReleaseDynCfg(cfgp);
00838 return 0;
00839 }
00840
00841
00842 if (cfgp->dyn_renewalTime == 0) {
00843 cfgp->dyn_renewalTime = cfgp->dyn_leaseTime / 2;
00844 }
00845 if (cfgp->dyn_rebindTime == 0) {
00846 cfgp->dyn_rebindTime = cfgp->dyn_renewalTime +
00847 cfgp->dyn_renewalTime / 2 +
00848 cfgp->dyn_renewalTime / 4;
00849 }
00850 return cfgp;
00851 }
00852
00863 static size_t DhcpAddOption(uint8_t * op, uint8_t ot, void *ov, uint8_t len)
00864 {
00865 *op++ = ot;
00866 *op++ = len;
00867 memcpy(op, ov, len);
00868
00869 return 2 + len;
00870 }
00871
00881 static size_t DhcpAddByteOption(uint8_t * op, uint8_t ot, uint8_t ov)
00882 {
00883 *op++ = ot;
00884 *op++ = 1;
00885 *op++ = ov;
00886
00887 return 3;
00888 }
00889
00900 static size_t DhcpAddShortOption(uint8_t * op, uint8_t ot, uint16_t ov)
00901 {
00902 *op++ = ot;
00903 *op++ = 2;
00904 ov = htons(ov);
00905 memcpy(op, &ov, 2);
00906
00907 return 4;
00908 }
00909
00922 static size_t DhcpAddParmReqOption(uint8_t * op)
00923 {
00924 *op++ = DHCPOPT_PARAMREQUEST;
00925 *op++ = 3;
00926 *op++ = DHCPOPT_NETMASK;
00927 *op++ = DHCPOPT_GATEWAY;
00928 *op++ = DHCPOPT_DNS;
00929 return 5;
00930 }
00931
00953 static unsigned int DhcpPrepHeader(BOOTP *bp, uint8_t msgtyp, uint32_t xid, uint32_t ciaddr, uint16_t secs)
00954 {
00955 uint8_t *op;
00956
00957 memset(bp, 0, sizeof(*bp));
00958
00959 bp->bp_op = 1;
00960
00961 bp->bp_htype = 1;
00962 bp->bp_hlen = 6;
00963 memcpy(bp->bp_chaddr, confnet.cdn_mac, 6);
00964
00965 bp->bp_xid = xid;
00966
00967 bp->bp_secs = htons(secs);
00968
00969 #ifdef DHCP_BROADCAST_FLAG
00970
00971
00972
00973
00974
00975 bp->bp_flags = htons(0x8000);
00976 #endif
00977
00978 bp->bp_ciaddr = ciaddr;
00979
00980
00981 op = bp->bp_options;
00982 *op++ = 0x63;
00983 *op++ = 0x82;
00984 *op++ = 0x53;
00985 *op++ = 0x63;
00986
00987
00988 return DhcpAddByteOption(op, DHCPOPT_MSGTYPE, msgtyp) + 4;
00989 }
00990
01009 static int DhcpSendMessage(UDPSOCKET * sock, uint32_t addr, BOOTP *bp, size_t len)
01010 {
01011
01012 bp->bp_options[len++] = DHCPOPT_END;
01013
01014
01015
01016 if ((len += sizeof(BOOTP) - sizeof(bp->bp_options)) < MIN_DHCP_MSGSIZE) {
01017 len = MIN_DHCP_MSGSIZE;
01018 }
01019 #ifdef NUTDEBUG
01020 if (__tcp_trf) {
01021 fprintf(__tcp_trs, "[DHCP-Send to %s]", inet_ntoa(addr));
01022 }
01023 #endif
01024 if (NutUdpSendTo(sock, addr, DHCP_SERVERPORT, bp, len) < 0) {
01025 dhcpError = DHCPERR_TRANSMIT;
01026 return -1;
01027 }
01028 return 0;
01029 }
01030
01044 static int DhcpRecvMessage(UDPSOCKET * sock, uint32_t xid, BOOTP *bp, uint32_t tmo)
01045 {
01046 int rc;
01047 uint16_t port;
01048 uint32_t addr;
01049 uint32_t etim;
01050 uint32_t wtim;
01051
01052
01053 etim = NutGetMillis();
01054
01055 wtim = tmo;
01056 for (;;) {
01057 rc = NutUdpReceiveFrom(sock, &addr, &port, bp, sizeof(BOOTP), wtim);
01058 #ifdef NUTDEBUG
01059 if (__tcp_trf) {
01060 if (rc > 0) {
01061 fprintf(__tcp_trs, "[DHCP-Recv from %s]", inet_ntoa(addr));
01062 } else if (rc < 0) {
01063 fprintf(__tcp_trs, "[DHCP-Recv Error]");
01064 } else {
01065 fprintf(__tcp_trs, "[DHCP-Recv Timeout %lu]", tmo);
01066 }
01067 }
01068 #endif
01069
01070 if (rc <= 0) {
01071 if (rc < 0) {
01072 dhcpError = DHCPERR_RECEIVE;
01073 }
01074 break;
01075 }
01076
01077
01078 if (rc > sizeof(BOOTP) - sizeof(bp->bp_options) + 5) {
01079
01080 if (bp->bp_op == 2 && bp->bp_xid == xid) {
01081
01082 break;
01083 }
01084 }
01085
01086
01087 wtim = NutGetMillis() - etim;
01088 if (wtim >= tmo - 250) {
01089
01090 rc = 0;
01091 break;
01092 }
01093 wtim = tmo - wtim;
01094 }
01095 return rc;
01096 }
01097
01112 static int DhcpBroadcastDiscover(UDPSOCKET * sock, BOOTP *bp, uint32_t xid, uint32_t raddr, uint16_t secs)
01113 {
01114 size_t optlen;
01115 int len;
01116 uint8_t *op = bp->bp_options;
01117
01118 optlen = DhcpPrepHeader(bp, DHCP_DISCOVER, xid, 0, secs);
01119
01120
01121 if (raddr) {
01122 optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
01123 }
01124
01125 optlen += DhcpAddParmReqOption(op + optlen);
01126
01127
01128
01129
01130
01131 len = strlen(confos.hostname);
01132 if (len > 0) {
01133 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01134 }
01135
01136
01137 optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
01138
01139 return DhcpSendMessage(sock, INADDR_BROADCAST, bp, optlen);
01140 }
01141
01142
01162 static int DhcpSendRequest(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid,
01163 uint32_t caddr, uint32_t raddr, uint32_t sid, uint16_t secs)
01164 {
01165 size_t optlen;
01166 int len;
01167 uint8_t *op = bp->bp_options;
01168
01169
01170 optlen = DhcpPrepHeader(bp, DHCP_REQUEST, xid, caddr, secs);
01171
01172
01173 if (raddr) {
01174 optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
01175 }
01176 if (sid) {
01177 optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
01178 }
01179 optlen += DhcpAddParmReqOption(op + optlen);
01180
01181
01182
01183 len = strlen(confos.hostname);
01184 if (len > 0) {
01185 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01186 }
01187
01188 return DhcpSendMessage(sock, daddr, bp, optlen);
01189 }
01190
01209 static int DhcpBroadcastRequest(UDPSOCKET * sock, BOOTP *bp, uint32_t xid,
01210 uint32_t caddr, uint32_t raddr, uint32_t sid, uint16_t secs)
01211 {
01212 return DhcpSendRequest(sock, INADDR_BROADCAST, bp, xid, caddr, raddr, sid, secs);
01213 }
01214
01230 static int DhcpSendRelease(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, uint32_t caddr, uint32_t sid)
01231 {
01232 size_t optlen;
01233 uint8_t *op = bp->bp_options;
01234
01235
01236 optlen = DhcpPrepHeader(bp, DHCP_RELEASE, xid, caddr, 0);
01237
01238
01239 if (sid) {
01240 optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
01241 }
01242 return DhcpSendMessage(sock, daddr, bp, optlen);
01243 }
01244
01257 static int DhcpSendInform(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, uint32_t caddr)
01258 {
01259 size_t optlen;
01260 size_t len;
01261 uint8_t *op = bp->bp_options;
01262
01263
01264 optlen = DhcpPrepHeader(bp, DHCP_INFORM, xid, caddr, 0);
01265
01266
01267 optlen += DhcpAddParmReqOption(op + optlen);
01268
01269
01270 len = strlen(confos.hostname);
01271 if (len > 0) {
01272 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01273 }
01274
01275
01276 optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
01277
01278 return DhcpSendMessage(sock, daddr, bp, optlen);
01279 }
01280
01281
01292 static DYNCFG *CheckOffer(DYNCFG * dyncfg, BOOTP *bp, size_t len)
01293 {
01294 DYNCFG *offer;
01295
01296
01297
01298 if ((offer = ParseReply(bp, len)) == 0) {
01299 return dyncfg;
01300 }
01301
01302
01303 if (offer->dyn_msgtyp != DHCP_OFFER) {
01304 ReleaseDynCfg(offer);
01305 return dyncfg;
01306 }
01307
01308
01309 if (dyncfg == 0) {
01310 dyncfg = offer;
01311 }
01312
01313
01314
01315
01316 else {
01317
01318
01319
01320 if (confnet.cdn_ip_addr & confnet.cdn_ip_mask) {
01321 if (dyncfg->dyn_yiaddr != confnet.cdn_ip_addr &&
01322 offer->dyn_yiaddr == confnet.cdn_ip_addr) {
01323 ReleaseDynCfg(dyncfg);
01324 dyncfg = offer;
01325 }
01326 }
01327
01328 else if (offer->dyn_leaseTime > dyncfg->dyn_leaseTime) {
01329 ReleaseDynCfg(dyncfg);
01330 dyncfg = offer;
01331 }
01332
01333 else {
01334 ReleaseDynCfg(offer);
01335 }
01336 }
01337 return dyncfg;
01338 }
01339
01353 THREAD(NutDhcpClient, arg)
01354 {
01355 DYNCFG *reply = 0;
01356 UDPSOCKET *sock = 0;
01357 BOOTP *bp = 0;
01358 int n;
01359 uint32_t xid;
01360 IFNET *nif;
01361 uint16_t secs = 0;
01362 uint32_t aqsTime = NutGetSeconds();
01363 uint32_t leaseTime = 0;
01364 uint32_t napTime;
01365 ureg_t retries;
01366 uint32_t tmo = MIN_DHCP_WAIT;
01367 uint32_t last_ip = confnet.cdn_ip_addr;
01368 uint32_t server_ip;
01369
01370
01371
01372
01373
01374 #ifdef __arm__
01375 nif = dhcpDev->dev_icb;
01376 #else
01377 nif = ((NUTDEVICE *) arg)->dev_icb;
01378 #endif
01379
01380
01381
01382
01383
01384
01385
01386
01387 xid = 0;
01388 for (retries = 0; retries < sizeof(xid); retries++) {
01389 xid <<= 8;
01390 xid += nif->if_mac[5 - retries];
01391 }
01392 retries = 0;
01393
01394 for (;;) {
01395 #ifdef NUTDEBUG
01396 if (__tcp_trf) {
01397 fprintf(__tcp_trs, "\n[%u.DHCP-", retries + 1);
01398 switch (dhcpState) {
01399 case DHCPST_INIT:
01400 fprintf(__tcp_trs, "INIT]");
01401 break;
01402 case DHCPST_SELECTING:
01403 fprintf(__tcp_trs, "SELECTING]");
01404 break;
01405 case DHCPST_REQUESTING:
01406 fprintf(__tcp_trs, "REQUESTING]");
01407 break;
01408 case DHCPST_REBOOTING:
01409 fprintf(__tcp_trs, "REBOOTING %s]", inet_ntoa(last_ip));
01410 break;
01411 case DHCPST_BOUND:
01412 fprintf(__tcp_trs, "BOUND %lu]", NutGetSeconds() - leaseTime);
01413 break;
01414 case DHCPST_RENEWING:
01415 fprintf(__tcp_trs, "RENEWING %lu]", NutGetSeconds() - leaseTime);
01416 break;
01417 case DHCPST_REBINDING:
01418 fprintf(__tcp_trs, "REBINDING %lu]", NutGetSeconds() - leaseTime);
01419 break;
01420 case DHCPST_INFORMING:
01421 fprintf(__tcp_trs, "INFORMING]");
01422 break;
01423 case DHCPST_RELEASING:
01424 fprintf(__tcp_trs, "RELEASING]");
01425 break;
01426 case DHCPST_IDLE:
01427 if (dhcpError) {
01428 fprintf(__tcp_trs, "ERROR %u]", dhcpError);
01429 } else {
01430 fprintf(__tcp_trs, "IDLE]");
01431 }
01432 break;
01433 default:
01434 fprintf(__tcp_trs, "UNKNOWN %u]", dhcpState);
01435 break;
01436 }
01437 }
01438 #endif
01439
01440
01441
01442
01443 server_ip = INADDR_BROADCAST;
01444 if (retries) {
01445
01446 tmo += tmo;
01447 if (tmo > MAX_DHCP_WAIT) {
01448 tmo = MAX_DHCP_WAIT;
01449 }
01450 } else {
01451
01452 tmo = MIN_DHCP_WAIT;
01453
01454
01455
01456
01457 if (dhcpState != DHCPST_REQUESTING) {
01458 xid++;
01459 }
01460
01461
01462
01463 if (dhcpConfig && dhcpConfig->dyn_sid) {
01464 server_ip = dhcpConfig->dyn_sid;
01465 }
01466 }
01467
01468
01469
01470
01471 if (dhcpState != DHCPST_IDLE && dhcpApiTimeout != NUT_WAIT_INFINITE) {
01472 uint32_t tt = NutGetMillis() - dhcpApiStart;
01473
01474 if (dhcpApiTimeout <= tt) {
01475 dhcpError = DHCPERR_TIMEOUT;
01476 dhcpState = DHCPST_IDLE;
01477 continue;
01478 }
01479 if ((tt = dhcpApiTimeout - tt) < tmo) {
01480 tmo = tt;
01481 }
01482 }
01483
01484
01485
01486
01487 if (dhcpState == DHCPST_SELECTING || dhcpState == DHCPST_RENEWING || dhcpState == DHCPST_REBINDING) {
01488
01489 if (retries) {
01490 if (NutGetSeconds() - aqsTime > 0xffffUL) {
01491 secs = 0xffff;
01492 } else {
01493 secs = (uint16_t) (NutGetSeconds() - aqsTime);
01494 }
01495 }
01496
01497 else {
01498 aqsTime = NutGetSeconds();
01499 secs = 0;
01500 }
01501 }
01502
01503
01504
01505
01506 if (dhcpState == DHCPST_BOUND || dhcpState == DHCPST_IDLE) {
01507 if (sock) {
01508 NutUdpDestroySocket(sock);
01509 sock = 0;
01510 }
01511 if (bp) {
01512 free(bp);
01513 bp = 0;
01514 }
01515 }
01516
01517
01518
01519
01520 else {
01521
01522
01523
01524 if (dhcpConfig == 0 && nif->if_local_ip) {
01525
01526
01527 dhcpState = DHCPST_IDLE;
01528 continue;
01529 }
01530
01531 if (sock == 0 || bp == 0) {
01532 if (sock == 0) {
01533 sock = NutUdpCreateSocket(DHCP_CLIENTPORT);
01534 }
01535 if (bp == 0) {
01536 bp = malloc(sizeof(BOOTP));
01537 }
01538 if (sock == 0 || bp == 0) {
01539
01540 dhcpError = DHCPERR_SYSTEM;
01541 dhcpState = DHCPST_IDLE;
01542
01543
01544
01545 continue;
01546 }
01547 #if MAX_DHCP_BUFSIZE
01548 {
01549 uint16_t max_ms = MAX_DHCP_BUFSIZE;
01550 NutUdpSetSockOpt(sock, SO_RCVBUF, &max_ms, sizeof(max_ms));
01551 }
01552 #endif
01553 }
01554 }
01555
01556
01557
01558
01559 if (dhcpState == DHCPST_INIT) {
01560
01561 retries = 0;
01562
01563 xid++;
01564
01565 if ((last_ip & confnet.cdn_ip_mask) == 0) {
01566
01567 dhcpState = DHCPST_SELECTING;
01568 } else {
01569
01570
01571 dhcpState = DHCPST_REBOOTING;
01572 }
01573 }
01574
01575
01576
01577
01578 else if (dhcpState == DHCPST_SELECTING) {
01579 if (retries++ > MAX_DCHP_RETRIES) {
01580
01581 dhcpError = DHCPERR_TIMEOUT;
01582 dhcpState = DHCPST_IDLE;
01583 }
01584
01585 else if (DhcpBroadcastDiscover(sock, bp, xid, last_ip, secs) < 0) {
01586
01587 dhcpState = DHCPST_IDLE;
01588 } else {
01589
01590 while ((n = DhcpRecvMessage(sock, xid, bp, tmo)) > 0) {
01591
01592 if ((dhcpConfig = CheckOffer(dhcpConfig, bp, n)) != 0) {
01593
01594
01595 if (dhcpApiTimeout < MIN_DHCP_WAIT * 3) {
01596 break;
01597 }
01598
01599
01600 tmo = MIN_DHCP_WAIT;
01601 }
01602 }
01603
01604 if (n < 0) {
01605 dhcpState = DHCPST_IDLE;
01606 }
01607
01608
01609 else if (dhcpConfig) {
01610 retries = 0;
01611 dhcpState = DHCPST_REQUESTING;
01612 }
01613 }
01614 }
01615
01616
01617
01618
01619 else if (dhcpState == DHCPST_REQUESTING) {
01620 if (retries++ > MAX_DCHP_RETRIES) {
01621
01622 dhcpState = DHCPST_INIT;
01623 }
01624
01625
01626 else if (DhcpBroadcastRequest(sock, bp, xid, 0, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid, secs) < 0) {
01627
01628 dhcpState = DHCPST_IDLE;
01629 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01630
01631 dhcpState = DHCPST_IDLE;
01632 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01633
01634 if (reply->dyn_msgtyp == DHCP_ACK) {
01635 ReleaseDynCfg(dhcpConfig);
01636 dhcpConfig = reply;
01637 reply = 0;
01638 leaseTime = aqsTime;
01639 dhcpState = DHCPST_BOUND;
01640 }
01641
01642
01643 else if (reply->dyn_msgtyp == DHCP_NAK) {
01644 dhcpState = DHCPST_INIT;
01645 }
01646 }
01647 }
01648
01649
01650
01651
01652 else if (dhcpState == DHCPST_REBOOTING) {
01653 if (++retries > MAX_DCHP_RETRIES) {
01654
01655 last_ip = 0;
01656 dhcpState = DHCPST_INIT;
01657 }
01658
01659 else if (DhcpBroadcastRequest(sock, bp, xid, 0, last_ip, 0, secs) < 0) {
01660
01661 dhcpState = DHCPST_IDLE;
01662 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01663
01664 dhcpState = DHCPST_IDLE;
01665 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01666 if (reply->dyn_msgtyp == DHCP_ACK) {
01667 ReleaseDynCfg(dhcpConfig);
01668 dhcpConfig = reply;
01669 reply = 0;
01670 leaseTime = aqsTime;
01671 dhcpState = DHCPST_BOUND;
01672 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01673
01674
01675
01676 last_ip = 0;
01677 dhcpState = DHCPST_INIT;
01678 }
01679 }
01680 }
01681
01682
01683
01684
01685 else if (dhcpState == DHCPST_BOUND) {
01686 retries = 0;
01687 NutEventBroadcast(&dhcpDone);
01688 if (dhcpConfig->dyn_renewalTime <= NutGetSeconds() - leaseTime) {
01689 dhcpState = DHCPST_RENEWING;
01690 } else {
01691
01692 napTime = dhcpConfig->dyn_renewalTime - (NutGetSeconds() - leaseTime);
01693 if (napTime > MAX_DHCP_NAPTIME) {
01694 napTime = MAX_DHCP_NAPTIME;
01695 }
01696 NutEventWait(&dhcpWake, napTime * 1000UL);
01697 }
01698 }
01699
01700
01701
01702
01703 else if (dhcpState == DHCPST_RENEWING) {
01704 retries++;
01705 if (tmo / 1000 > dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime)) {
01706 tmo = dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime) * 1000;
01707 }
01708 if (dhcpConfig->dyn_rebindTime <= NutGetSeconds() - leaseTime) {
01709 retries = 0;
01710 dhcpState = DHCPST_REBINDING;
01711 }
01712
01713
01714 else if (DhcpSendRequest(sock, dhcpConfig->dyn_sid, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) <
01715 0) {
01716
01717 retries = 0;
01718 dhcpState = DHCPST_REBINDING;
01719 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01720
01721 dhcpState = DHCPST_IDLE;
01722 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01723 if (reply->dyn_msgtyp == DHCP_ACK) {
01724
01725 ReleaseDynCfg(dhcpConfig);
01726 dhcpConfig = reply;
01727 reply = 0;
01728 leaseTime = aqsTime;
01729 dhcpState = DHCPST_BOUND;
01730 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01731
01732 retries = 0;
01733 dhcpState = DHCPST_REBINDING;
01734 }
01735 }
01736 }
01737
01738
01739
01740
01741 else if (dhcpState == DHCPST_REBINDING) {
01742 retries++;
01743 if (tmo > dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime)) {
01744 tmo = dhcpConfig->dyn_rebindTime - NutGetSeconds() - leaseTime;
01745 }
01746 if (dhcpConfig->dyn_rebindTime <= NutGetSeconds() - leaseTime) {
01747 retries = 0;
01748 dhcpState = DHCPST_REBINDING;
01749 }
01750
01751
01752 else if (DhcpBroadcastRequest(sock, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) < 0) {
01753
01754 dhcpState = DHCPST_IDLE;
01755 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01756
01757 dhcpState = DHCPST_IDLE;
01758 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01759 if (reply->dyn_msgtyp == DHCP_ACK) {
01760
01761 ReleaseDynCfg(dhcpConfig);
01762 dhcpConfig = reply;
01763 reply = 0;
01764 leaseTime = aqsTime;
01765 dhcpState = DHCPST_BOUND;
01766 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776 dhcpState = DHCPST_INIT;
01777 }
01778 }
01779 }
01780
01781
01782
01783
01784 else if (dhcpState == DHCPST_INFORMING) {
01785 if (retries++ > MAX_DCHP_RETRIES) {
01786 dhcpState = DHCPST_IDLE;
01787 } else if (DhcpSendInform(sock, server_ip, bp, xid, nif->if_local_ip) < 0) {
01788 if (server_ip == INADDR_BROADCAST) {
01789 dhcpState = DHCPST_IDLE;
01790 }
01791 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) != 0) {
01792 if (n > 0 &&
01793 (reply = ParseReply(bp, n)) != 0 &&
01794 reply->dyn_msgtyp == DHCP_ACK) {
01795
01796 ReleaseDynCfg(dhcpConfig);
01797 dhcpConfig = reply;
01798 reply = 0;
01799 }
01800 dhcpState = DHCPST_IDLE;
01801 }
01802 }
01803
01804
01805
01806
01807 else if (dhcpState == DHCPST_RELEASING) {
01808 if (dhcpConfig == 0 ||
01809 retries++ > MAX_DCHP_RELEASE_RETRIES ||
01810 DhcpSendRelease(sock, server_ip, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid) < 0) {
01811 if (server_ip == INADDR_BROADCAST) {
01812 dhcpState = DHCPST_IDLE;
01813 }
01814 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01815
01816 dhcpState = DHCPST_IDLE;
01817 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01818 if (reply->dyn_msgtyp == DHCP_ACK) {
01819 dhcpState = DHCPST_IDLE;
01820 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01821 dhcpState = DHCPST_IDLE;
01822 }
01823 }
01824 }
01825
01826
01827
01828
01829
01830
01831
01832
01833 else if (dhcpState == DHCPST_IDLE) {
01834 ReleaseDynCfg(dhcpConfig);
01835 dhcpConfig = 0;
01836 retries = 0;
01837 NutEventBroadcast(&dhcpDone);
01838 NutEventWait(&dhcpWake, NUT_WAIT_INFINITE);
01839 }
01840
01841
01842 if (reply) {
01843 ReleaseDynCfg(reply);
01844 reply = 0;
01845 }
01846 }
01847 }
01848
01863 static int DhcpKick(CONST char *name, uint8_t state, uint32_t timeout)
01864 {
01865 NUTDEVICE *dev;
01866 IFNET *nif;
01867
01868
01869 if ((dev = NutDeviceLookup(name)) == 0 ||
01870 dev->dev_type != IFTYP_NET ||
01871 (nif = dev->dev_icb) == 0 ||
01872 nif->if_type != IFT_ETHER) {
01873 dhcpError = DHCPERR_BADDEV;
01874 return -1;
01875 }
01876
01877
01878 dhcpApiStart = NutGetMillis();
01879 dhcpApiTimeout = timeout;
01880
01881 dhcpState = state;
01882 if (dhcpThread == 0) {
01883 #ifdef __arm__
01884 dhcpDev = dev;
01885 #endif
01886 dhcpThread = NutThreadCreate("dhcpc", NutDhcpClient, dev,
01887 (NUT_THREAD_DHCPSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD);
01888 }
01889 NutEventPost(&dhcpWake);
01890 NutEventWait(&dhcpDone, NUT_WAIT_INFINITE);
01891
01892 return 0;
01893 }
01894
01934 int NutDhcpIfConfig(CONST char *name, uint8_t * mac, uint32_t timeout)
01935 {
01936 uint8_t mac0[6];
01937 uint8_t macF[6];
01938 NUTDEVICE *dev;
01939 IFNET *nif;
01940
01941
01942
01943
01944 if ((dev = NutDeviceLookup(name)) == 0 ||
01945 dev->dev_type != IFTYP_NET ||
01946 (nif = dev->dev_icb) == 0 ||
01947 nif->if_type != IFT_ETHER) {
01948 dhcpError = DHCPERR_BADDEV;
01949 return -1;
01950 }
01951
01952
01953
01954
01955
01956 memset(mac0, 0x00, sizeof(mac0));
01957 memset(macF, 0xFF, sizeof(macF));
01958 if (memcmp(nif->if_mac, mac0, 6) == 0 || memcmp(nif->if_mac, macF, 6) == 0) {
01959
01960
01961
01962
01963 if (mac) {
01964 memcpy(confnet.cdn_mac, mac, sizeof(confnet.cdn_mac));
01965 }
01966
01967
01968
01969
01970
01971
01972
01973 else if (NutNetLoadConfig(name)) {
01974 dhcpError = DHCPERR_NOMAC;
01975 return -1;
01976 }
01977
01978
01979
01980
01981
01982 memcpy(nif->if_mac, confnet.cdn_mac, 6);
01983 NutSleep(500);
01984 }
01985
01986
01987
01988
01989 if ((confnet.cdn_cip_addr & confnet.cdn_ip_mask) != 0) {
01990 confnet.cdn_ip_addr = confnet.cdn_cip_addr;
01991 NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
01992 return 0;
01993 }
01994
01995
01996
01997
01998
01999
02000 if (DhcpKick(name, DHCPST_INIT, timeout) == 0) {
02001
02002
02003
02004
02005 if (dhcpState == DHCPST_BOUND) {
02006 #ifdef NUTDEBUG
02007 if (__tcp_trf) {
02008 fprintf(__tcp_trs, "[DHCP-Config %s]", inet_ntoa(dhcpConfig->dyn_yiaddr));
02009 }
02010 #endif
02011 NutNetIfSetup(dev, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_netmask, dhcpConfig->dyn_gateway);
02012 NutDnsConfig2(0, 0, dhcpConfig->dyn_pdns, dhcpConfig->dyn_sdns);
02013 return 0;
02014 }
02015
02016
02017
02018
02019
02020 if (nif->if_local_ip) {
02021 #ifdef NUTDEBUG
02022 if (__tcp_trf) {
02023 fprintf(__tcp_trs, "[DHCP-External %s]", inet_ntoa(nif->if_local_ip));
02024 }
02025 #endif
02026 return 0;
02027 }
02028
02029
02030
02031
02032
02033 if ((confnet.cdn_ip_addr & confnet.cdn_ip_mask) != 0) {
02034 #ifdef NUTDEBUG
02035 if (__tcp_trf) {
02036 fprintf(__tcp_trs, "[DHCP-Reusing %s]", inet_ntoa(confnet.cdn_ip_addr));
02037 }
02038 #endif
02039 NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
02040 return 0;
02041 }
02042 }
02043 return -1;
02044 }
02045
02062 int NutDhcpRelease(CONST char *name, uint32_t timeout)
02063 {
02064
02065 if (dhcpState != DHCPST_BOUND) {
02066 dhcpError = DHCPERR_STATE;
02067 return -1;
02068 }
02069
02070
02071 return DhcpKick(name, DHCPST_RELEASING, timeout);
02072 }
02073
02084 int NutDhcpInform(CONST char *name, uint32_t timeout)
02085 {
02086
02087 if (dhcpState != DHCPST_IDLE) {
02088 dhcpError = DHCPERR_STATE;
02089 return -1;
02090 }
02091
02092
02093 return DhcpKick(name, DHCPST_INFORMING, timeout);
02094 }
02095
02113 int NutDhcpStatus(CONST char *name)
02114 {
02115 return dhcpState;
02116 }
02117
02136 int NutDhcpError(CONST char *name)
02137 {
02138 int rc = dhcpError;
02139 dhcpError = 0;
02140 return rc;
02141 }
02142
02150 int NutDhcpIsConfigured(void)
02151 {
02152 return (dhcpState == DHCPST_BOUND);
02153 }
02154