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
00189 #include <sys/thread.h>
00190 #include <sys/event.h>
00191 #include <sys/timer.h>
00192 #include <sys/confnet.h>
00193 #include <sys/confos.h>
00194
00195 #include <stdlib.h>
00196 #include <string.h>
00197 #include <time.h>
00198
00199 #include <arpa/inet.h>
00200 #include <netinet/in.h>
00201 #include <netdb.h>
00202 #include <net/route.h>
00203 #include <sys/socket.h>
00204 #include <pro/dhcp.h>
00205
00206 #ifdef NUTDEBUG
00207 #include <net/netdebug.h>
00208 #endif
00209
00210 #if 0
00211
00212 #define NUTDEBUG
00213 #include <stdio.h>
00214 #define __tcp_trs stdout
00215 static uint_fast8_t __tcp_trf = 1;
00216 #endif
00217
00222
00229
00235 #ifndef DHCP_SERVERPORT
00236 #define DHCP_SERVERPORT 67
00237 #endif
00238
00244 #ifndef DHCP_CLIENTPORT
00245 #define DHCP_CLIENTPORT 68
00246 #endif
00247
00257 #ifndef MAX_DHCP_MSGSIZE
00258 #define MAX_DHCP_MSGSIZE 576
00259 #endif
00260
00268 #ifndef MIN_DHCP_MSGSIZE
00269 #define MIN_DHCP_MSGSIZE 300
00270 #endif
00271
00287 #ifndef MAX_DHCP_BUFSIZE
00288 #define MAX_DHCP_BUFSIZE 1728
00289 #endif
00290
00300 #ifndef MIN_DHCP_WAIT
00301 #define MIN_DHCP_WAIT 4000
00302 #endif
00303
00312 #ifndef MAX_DHCP_WAIT
00313 #define MAX_DHCP_WAIT 64000
00314 #endif
00315
00324 #ifndef MAX_DCHP_RETRIES
00325 #define MAX_DCHP_RETRIES 3
00326 #endif
00327
00336 #ifndef MAX_DCHP_RELEASE_RETRIES
00337 #define MAX_DCHP_RELEASE_RETRIES 0
00338 #endif
00339
00347 #ifndef DHCP_DEFAULT_LEASE
00348 #define DHCP_DEFAULT_LEASE 43200
00349 #endif
00350
00356 #ifndef MAX_DHCP_NAPTIME
00357 #define MAX_DHCP_NAPTIME 4294967
00358 #endif
00359
00365 #ifndef NUT_THREAD_DHCPSTACK
00366 #define NUT_THREAD_DHCPSTACK 512
00367 #endif
00368
00377
00380 #define DHCP_DISCOVER 1
00381
00386 #define DHCP_OFFER 2
00387
00395 #define DHCP_REQUEST 3
00396
00401 #define DHCP_DECLINE 4
00402
00407 #define DHCP_ACK 5
00408
00413 #define DHCP_NAK 6
00414
00417 #define DHCP_RELEASE 7
00418
00423 #define DHCP_INFORM 8
00424
00434
00441 #define DHCPOPT_PAD 0
00442
00446 #define DHCPOPT_NETMASK 1
00447
00451 #define DHCPOPT_GATEWAY 3
00452
00456 #define DHCPOPT_DNS 6
00457
00461 #define DHCPOPT_HOSTNAME 12
00462
00466 #define DHCPOPT_DOMAIN 15
00467
00471 #define DHCPOPT_BROADCAST 28
00472
00476 #define DHCPOPT_REQESTIP 50
00477
00481 #define DHCPOPT_LEASETIME 51
00482
00486 #define DHCPOPT_MSGTYPE 53
00487
00491 #define DHCPOPT_SID 54
00492
00496 #define DHCPOPT_PARAMREQUEST 55
00497
00501 #define DHCPOPT_MAXMSGSIZE 57
00502
00506 #define DHCPOPT_RENEWALTIME 58
00507
00511 #define DHCPOPT_REBINDTIME 59
00512
00516 #define DHCPOPT_END 255
00517
00523 typedef struct bootp BOOTP;
00524
00528 struct __attribute__ ((packed)) bootp {
00529 uint8_t bp_op;
00530 uint8_t bp_htype;
00531 uint8_t bp_hlen;
00532 uint8_t bp_hops;
00533 uint32_t bp_xid;
00534 uint16_t bp_secs;
00535 uint16_t bp_flags;
00536 uint32_t bp_ciaddr;
00537 uint32_t bp_yiaddr;
00538 uint32_t bp_siaddr;
00539 uint32_t bp_giaddr;
00540 uint8_t bp_chaddr[16];
00541 char bp_sname[64];
00542 char bp_file[128];
00543 uint8_t bp_options[312];
00544 };
00545
00549 typedef struct dyn_cfg DYNCFG;
00550
00554 struct dyn_cfg {
00555 uint8_t dyn_msgtyp;
00556 uint32_t dyn_yiaddr;
00557 uint32_t dyn_netmask;
00558 uint32_t dyn_broadcast;
00559 uint32_t dyn_gateway;
00560 uint32_t dyn_pdns;
00561 uint32_t dyn_sdns;
00562 uint32_t dyn_sid;
00563 uint32_t dyn_renewalTime;
00564 uint32_t dyn_rebindTime;
00565 uint32_t dyn_leaseTime;
00566 uint8_t *dyn_hostname;
00567 uint8_t *dyn_domain;
00568 };
00569
00576 static DYNCFG *dhcpConfig;
00577
00584 static HANDLE dhcpThread;
00585
00589 static uint8_t dhcpState;
00590
00594 static int dhcpError;
00595
00601 static HANDLE dhcpWake;
00602
00608 static HANDLE dhcpDone;
00609
00615 static uint32_t dhcpApiTimeout;
00616
00623 static uint32_t dhcpApiStart;
00624
00631 #ifdef __arm__
00632 static NUTDEVICE *dhcpDev;
00633 #endif
00634
00646 static void copy_str(uint8_t ** dst, void *src, int len)
00647 {
00648 if (*dst) {
00649 free(*dst);
00650 }
00651 if ((*dst = malloc(len + 1)) != 0) {
00652 if (len) {
00653 memcpy(*dst, src, len);
00654 }
00655 *(*dst + len) = 0;
00656 }
00657 }
00658
00666 static void ReleaseDynCfg(DYNCFG * dyncfg)
00667 {
00668 if (dyncfg) {
00669 if (dyncfg->dyn_hostname) {
00670 free(dyncfg->dyn_hostname);
00671 }
00672 if (dyncfg->dyn_domain) {
00673 free(dyncfg->dyn_domain);
00674 }
00675 free(dyncfg);
00676 }
00677 }
00678
00690 static DYNCFG *ParseReply(BOOTP *bp, int len)
00691 {
00692 uint8_t *op;
00693 int left;
00694 DYNCFG *cfgp;
00695
00696
00697 if ((cfgp = malloc(sizeof(DYNCFG))) == 0) {
00698 return 0;
00699 }
00700 memset(cfgp, 0, sizeof(DYNCFG));
00701 cfgp->dyn_leaseTime = DHCP_DEFAULT_LEASE;
00702
00703
00704 memcpy(&cfgp->dyn_yiaddr, &bp->bp_yiaddr, 4);
00705
00706
00707
00708
00709
00710 op = bp->bp_options + 4;
00711 left = len - (sizeof(*bp) - sizeof(bp->bp_options)) - 4;
00712 while (*op != DHCPOPT_END && left > 0) {
00713 uint8_t ol;
00714
00715 #ifdef NUTDEBUG
00716 if (__tcp_trf) {
00717 fprintf(__tcp_trs, "[DHCP-Opt-%u]", *op);
00718 }
00719 #endif
00720
00721 if (*op == DHCPOPT_PAD) {
00722 op++;
00723 left--;
00724 continue;
00725 }
00726
00727
00728 if ((ol = *(op + 1)) > left) {
00729 break;
00730 }
00731
00732
00733 if (*op == DHCPOPT_MSGTYPE) {
00734 if (ol != 1) {
00735 break;
00736 }
00737 cfgp->dyn_msgtyp = *(op + 2);
00738 }
00739
00740 else if (*op == DHCPOPT_HOSTNAME) {
00741 copy_str(&cfgp->dyn_hostname, op + 2, ol);
00742 }
00743
00744 else if (*op == DHCPOPT_DOMAIN) {
00745 copy_str(&cfgp->dyn_domain, op + 2, ol);
00746 }
00747
00748
00749 else if (ol >= 4) {
00750
00751 uint32_t lval = *(op + 2);
00752 lval += (uint32_t)(*(op + 3)) << 8;
00753 lval += (uint32_t)(*(op + 4)) << 16;
00754 lval += (uint32_t)(*(op + 5)) << 24;
00755
00756
00757 if (*op == DHCPOPT_NETMASK) {
00758 cfgp->dyn_netmask = lval;
00759 }
00760
00761 else if (*op == DHCPOPT_BROADCAST) {
00762 cfgp->dyn_broadcast = lval;
00763 }
00764
00765
00766
00767 else if (*op == DHCPOPT_GATEWAY) {
00768 cfgp->dyn_gateway = lval;
00769 }
00770
00771
00772 else if (*op == DHCPOPT_DNS) {
00773 cfgp->dyn_pdns = lval;
00774 if (ol >= 8) {
00775 cfgp->dyn_sdns = *(op + 6);
00776 cfgp->dyn_sdns += (uint32_t)(*(op + 7)) << 8;
00777 cfgp->dyn_sdns += (uint32_t)(*(op + 8)) << 16;
00778 cfgp->dyn_sdns += (uint32_t)(*(op + 9)) << 24;
00779 }
00780 }
00781
00782 else if (*op == DHCPOPT_SID) {
00783 cfgp->dyn_sid = lval;
00784 }
00785
00786 else if (*op == DHCPOPT_RENEWALTIME) {
00787 cfgp->dyn_renewalTime = ntohl(lval);
00788 }
00789
00790 else if (*op == DHCPOPT_REBINDTIME) {
00791 cfgp->dyn_rebindTime = ntohl(lval);
00792 }
00793
00794 else if (*op == DHCPOPT_LEASETIME) {
00795 cfgp->dyn_leaseTime = ntohl(lval);
00796 }
00797 }
00798 op += ol + 2;
00799 left -= ol + 2;
00800 }
00801
00802
00803
00804
00805
00806 if (*op != DHCPOPT_END ||
00807 (cfgp->dyn_msgtyp != DHCP_OFFER &&
00808 cfgp->dyn_msgtyp != DHCP_ACK &&
00809 cfgp->dyn_msgtyp != DHCP_NAK)) {
00810 #ifdef NUTDEBUG
00811 if (__tcp_trf) {
00812 fprintf(__tcp_trs, "[DHCP-Parse Error]");
00813 }
00814 #endif
00815 ReleaseDynCfg(cfgp);
00816 return 0;
00817 }
00818
00819
00820 if (cfgp->dyn_renewalTime == 0) {
00821 cfgp->dyn_renewalTime = cfgp->dyn_leaseTime / 2;
00822 }
00823 if (cfgp->dyn_rebindTime == 0) {
00824 cfgp->dyn_rebindTime = cfgp->dyn_renewalTime +
00825 cfgp->dyn_renewalTime / 2 +
00826 cfgp->dyn_renewalTime / 4;
00827 }
00828 return cfgp;
00829 }
00830
00841 static size_t DhcpAddOption(uint8_t * op, uint8_t ot, void *ov, uint8_t len)
00842 {
00843 *op++ = ot;
00844 *op++ = len;
00845 memcpy(op, ov, len);
00846
00847 return 2 + len;
00848 }
00849
00859 static size_t DhcpAddByteOption(uint8_t * op, uint8_t ot, uint8_t ov)
00860 {
00861 *op++ = ot;
00862 *op++ = 1;
00863 *op++ = ov;
00864
00865 return 3;
00866 }
00867
00878 static size_t DhcpAddShortOption(uint8_t * op, uint8_t ot, uint16_t ov)
00879 {
00880 *op++ = ot;
00881 *op++ = 2;
00882 ov = htons(ov);
00883 memcpy(op, &ov, 2);
00884
00885 return 4;
00886 }
00887
00900 static size_t DhcpAddParmReqOption(uint8_t * op)
00901 {
00902 *op++ = DHCPOPT_PARAMREQUEST;
00903 *op++ = 3;
00904 *op++ = DHCPOPT_NETMASK;
00905 *op++ = DHCPOPT_GATEWAY;
00906 *op++ = DHCPOPT_DNS;
00907 return 5;
00908 }
00909
00931 static u_int DhcpPrepHeader(BOOTP *bp, uint8_t msgtyp, uint32_t xid, uint32_t ciaddr, uint16_t secs)
00932 {
00933 uint8_t *op;
00934
00935 memset(bp, 0, sizeof(*bp));
00936
00937 bp->bp_op = 1;
00938
00939 bp->bp_htype = 1;
00940 bp->bp_hlen = 6;
00941 memcpy(bp->bp_chaddr, confnet.cdn_mac, 6);
00942
00943 bp->bp_xid = xid;
00944
00945 bp->bp_secs = htons(secs);
00946
00947 #ifdef DHCP_BROADCAST_FLAG
00948
00949
00950
00951
00952
00953 bp->bp_flags = htons(0x8000);
00954 #endif
00955
00956 bp->bp_ciaddr = ciaddr;
00957
00958
00959 op = bp->bp_options;
00960 *op++ = 0x63;
00961 *op++ = 0x82;
00962 *op++ = 0x53;
00963 *op++ = 0x63;
00964
00965
00966 return DhcpAddByteOption(op, DHCPOPT_MSGTYPE, msgtyp) + 4;
00967 }
00968
00987 static int DhcpSendMessage(UDPSOCKET * sock, uint32_t addr, BOOTP *bp, size_t len)
00988 {
00989
00990 bp->bp_options[len++] = DHCPOPT_END;
00991
00992
00993
00994 if ((len += sizeof(BOOTP) - sizeof(bp->bp_options)) < MIN_DHCP_MSGSIZE) {
00995 len = MIN_DHCP_MSGSIZE;
00996 }
00997 #ifdef NUTDEBUG
00998 if (__tcp_trf) {
00999 fprintf(__tcp_trs, "[DHCP-Send to %s]", inet_ntoa(addr));
01000 }
01001 #endif
01002 if (NutUdpSendTo(sock, addr, DHCP_SERVERPORT, bp, len) < 0) {
01003 dhcpError = DHCPERR_TRANSMIT;
01004 return -1;
01005 }
01006 return 0;
01007 }
01008
01022 static int DhcpRecvMessage(UDPSOCKET * sock, uint32_t xid, BOOTP *bp, uint32_t tmo)
01023 {
01024 int rc;
01025 uint16_t port;
01026 uint32_t addr;
01027 uint32_t etim;
01028 uint32_t wtim;
01029
01030
01031 etim = NutGetMillis();
01032
01033 wtim = tmo;
01034 for (;;) {
01035 rc = NutUdpReceiveFrom(sock, &addr, &port, bp, sizeof(BOOTP), wtim);
01036 #ifdef NUTDEBUG
01037 if (__tcp_trf) {
01038 if (rc > 0) {
01039 fprintf(__tcp_trs, "[DHCP-Recv from %s]", inet_ntoa(addr));
01040 } else if (rc < 0) {
01041 fprintf(__tcp_trs, "[DHCP-Recv Error]");
01042 } else {
01043 fprintf(__tcp_trs, "[DHCP-Recv Timeout %lu]", tmo);
01044 }
01045 }
01046 #endif
01047
01048 if (rc <= 0) {
01049 if (rc < 0) {
01050 dhcpError = DHCPERR_RECEIVE;
01051 }
01052 break;
01053 }
01054
01055
01056 if (rc > sizeof(BOOTP) - sizeof(bp->bp_options) + 5) {
01057
01058 if (bp->bp_op == 2 && bp->bp_xid == xid) {
01059
01060 break;
01061 }
01062 }
01063
01064
01065 wtim = NutGetMillis() - etim;
01066 if (wtim >= tmo - 250) {
01067
01068 rc = 0;
01069 break;
01070 }
01071 wtim = tmo - wtim;
01072 }
01073 return rc;
01074 }
01075
01090 static int DhcpBroadcastDiscover(UDPSOCKET * sock, BOOTP *bp, uint32_t xid, uint32_t raddr, uint16_t secs)
01091 {
01092 size_t optlen;
01093 int len;
01094 uint8_t *op = bp->bp_options;
01095
01096 optlen = DhcpPrepHeader(bp, DHCP_DISCOVER, xid, 0, secs);
01097
01098
01099 if (raddr) {
01100 optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
01101 }
01102
01103 optlen += DhcpAddParmReqOption(op + optlen);
01104
01105
01106
01107
01108
01109 len = strlen(confos.hostname);
01110 if (len > 0) {
01111 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01112 }
01113
01114
01115 optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
01116
01117 return DhcpSendMessage(sock, INADDR_BROADCAST, bp, optlen);
01118 }
01119
01120
01140 static int DhcpSendRequest(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid,
01141 uint32_t caddr, uint32_t raddr, uint32_t sid, uint16_t secs)
01142 {
01143 size_t optlen;
01144 int len;
01145 uint8_t *op = bp->bp_options;
01146
01147
01148 optlen = DhcpPrepHeader(bp, DHCP_REQUEST, xid, caddr, secs);
01149
01150
01151 if (raddr) {
01152 optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
01153 }
01154 if (sid) {
01155 optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
01156 }
01157 optlen += DhcpAddParmReqOption(op + optlen);
01158
01159
01160
01161 len = strlen(confos.hostname);
01162 if (len > 0) {
01163 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01164 }
01165
01166 return DhcpSendMessage(sock, daddr, bp, optlen);
01167 }
01168
01187 static int DhcpBroadcastRequest(UDPSOCKET * sock, BOOTP *bp, uint32_t xid,
01188 uint32_t caddr, uint32_t raddr, uint32_t sid, uint16_t secs)
01189 {
01190 return DhcpSendRequest(sock, INADDR_BROADCAST, bp, xid, caddr, raddr, sid, secs);
01191 }
01192
01208 static int DhcpSendRelease(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, uint32_t caddr, uint32_t sid)
01209 {
01210 size_t optlen;
01211 uint8_t *op = bp->bp_options;
01212
01213
01214 optlen = DhcpPrepHeader(bp, DHCP_RELEASE, xid, caddr, 0);
01215
01216
01217 if (sid) {
01218 optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
01219 }
01220 return DhcpSendMessage(sock, daddr, bp, optlen);
01221 }
01222
01235 static int DhcpSendInform(UDPSOCKET * sock, uint32_t daddr, BOOTP *bp, uint32_t xid, uint32_t caddr)
01236 {
01237 size_t optlen;
01238 size_t len;
01239 uint8_t *op = bp->bp_options;
01240
01241
01242 optlen = DhcpPrepHeader(bp, DHCP_INFORM, xid, caddr, 0);
01243
01244
01245 optlen += DhcpAddParmReqOption(op + optlen);
01246
01247
01248 len = strlen(confos.hostname);
01249 if (len > 0) {
01250 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01251 }
01252
01253
01254 optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
01255
01256 return DhcpSendMessage(sock, daddr, bp, optlen);
01257 }
01258
01259
01270 static DYNCFG *CheckOffer(DYNCFG * dyncfg, BOOTP *bp, size_t len)
01271 {
01272 DYNCFG *offer;
01273
01274
01275
01276 if ((offer = ParseReply(bp, len)) == 0) {
01277 return dyncfg;
01278 }
01279
01280
01281 if (offer->dyn_msgtyp != DHCP_OFFER) {
01282 ReleaseDynCfg(offer);
01283 return dyncfg;
01284 }
01285
01286
01287 if (dyncfg == 0) {
01288 dyncfg = offer;
01289 }
01290
01291
01292
01293
01294 else {
01295
01296
01297
01298 if (confnet.cdn_ip_addr & confnet.cdn_ip_mask) {
01299 if (dyncfg->dyn_yiaddr != confnet.cdn_ip_addr &&
01300 offer->dyn_yiaddr == confnet.cdn_ip_addr) {
01301 ReleaseDynCfg(dyncfg);
01302 dyncfg = offer;
01303 }
01304 }
01305
01306 else if (offer->dyn_leaseTime > dyncfg->dyn_leaseTime) {
01307 ReleaseDynCfg(dyncfg);
01308 dyncfg = offer;
01309 }
01310
01311 else {
01312 ReleaseDynCfg(offer);
01313 }
01314 }
01315 return dyncfg;
01316 }
01317
01331 THREAD(NutDhcpClient, arg)
01332 {
01333 DYNCFG *reply = 0;
01334 UDPSOCKET *sock = 0;
01335 BOOTP *bp = 0;
01336 int n;
01337 uint32_t xid;
01338 IFNET *nif;
01339 uint16_t secs = 0;
01340 uint32_t aqsTime = NutGetSeconds();
01341 uint32_t leaseTime = 0;
01342 uint32_t napTime;
01343 ureg_t retries;
01344 uint32_t tmo = MIN_DHCP_WAIT;
01345 uint32_t last_ip = confnet.cdn_ip_addr;
01346 uint32_t server_ip;
01347
01348
01349
01350
01351
01352 #ifdef __arm__
01353 nif = dhcpDev->dev_icb;
01354 #else
01355 nif = ((NUTDEVICE *) arg)->dev_icb;
01356 #endif
01357
01358
01359
01360
01361
01362
01363
01364
01365 xid = 0;
01366 for (retries = 0; retries < sizeof(xid); retries++) {
01367 xid <<= 8;
01368 xid += nif->if_mac[5 - retries];
01369 }
01370 retries = 0;
01371
01372 for (;;) {
01373 #ifdef NUTDEBUG
01374 if (__tcp_trf) {
01375 fprintf(__tcp_trs, "\n[%u.DHCP-", retries + 1);
01376 switch (dhcpState) {
01377 case DHCPST_INIT:
01378 fprintf(__tcp_trs, "INIT]");
01379 break;
01380 case DHCPST_SELECTING:
01381 fprintf(__tcp_trs, "SELECTING]");
01382 break;
01383 case DHCPST_REQUESTING:
01384 fprintf(__tcp_trs, "REQUESTING]");
01385 break;
01386 case DHCPST_REBOOTING:
01387 fprintf(__tcp_trs, "REBOOTING %s]", inet_ntoa(last_ip));
01388 break;
01389 case DHCPST_BOUND:
01390 fprintf(__tcp_trs, "BOUND %lu]", NutGetSeconds() - leaseTime);
01391 break;
01392 case DHCPST_RENEWING:
01393 fprintf(__tcp_trs, "RENEWING %lu]", NutGetSeconds() - leaseTime);
01394 break;
01395 case DHCPST_REBINDING:
01396 fprintf(__tcp_trs, "REBINDING %lu]", NutGetSeconds() - leaseTime);
01397 break;
01398 case DHCPST_INFORMING:
01399 fprintf(__tcp_trs, "INFORMING]");
01400 break;
01401 case DHCPST_RELEASING:
01402 fprintf(__tcp_trs, "RELEASING]");
01403 break;
01404 case DHCPST_IDLE:
01405 if (dhcpError) {
01406 fprintf(__tcp_trs, "ERROR %u]", dhcpError);
01407 } else {
01408 fprintf(__tcp_trs, "IDLE]");
01409 }
01410 break;
01411 default:
01412 fprintf(__tcp_trs, "UNKNOWN %u]", dhcpState);
01413 break;
01414 }
01415 }
01416 #endif
01417
01418
01419
01420
01421 server_ip = INADDR_BROADCAST;
01422 if (retries) {
01423
01424 tmo += tmo;
01425 if (tmo > MAX_DHCP_WAIT) {
01426 tmo = MAX_DHCP_WAIT;
01427 }
01428 } else {
01429
01430 tmo = MIN_DHCP_WAIT;
01431
01432
01433
01434
01435 if (dhcpState != DHCPST_REQUESTING) {
01436 xid++;
01437 }
01438
01439
01440
01441 if (dhcpConfig && dhcpConfig->dyn_sid) {
01442 server_ip = dhcpConfig->dyn_sid;
01443 }
01444 }
01445
01446
01447
01448
01449 if (dhcpState != DHCPST_IDLE && dhcpApiTimeout != NUT_WAIT_INFINITE) {
01450 uint32_t tt = NutGetMillis() - dhcpApiStart;
01451
01452 if (dhcpApiTimeout <= tt) {
01453 dhcpError = DHCPERR_TIMEOUT;
01454 dhcpState = DHCPST_IDLE;
01455 continue;
01456 }
01457 if ((tt = dhcpApiTimeout - tt) < tmo) {
01458 tmo = tt;
01459 }
01460 }
01461
01462
01463
01464
01465 if (dhcpState == DHCPST_SELECTING || dhcpState == DHCPST_RENEWING || dhcpState == DHCPST_REBINDING) {
01466
01467 if (retries) {
01468 if (NutGetSeconds() - aqsTime > 0xffffUL) {
01469 secs = 0xffff;
01470 } else {
01471 secs = (uint16_t) (NutGetSeconds() - aqsTime);
01472 }
01473 }
01474
01475 else {
01476 aqsTime = NutGetSeconds();
01477 secs = 0;
01478 }
01479 }
01480
01481
01482
01483
01484 if (dhcpState == DHCPST_BOUND || dhcpState == DHCPST_IDLE) {
01485 if (sock) {
01486 NutUdpDestroySocket(sock);
01487 sock = 0;
01488 }
01489 if (bp) {
01490 free(bp);
01491 bp = 0;
01492 }
01493 }
01494
01495
01496
01497
01498 else {
01499
01500
01501
01502 if (dhcpConfig == 0 && nif->if_local_ip) {
01503
01504
01505 dhcpState = DHCPST_IDLE;
01506 continue;
01507 }
01508
01509 if (sock == 0 || bp == 0) {
01510 if (sock == 0) {
01511 sock = NutUdpCreateSocket(DHCP_CLIENTPORT);
01512 }
01513 if (bp == 0) {
01514 bp = malloc(sizeof(BOOTP));
01515 }
01516 if (sock == 0 || bp == 0) {
01517
01518 dhcpError = DHCPERR_SYSTEM;
01519 dhcpState = DHCPST_IDLE;
01520
01521
01522
01523 continue;
01524 }
01525 #if MAX_DHCP_BUFSIZE
01526 {
01527 uint16_t max_ms = MAX_DHCP_BUFSIZE;
01528 NutUdpSetSockOpt(sock, SO_RCVBUF, &max_ms, sizeof(max_ms));
01529 }
01530 #endif
01531 }
01532 }
01533
01534
01535
01536
01537 if (dhcpState == DHCPST_INIT) {
01538
01539 retries = 0;
01540
01541 xid++;
01542
01543 if ((last_ip & confnet.cdn_ip_mask) == 0) {
01544
01545 dhcpState = DHCPST_SELECTING;
01546 } else {
01547
01548
01549 dhcpState = DHCPST_REBOOTING;
01550 }
01551 }
01552
01553
01554
01555
01556 else if (dhcpState == DHCPST_SELECTING) {
01557 if (retries++ > MAX_DCHP_RETRIES) {
01558
01559 dhcpError = DHCPERR_TIMEOUT;
01560 dhcpState = DHCPST_IDLE;
01561 }
01562
01563 else if (DhcpBroadcastDiscover(sock, bp, xid, last_ip, secs) < 0) {
01564
01565 dhcpState = DHCPST_IDLE;
01566 } else {
01567
01568 while ((n = DhcpRecvMessage(sock, xid, bp, tmo)) > 0) {
01569
01570 if ((dhcpConfig = CheckOffer(dhcpConfig, bp, n)) != 0) {
01571
01572
01573 if (dhcpApiTimeout < MIN_DHCP_WAIT * 3) {
01574 break;
01575 }
01576
01577
01578 tmo = MIN_DHCP_WAIT;
01579 }
01580 }
01581
01582 if (n < 0) {
01583 dhcpState = DHCPST_IDLE;
01584 }
01585
01586
01587 else if (dhcpConfig) {
01588 retries = 0;
01589 dhcpState = DHCPST_REQUESTING;
01590 }
01591 }
01592 }
01593
01594
01595
01596
01597 else if (dhcpState == DHCPST_REQUESTING) {
01598 if (retries++ > MAX_DCHP_RETRIES) {
01599
01600 dhcpState = DHCPST_INIT;
01601 }
01602
01603
01604 else if (DhcpBroadcastRequest(sock, bp, xid, 0, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid, secs) < 0) {
01605
01606 dhcpState = DHCPST_IDLE;
01607 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01608
01609 dhcpState = DHCPST_IDLE;
01610 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01611
01612 if (reply->dyn_msgtyp == DHCP_ACK) {
01613 ReleaseDynCfg(dhcpConfig);
01614 dhcpConfig = reply;
01615 reply = 0;
01616 leaseTime = aqsTime;
01617 dhcpState = DHCPST_BOUND;
01618 }
01619
01620
01621 else if (reply->dyn_msgtyp == DHCP_NAK) {
01622 dhcpState = DHCPST_INIT;
01623 }
01624 }
01625 }
01626
01627
01628
01629
01630 else if (dhcpState == DHCPST_REBOOTING) {
01631 if (++retries > MAX_DCHP_RETRIES) {
01632
01633 last_ip = 0;
01634 dhcpState = DHCPST_INIT;
01635 }
01636
01637 else if (DhcpBroadcastRequest(sock, bp, xid, 0, last_ip, 0, secs) < 0) {
01638
01639 dhcpState = DHCPST_IDLE;
01640 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01641
01642 dhcpState = DHCPST_IDLE;
01643 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01644 if (reply->dyn_msgtyp == DHCP_ACK) {
01645 ReleaseDynCfg(dhcpConfig);
01646 dhcpConfig = reply;
01647 reply = 0;
01648 leaseTime = aqsTime;
01649 dhcpState = DHCPST_BOUND;
01650 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01651
01652
01653
01654 last_ip = 0;
01655 dhcpState = DHCPST_INIT;
01656 }
01657 }
01658 }
01659
01660
01661
01662
01663 else if (dhcpState == DHCPST_BOUND) {
01664 retries = 0;
01665 NutEventBroadcast(&dhcpDone);
01666 if (dhcpConfig->dyn_renewalTime <= NutGetSeconds() - leaseTime) {
01667 dhcpState = DHCPST_RENEWING;
01668 } else {
01669
01670 napTime = dhcpConfig->dyn_renewalTime - (NutGetSeconds() - leaseTime);
01671 if (napTime > MAX_DHCP_NAPTIME) {
01672 napTime = MAX_DHCP_NAPTIME;
01673 }
01674 NutEventWait(&dhcpWake, napTime * 1000UL);
01675 }
01676 }
01677
01678
01679
01680
01681 else if (dhcpState == DHCPST_RENEWING) {
01682 retries++;
01683 if (tmo / 1000 > dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime)) {
01684 tmo = dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime) * 1000;
01685 }
01686 if (dhcpConfig->dyn_rebindTime <= NutGetSeconds() - leaseTime) {
01687 retries = 0;
01688 dhcpState = DHCPST_REBINDING;
01689 }
01690
01691
01692 else if (DhcpSendRequest(sock, dhcpConfig->dyn_sid, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) <
01693 0) {
01694
01695 retries = 0;
01696 dhcpState = DHCPST_REBINDING;
01697 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01698
01699 dhcpState = DHCPST_IDLE;
01700 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01701 if (reply->dyn_msgtyp == DHCP_ACK) {
01702
01703 ReleaseDynCfg(dhcpConfig);
01704 dhcpConfig = reply;
01705 reply = 0;
01706 leaseTime = aqsTime;
01707 dhcpState = DHCPST_BOUND;
01708 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01709
01710 retries = 0;
01711 dhcpState = DHCPST_REBINDING;
01712 }
01713 }
01714 }
01715
01716
01717
01718
01719 else if (dhcpState == DHCPST_REBINDING) {
01720 retries++;
01721 if (tmo > dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime)) {
01722 tmo = dhcpConfig->dyn_rebindTime - NutGetSeconds() - leaseTime;
01723 }
01724 if (dhcpConfig->dyn_rebindTime <= NutGetSeconds() - leaseTime) {
01725 retries = 0;
01726 dhcpState = DHCPST_REBINDING;
01727 }
01728
01729
01730 else if (DhcpBroadcastRequest(sock, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) < 0) {
01731
01732 dhcpState = DHCPST_IDLE;
01733 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01734
01735 dhcpState = DHCPST_IDLE;
01736 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01737 if (reply->dyn_msgtyp == DHCP_ACK) {
01738
01739 ReleaseDynCfg(dhcpConfig);
01740 dhcpConfig = reply;
01741 reply = 0;
01742 leaseTime = aqsTime;
01743 dhcpState = DHCPST_BOUND;
01744 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754 dhcpState = DHCPST_INIT;
01755 }
01756 }
01757 }
01758
01759
01760
01761
01762 else if (dhcpState == DHCPST_INFORMING) {
01763 if (retries++ > MAX_DCHP_RETRIES) {
01764 dhcpState = DHCPST_IDLE;
01765 } else if (DhcpSendInform(sock, server_ip, bp, xid, nif->if_local_ip) < 0) {
01766 if (server_ip == INADDR_BROADCAST) {
01767 dhcpState = DHCPST_IDLE;
01768 }
01769 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) != 0) {
01770 if (n > 0 &&
01771 (reply = ParseReply(bp, n)) != 0 &&
01772 reply->dyn_msgtyp == DHCP_ACK) {
01773
01774 ReleaseDynCfg(dhcpConfig);
01775 dhcpConfig = reply;
01776 reply = 0;
01777 }
01778 dhcpState = DHCPST_IDLE;
01779 }
01780 }
01781
01782
01783
01784
01785 else if (dhcpState == DHCPST_RELEASING) {
01786 if (dhcpConfig == 0 ||
01787 retries++ > MAX_DCHP_RELEASE_RETRIES ||
01788 DhcpSendRelease(sock, server_ip, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid) < 0) {
01789 if (server_ip == INADDR_BROADCAST) {
01790 dhcpState = DHCPST_IDLE;
01791 }
01792 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01793
01794 dhcpState = DHCPST_IDLE;
01795 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01796 if (reply->dyn_msgtyp == DHCP_ACK) {
01797 dhcpState = DHCPST_IDLE;
01798 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01799 dhcpState = DHCPST_IDLE;
01800 }
01801 }
01802 }
01803
01804
01805
01806
01807
01808
01809
01810
01811 else if (dhcpState == DHCPST_IDLE) {
01812 ReleaseDynCfg(dhcpConfig);
01813 dhcpConfig = 0;
01814 retries = 0;
01815 NutEventBroadcast(&dhcpDone);
01816 NutEventWait(&dhcpWake, NUT_WAIT_INFINITE);
01817 }
01818
01819
01820 if (reply) {
01821 ReleaseDynCfg(reply);
01822 reply = 0;
01823 }
01824 }
01825 }
01826
01841 static int DhcpKick(CONST char *name, uint8_t state, uint32_t timeout)
01842 {
01843 NUTDEVICE *dev;
01844 IFNET *nif;
01845
01846
01847 if ((dev = NutDeviceLookup(name)) == 0 ||
01848 dev->dev_type != IFTYP_NET ||
01849 (nif = dev->dev_icb) == 0 ||
01850 nif->if_type != IFT_ETHER) {
01851 dhcpError = DHCPERR_BADDEV;
01852 return -1;
01853 }
01854
01855
01856 dhcpApiStart = NutGetMillis();
01857 dhcpApiTimeout = timeout;
01858
01859 dhcpState = state;
01860 if (dhcpThread == 0) {
01861 #ifdef __arm__
01862 dhcpDev = dev;
01863 #endif
01864 dhcpThread = NutThreadCreate("dhcpc", NutDhcpClient, dev, NUT_THREAD_DHCPSTACK);
01865 }
01866 NutEventPost(&dhcpWake);
01867 NutEventWait(&dhcpDone, NUT_WAIT_INFINITE);
01868
01869 return 0;
01870 }
01871
01911 int NutDhcpIfConfig(CONST char *name, uint8_t * mac, uint32_t timeout)
01912 {
01913 uint8_t mac0[6];
01914 uint8_t macF[6];
01915 NUTDEVICE *dev;
01916 IFNET *nif;
01917
01918
01919
01920
01921 if ((dev = NutDeviceLookup(name)) == 0 ||
01922 dev->dev_type != IFTYP_NET ||
01923 (nif = dev->dev_icb) == 0 ||
01924 nif->if_type != IFT_ETHER) {
01925 dhcpError = DHCPERR_BADDEV;
01926 return -1;
01927 }
01928
01929
01930
01931
01932
01933 memset(mac0, 0x00, sizeof(mac0));
01934 memset(macF, 0xFF, sizeof(macF));
01935 if (memcmp(nif->if_mac, mac0, 6) == 0 || memcmp(nif->if_mac, macF, 6) == 0) {
01936
01937
01938
01939
01940 if (mac) {
01941 memcpy(confnet.cdn_mac, mac, sizeof(confnet.cdn_mac));
01942 }
01943
01944
01945
01946
01947
01948
01949
01950 else if (NutNetLoadConfig(name)) {
01951 dhcpError = DHCPERR_NOMAC;
01952 return -1;
01953 }
01954
01955
01956
01957
01958
01959 memcpy(nif->if_mac, confnet.cdn_mac, 6);
01960 NutSleep(500);
01961 }
01962
01963
01964
01965
01966 if ((confnet.cdn_cip_addr & confnet.cdn_ip_mask) != 0) {
01967 confnet.cdn_ip_addr = confnet.cdn_cip_addr;
01968 NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
01969 return 0;
01970 }
01971
01972
01973
01974
01975
01976
01977 if (DhcpKick(name, DHCPST_INIT, timeout) == 0) {
01978
01979
01980
01981
01982 if (dhcpState == DHCPST_BOUND) {
01983 #ifdef NUTDEBUG
01984 if (__tcp_trf) {
01985 fprintf(__tcp_trs, "[DHCP-Config %s]", inet_ntoa(dhcpConfig->dyn_yiaddr));
01986 }
01987 #endif
01988 NutNetIfSetup(dev, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_netmask, dhcpConfig->dyn_gateway);
01989 NutDnsConfig2(0, 0, dhcpConfig->dyn_pdns, dhcpConfig->dyn_sdns);
01990 return 0;
01991 }
01992
01993
01994
01995
01996
01997 if (nif->if_local_ip) {
01998 #ifdef NUTDEBUG
01999 if (__tcp_trf) {
02000 fprintf(__tcp_trs, "[DHCP-External %s]", inet_ntoa(nif->if_local_ip));
02001 }
02002 #endif
02003 return 0;
02004 }
02005
02006
02007
02008
02009
02010 if ((confnet.cdn_ip_addr & confnet.cdn_ip_mask) != 0) {
02011 #ifdef NUTDEBUG
02012 if (__tcp_trf) {
02013 fprintf(__tcp_trs, "[DHCP-Reusing %s]", inet_ntoa(confnet.cdn_ip_addr));
02014 }
02015 #endif
02016 NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
02017 return 0;
02018 }
02019 }
02020 return -1;
02021 }
02022
02039 int NutDhcpRelease(CONST char *name, uint32_t timeout)
02040 {
02041
02042 if (dhcpState != DHCPST_BOUND) {
02043 dhcpError = DHCPERR_STATE;
02044 return -1;
02045 }
02046
02047
02048 return DhcpKick(name, DHCPST_RELEASING, timeout);
02049 }
02050
02061 int NutDhcpInform(CONST char *name, uint32_t timeout)
02062 {
02063
02064 if (dhcpState != DHCPST_IDLE) {
02065 dhcpError = DHCPERR_STATE;
02066 return -1;
02067 }
02068
02069
02070 return DhcpKick(name, DHCPST_INFORMING, timeout);
02071 }
02072
02090 int NutDhcpStatus(CONST char *name)
02091 {
02092 return dhcpState;
02093 }
02094
02113 int NutDhcpError(CONST char *name)
02114 {
02115 int rc = dhcpError;
02116 dhcpError = 0;
02117 return rc;
02118 }
02119
02127 int NutDhcpIsConfigured(void)
02128 {
02129 return (dhcpState == DHCPST_BOUND);
02130 }
02131