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
00182 #include <sys/thread.h>
00183 #include <sys/event.h>
00184 #include <sys/timer.h>
00185 #include <sys/confnet.h>
00186 #include <sys/confos.h>
00187
00188 #include <stdlib.h>
00189 #include <string.h>
00190 #include <time.h>
00191
00192 #include <arpa/inet.h>
00193 #include <netinet/in.h>
00194 #include <netdb.h>
00195 #include <net/route.h>
00196 #include <sys/socket.h>
00197 #include <pro/dhcp.h>
00198
00199 #ifdef NUTDEBUG
00200 #include <net/netdebug.h>
00201 #endif
00202
00203 #if 0
00204
00205 #define NUTDEBUG
00206 #include <stdio.h>
00207 #define __tcp_trs stdout
00208 static u_char __tcp_trf = 1;
00209 #endif
00210
00215
00222
00228 #ifndef DHCP_SERVERPORT
00229 #define DHCP_SERVERPORT 67
00230 #endif
00231
00237 #ifndef DHCP_CLIENTPORT
00238 #define DHCP_CLIENTPORT 68
00239 #endif
00240
00250 #ifndef MAX_DHCP_MSGSIZE
00251 #define MAX_DHCP_MSGSIZE 576
00252 #endif
00253
00261 #ifndef MIN_DHCP_MSGSIZE
00262 #define MIN_DHCP_MSGSIZE 300
00263 #endif
00264
00280 #ifndef MAX_DHCP_BUFSIZE
00281 #define MAX_DHCP_BUFSIZE 1728
00282 #endif
00283
00293 #ifndef MIN_DHCP_WAIT
00294 #define MIN_DHCP_WAIT 4000
00295 #endif
00296
00305 #ifndef MAX_DHCP_WAIT
00306 #define MAX_DHCP_WAIT 64000
00307 #endif
00308
00317 #ifndef MAX_DCHP_RETRIES
00318 #define MAX_DCHP_RETRIES 3
00319 #endif
00320
00329 #ifndef MAX_DCHP_RELEASE_RETRIES
00330 #define MAX_DCHP_RELEASE_RETRIES 0
00331 #endif
00332
00340 #ifndef DHCP_DEFAULT_LEASE
00341 #define DHCP_DEFAULT_LEASE 43200
00342 #endif
00343
00349 #ifndef MAX_DHCP_NAPTIME
00350 #define MAX_DHCP_NAPTIME 4294967
00351 #endif
00352
00358 #ifndef NUT_THREAD_DHCPSTACK
00359 #define NUT_THREAD_DHCPSTACK 512
00360 #endif
00361
00370
00373 #define DHCP_DISCOVER 1
00374
00379 #define DHCP_OFFER 2
00380
00388 #define DHCP_REQUEST 3
00389
00394 #define DHCP_DECLINE 4
00395
00400 #define DHCP_ACK 5
00401
00406 #define DHCP_NAK 6
00407
00410 #define DHCP_RELEASE 7
00411
00416 #define DHCP_INFORM 8
00417
00427
00434 #define DHCPOPT_PAD 0
00435
00439 #define DHCPOPT_NETMASK 1
00440
00444 #define DHCPOPT_GATEWAY 3
00445
00449 #define DHCPOPT_DNS 6
00450
00454 #define DHCPOPT_HOSTNAME 12
00455
00459 #define DHCPOPT_DOMAIN 15
00460
00464 #define DHCPOPT_BROADCAST 28
00465
00469 #define DHCPOPT_REQESTIP 50
00470
00474 #define DHCPOPT_LEASETIME 51
00475
00479 #define DHCPOPT_MSGTYPE 53
00480
00484 #define DHCPOPT_SID 54
00485
00489 #define DHCPOPT_PARAMREQUEST 55
00490
00494 #define DHCPOPT_MAXMSGSIZE 57
00495
00499 #define DHCPOPT_RENEWALTIME 58
00500
00504 #define DHCPOPT_REBINDTIME 59
00505
00509 #define DHCPOPT_END 255
00510
00516 typedef struct __attribute__ ((packed)) bootp BOOTP;
00517
00521 struct __attribute__ ((packed)) bootp {
00522 u_char bp_op;
00523 u_char bp_htype;
00524 u_char bp_hlen;
00525 u_char bp_hops;
00526 u_long bp_xid;
00527 u_short bp_secs;
00528 u_short bp_flags;
00529 u_long bp_ciaddr;
00530 u_long bp_yiaddr;
00531 u_long bp_siaddr;
00532 u_long bp_giaddr;
00533 u_char bp_chaddr[16];
00534 char bp_sname[64];
00535 char bp_file[128];
00536 u_char bp_options[312];
00537 };
00538
00542 typedef struct dyn_cfg DYNCFG;
00543
00547 struct dyn_cfg {
00548 u_char dyn_msgtyp;
00549 u_long dyn_yiaddr;
00550 u_long dyn_netmask;
00551 u_long dyn_broadcast;
00552 u_long dyn_gateway;
00553 u_long dyn_pdns;
00554 u_long dyn_sdns;
00555 u_long dyn_sid;
00556 u_long dyn_renewalTime;
00557 u_long dyn_rebindTime;
00558 u_long dyn_leaseTime;
00559 u_char *dyn_hostname;
00560 u_char *dyn_domain;
00561 };
00562
00569 static DYNCFG *dhcpConfig;
00570
00577 static HANDLE dhcpThread;
00578
00582 static u_char dhcpState;
00583
00587 static int dhcpError;
00588
00594 static HANDLE dhcpWake;
00595
00601 static HANDLE dhcpDone;
00602
00608 static u_long dhcpApiTimeout;
00609
00616 static u_long dhcpApiStart;
00617
00624 #ifdef __arm__
00625 static NUTDEVICE *dhcpDev;
00626 #endif
00627
00639 static void copy_str(u_char ** dst, void *src, int len)
00640 {
00641 if (*dst) {
00642 free(*dst);
00643 }
00644 if ((*dst = malloc(len + 1)) != 0) {
00645 if (len) {
00646 memcpy(*dst, src, len);
00647 }
00648 *(*dst + len) = 0;
00649 }
00650 }
00651
00659 static void ReleaseDynCfg(DYNCFG * dyncfg)
00660 {
00661 if (dyncfg) {
00662 if (dyncfg->dyn_hostname) {
00663 free(dyncfg->dyn_hostname);
00664 }
00665 if (dyncfg->dyn_domain) {
00666 free(dyncfg->dyn_domain);
00667 }
00668 free(dyncfg);
00669 }
00670 }
00671
00683 static DYNCFG *ParseReply(BOOTP *bp, int len)
00684 {
00685 u_char *op;
00686 int left;
00687 DYNCFG *cfgp;
00688
00689
00690 if ((cfgp = malloc(sizeof(DYNCFG))) == 0) {
00691 return 0;
00692 }
00693 memset(cfgp, 0, sizeof(DYNCFG));
00694 cfgp->dyn_leaseTime = DHCP_DEFAULT_LEASE;
00695
00696
00697 memcpy(&cfgp->dyn_yiaddr, &bp->bp_yiaddr, 4);
00698
00699
00700
00701
00702
00703 op = bp->bp_options + 4;
00704 left = len - (sizeof(*bp) - sizeof(bp->bp_options)) - 4;
00705 while (*op != DHCPOPT_END && left > 0) {
00706 u_char ol;
00707
00708 #ifdef NUTDEBUG
00709 if (__tcp_trf) {
00710 fprintf(__tcp_trs, "[DHCP-Opt-%u]", *op);
00711 }
00712 #endif
00713
00714 if (*op == DHCPOPT_PAD) {
00715 op++;
00716 left--;
00717 continue;
00718 }
00719
00720
00721 if ((ol = *(op + 1)) > left) {
00722 break;
00723 }
00724
00725
00726 if (*op == DHCPOPT_MSGTYPE) {
00727 if (ol != 1) {
00728 break;
00729 }
00730 cfgp->dyn_msgtyp = *(op + 2);
00731 }
00732
00733 else if (*op == DHCPOPT_HOSTNAME) {
00734 copy_str(&cfgp->dyn_hostname, op + 2, ol);
00735 }
00736
00737 else if (*op == DHCPOPT_DOMAIN) {
00738 copy_str(&cfgp->dyn_domain, op + 2, ol);
00739 }
00740
00741
00742 else if (ol >= 4) {
00743
00744 u_long lval = *(op + 2);
00745 lval += (u_long)(*(op + 3)) << 8;
00746 lval += (u_long)(*(op + 4)) << 16;
00747 lval += (u_long)(*(op + 5)) << 24;
00748
00749
00750 if (*op == DHCPOPT_NETMASK) {
00751 cfgp->dyn_netmask = lval;
00752 }
00753
00754 else if (*op == DHCPOPT_BROADCAST) {
00755 cfgp->dyn_broadcast = lval;
00756 }
00757
00758
00759
00760 else if (*op == DHCPOPT_GATEWAY) {
00761 cfgp->dyn_gateway = lval;
00762 }
00763
00764
00765 else if (*op == DHCPOPT_DNS) {
00766 cfgp->dyn_pdns = lval;
00767 if (ol >= 8) {
00768 cfgp->dyn_sdns = *(op + 6);
00769 cfgp->dyn_sdns += (u_long)(*(op + 7)) << 8;
00770 cfgp->dyn_sdns += (u_long)(*(op + 8)) << 16;
00771 cfgp->dyn_sdns += (u_long)(*(op + 9)) << 24;
00772 }
00773 }
00774
00775 else if (*op == DHCPOPT_SID) {
00776 cfgp->dyn_sid = lval;
00777 }
00778
00779 else if (*op == DHCPOPT_RENEWALTIME) {
00780 cfgp->dyn_renewalTime = ntohl(lval);
00781 }
00782
00783 else if (*op == DHCPOPT_REBINDTIME) {
00784 cfgp->dyn_rebindTime = ntohl(lval);
00785 }
00786
00787 else if (*op == DHCPOPT_LEASETIME) {
00788 cfgp->dyn_leaseTime = ntohl(lval);
00789 }
00790 }
00791 op += ol + 2;
00792 left -= ol + 2;
00793 }
00794
00795
00796
00797
00798
00799 if (*op != DHCPOPT_END ||
00800 (cfgp->dyn_msgtyp != DHCP_OFFER &&
00801 cfgp->dyn_msgtyp != DHCP_ACK &&
00802 cfgp->dyn_msgtyp != DHCP_NAK)) {
00803 #ifdef NUTDEBUG
00804 if (__tcp_trf) {
00805 fprintf(__tcp_trs, "[DHCP-Parse Error]");
00806 }
00807 #endif
00808 ReleaseDynCfg(cfgp);
00809 return 0;
00810 }
00811
00812
00813 if (cfgp->dyn_renewalTime == 0) {
00814 cfgp->dyn_renewalTime = cfgp->dyn_leaseTime / 2;
00815 }
00816 if (cfgp->dyn_rebindTime == 0) {
00817 cfgp->dyn_rebindTime = cfgp->dyn_renewalTime +
00818 cfgp->dyn_renewalTime / 2 +
00819 cfgp->dyn_renewalTime / 4;
00820 }
00821 return cfgp;
00822 }
00823
00834 static size_t DhcpAddOption(u_char * op, u_char ot, void *ov, u_char len)
00835 {
00836 *op++ = ot;
00837 *op++ = len;
00838 memcpy(op, ov, len);
00839
00840 return 2 + len;
00841 }
00842
00852 static size_t DhcpAddByteOption(u_char * op, u_char ot, u_char ov)
00853 {
00854 *op++ = ot;
00855 *op++ = 1;
00856 *op++ = ov;
00857
00858 return 3;
00859 }
00860
00871 static size_t DhcpAddShortOption(u_char * op, u_char ot, u_short ov)
00872 {
00873 *op++ = ot;
00874 *op++ = 2;
00875 ov = htons(ov);
00876 memcpy(op, &ov, 2);
00877
00878 return 4;
00879 }
00880
00893 static size_t DhcpAddParmReqOption(u_char * op)
00894 {
00895 *op++ = DHCPOPT_PARAMREQUEST;
00896 *op++ = 3;
00897 *op++ = DHCPOPT_NETMASK;
00898 *op++ = DHCPOPT_GATEWAY;
00899 *op++ = DHCPOPT_DNS;
00900 return 5;
00901 }
00902
00924 static u_int DhcpPrepHeader(BOOTP *bp, u_char msgtyp, u_long xid, u_long ciaddr, u_short secs)
00925 {
00926 u_char *op;
00927
00928 memset(bp, 0, sizeof(*bp));
00929
00930 bp->bp_op = 1;
00931
00932 bp->bp_htype = 1;
00933 bp->bp_hlen = 6;
00934 memcpy(bp->bp_chaddr, confnet.cdn_mac, 6);
00935
00936 bp->bp_xid = xid;
00937
00938 bp->bp_secs = htons(secs);
00939
00940 #ifdef DHCP_BROADCAST_FLAG
00941
00942
00943
00944
00945
00946 bp->bp_flags = htons(0x8000);
00947 #endif
00948
00949 bp->bp_ciaddr = ciaddr;
00950
00951
00952 op = bp->bp_options;
00953 *op++ = 0x63;
00954 *op++ = 0x82;
00955 *op++ = 0x53;
00956 *op++ = 0x63;
00957
00958
00959 return DhcpAddByteOption(op, DHCPOPT_MSGTYPE, msgtyp) + 4;
00960 }
00961
00980 static int DhcpSendMessage(UDPSOCKET * sock, u_long addr, BOOTP *bp, size_t len)
00981 {
00982
00983 bp->bp_options[len++] = DHCPOPT_END;
00984
00985
00986
00987 if ((len += sizeof(BOOTP) - sizeof(bp->bp_options)) < MIN_DHCP_MSGSIZE) {
00988 len = MIN_DHCP_MSGSIZE;
00989 }
00990 #ifdef NUTDEBUG
00991 if (__tcp_trf) {
00992 fprintf(__tcp_trs, "[DHCP-Send to %s]", inet_ntoa(addr));
00993 }
00994 #endif
00995 if (NutUdpSendTo(sock, addr, DHCP_SERVERPORT, bp, len) < 0) {
00996 dhcpError = DHCPERR_TRANSMIT;
00997 return -1;
00998 }
00999 return 0;
01000 }
01001
01015 static int DhcpRecvMessage(UDPSOCKET * sock, u_long xid, BOOTP *bp, u_long tmo)
01016 {
01017 int rc;
01018 u_short port;
01019 u_long addr;
01020 u_long etim;
01021 u_long wtim;
01022
01023
01024 etim = NutGetMillis();
01025
01026 wtim = tmo;
01027 for (;;) {
01028 rc = NutUdpReceiveFrom(sock, &addr, &port, bp, sizeof(BOOTP), wtim);
01029 #ifdef NUTDEBUG
01030 if (__tcp_trf) {
01031 if (rc > 0) {
01032 fprintf(__tcp_trs, "[DHCP-Recv from %s]", inet_ntoa(addr));
01033 } else if (rc < 0) {
01034 fprintf(__tcp_trs, "[DHCP-Recv Error]");
01035 } else {
01036 fprintf(__tcp_trs, "[DHCP-Recv Timeout %lu]", tmo);
01037 }
01038 }
01039 #endif
01040
01041 if (rc <= 0) {
01042 if (rc < 0) {
01043 dhcpError = DHCPERR_RECEIVE;
01044 }
01045 break;
01046 }
01047
01048
01049 if (rc > sizeof(BOOTP) - sizeof(bp->bp_options) + 5) {
01050
01051 if (bp->bp_op == 2 && bp->bp_xid == xid) {
01052
01053 break;
01054 }
01055 }
01056
01057
01058 wtim = NutGetMillis() - etim;
01059 if (wtim >= tmo - 250) {
01060
01061 rc = 0;
01062 break;
01063 }
01064 wtim = tmo - wtim;
01065 }
01066 return rc;
01067 }
01068
01083 static int DhcpBroadcastDiscover(UDPSOCKET * sock, BOOTP *bp, u_long xid, u_long raddr, u_short secs)
01084 {
01085 size_t optlen;
01086 int len;
01087 u_char *op = bp->bp_options;
01088
01089 optlen = DhcpPrepHeader(bp, DHCP_DISCOVER, xid, 0, secs);
01090
01091
01092 if (raddr) {
01093 optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
01094 }
01095
01096 optlen += DhcpAddParmReqOption(op + optlen);
01097
01098
01099
01100
01101
01102 len = strlen(confos.hostname);
01103 if (len > 0) {
01104 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01105 }
01106
01107
01108 optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
01109
01110 return DhcpSendMessage(sock, INADDR_BROADCAST, bp, optlen);
01111 }
01112
01113
01133 static int DhcpSendRequest(UDPSOCKET * sock, u_long daddr, BOOTP *bp, u_long xid,
01134 u_long caddr, u_long raddr, u_long sid, u_short secs)
01135 {
01136 size_t optlen;
01137 int len;
01138 u_char *op = bp->bp_options;
01139
01140
01141 optlen = DhcpPrepHeader(bp, DHCP_REQUEST, xid, caddr, secs);
01142
01143
01144 if (raddr) {
01145 optlen += DhcpAddOption(op + optlen, DHCPOPT_REQESTIP, &raddr, sizeof(raddr));
01146 }
01147 if (sid) {
01148 optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
01149 }
01150 optlen += DhcpAddParmReqOption(op + optlen);
01151
01152
01153
01154 len = strlen(confos.hostname);
01155 if (len > 0) {
01156 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01157 }
01158
01159 return DhcpSendMessage(sock, daddr, bp, optlen);
01160 }
01161
01180 static int DhcpBroadcastRequest(UDPSOCKET * sock, BOOTP *bp, u_long xid,
01181 u_long caddr, u_long raddr, u_long sid, u_short secs)
01182 {
01183 return DhcpSendRequest(sock, INADDR_BROADCAST, bp, xid, caddr, raddr, sid, secs);
01184 }
01185
01201 static int DhcpSendRelease(UDPSOCKET * sock, u_long daddr, BOOTP *bp, u_long xid, u_long caddr, u_long sid)
01202 {
01203 size_t optlen;
01204 u_char *op = bp->bp_options;
01205
01206
01207 optlen = DhcpPrepHeader(bp, DHCP_RELEASE, xid, caddr, 0);
01208
01209
01210 if (sid) {
01211 optlen += DhcpAddOption(op + optlen, DHCPOPT_SID, &sid, sizeof(sid));
01212 }
01213 return DhcpSendMessage(sock, daddr, bp, optlen);
01214 }
01215
01228 static int DhcpSendInform(UDPSOCKET * sock, u_long daddr, BOOTP *bp, u_long xid, u_long caddr)
01229 {
01230 size_t optlen;
01231 size_t len;
01232 u_char *op = bp->bp_options;
01233
01234
01235 optlen = DhcpPrepHeader(bp, DHCP_INFORM, xid, caddr, 0);
01236
01237
01238 optlen += DhcpAddParmReqOption(op + optlen);
01239
01240
01241 len = strlen(confos.hostname);
01242 if (len > 0) {
01243 optlen += DhcpAddOption(op + optlen, DHCPOPT_HOSTNAME, confos.hostname, len);
01244 }
01245
01246
01247 optlen += DhcpAddShortOption(op + optlen, DHCPOPT_MAXMSGSIZE, MAX_DHCP_MSGSIZE);
01248
01249 return DhcpSendMessage(sock, daddr, bp, optlen);
01250 }
01251
01252
01263 static DYNCFG *CheckOffer(DYNCFG * dyncfg, BOOTP *bp, size_t len)
01264 {
01265 DYNCFG *offer;
01266
01267
01268
01269 if ((offer = ParseReply(bp, len)) == 0) {
01270 return dyncfg;
01271 }
01272
01273
01274 if (offer->dyn_msgtyp != DHCP_OFFER) {
01275 ReleaseDynCfg(offer);
01276 return dyncfg;
01277 }
01278
01279
01280 if (dyncfg == 0) {
01281 dyncfg = offer;
01282 }
01283
01284
01285
01286
01287 else {
01288
01289
01290
01291 if (confnet.cdn_ip_addr & confnet.cdn_ip_mask) {
01292 if (dyncfg->dyn_yiaddr != confnet.cdn_ip_addr &&
01293 offer->dyn_yiaddr == confnet.cdn_ip_addr) {
01294 ReleaseDynCfg(dyncfg);
01295 dyncfg = offer;
01296 }
01297 }
01298
01299 else if (offer->dyn_leaseTime > dyncfg->dyn_leaseTime) {
01300 ReleaseDynCfg(dyncfg);
01301 dyncfg = offer;
01302 }
01303
01304 else {
01305 ReleaseDynCfg(offer);
01306 }
01307 }
01308 return dyncfg;
01309 }
01310
01324 THREAD(NutDhcpClient, arg)
01325 {
01326 DYNCFG *reply = 0;
01327 UDPSOCKET *sock = 0;
01328 BOOTP *bp = 0;
01329 int n;
01330 u_long xid;
01331 IFNET *nif;
01332 u_short secs = 0;
01333 u_long aqsTime = NutGetSeconds();
01334 u_long leaseTime = 0;
01335 u_long napTime;
01336 ureg_t retries;
01337 u_long tmo = MIN_DHCP_WAIT;
01338 u_long last_ip = confnet.cdn_ip_addr;
01339 u_long server_ip;
01340
01341
01342
01343
01344
01345 #ifdef __arm__
01346 nif = dhcpDev->dev_icb;
01347 #else
01348 nif = ((NUTDEVICE *) arg)->dev_icb;
01349 #endif
01350
01351
01352
01353
01354
01355
01356
01357
01358 xid = 0;
01359 for (retries = 0; retries < sizeof(xid); retries++) {
01360 xid <<= 8;
01361 xid += nif->if_mac[5 - retries];
01362 }
01363 retries = 0;
01364
01365 for (;;) {
01366 #ifdef NUTDEBUG
01367 if (__tcp_trf) {
01368 fprintf(__tcp_trs, "\n[%u.DHCP-", retries + 1);
01369 switch (dhcpState) {
01370 case DHCPST_INIT:
01371 fprintf(__tcp_trs, "INIT]");
01372 break;
01373 case DHCPST_SELECTING:
01374 fprintf(__tcp_trs, "SELECTING]");
01375 break;
01376 case DHCPST_REQUESTING:
01377 fprintf(__tcp_trs, "REQUESTING]");
01378 break;
01379 case DHCPST_REBOOTING:
01380 fprintf(__tcp_trs, "REBOOTING %s]", inet_ntoa(last_ip));
01381 break;
01382 case DHCPST_BOUND:
01383 fprintf(__tcp_trs, "BOUND %lu]", NutGetSeconds() - leaseTime);
01384 break;
01385 case DHCPST_RENEWING:
01386 fprintf(__tcp_trs, "RENEWING %lu]", NutGetSeconds() - leaseTime);
01387 break;
01388 case DHCPST_REBINDING:
01389 fprintf(__tcp_trs, "REBINDING %lu]", NutGetSeconds() - leaseTime);
01390 break;
01391 case DHCPST_INFORMING:
01392 fprintf(__tcp_trs, "INFORMING]");
01393 break;
01394 case DHCPST_RELEASING:
01395 fprintf(__tcp_trs, "RELEASING]");
01396 break;
01397 case DHCPST_IDLE:
01398 if (dhcpError) {
01399 fprintf(__tcp_trs, "ERROR %u]", dhcpError);
01400 } else {
01401 fprintf(__tcp_trs, "IDLE]");
01402 }
01403 break;
01404 default:
01405 fprintf(__tcp_trs, "UNKNOWN %u]", dhcpState);
01406 break;
01407 }
01408 }
01409 #endif
01410
01411
01412
01413
01414 server_ip = INADDR_BROADCAST;
01415 if (retries) {
01416
01417 tmo += tmo;
01418 if (tmo > MAX_DHCP_WAIT) {
01419 tmo = MAX_DHCP_WAIT;
01420 }
01421 } else {
01422
01423 tmo = MIN_DHCP_WAIT;
01424
01425
01426
01427
01428 if (dhcpState != DHCPST_REQUESTING) {
01429 xid++;
01430 }
01431
01432
01433
01434 if (dhcpConfig && dhcpConfig->dyn_sid) {
01435 server_ip = dhcpConfig->dyn_sid;
01436 }
01437 }
01438
01439
01440
01441
01442 if (dhcpState != DHCPST_IDLE && dhcpApiTimeout != NUT_WAIT_INFINITE) {
01443 u_long tt = NutGetMillis() - dhcpApiStart;
01444
01445 if (dhcpApiTimeout <= tt) {
01446 dhcpError = DHCPERR_TIMEOUT;
01447 dhcpState = DHCPST_IDLE;
01448 continue;
01449 }
01450 if ((tt = dhcpApiTimeout - tt) < tmo) {
01451 tmo = tt;
01452 }
01453 }
01454
01455
01456
01457
01458 if (dhcpState == DHCPST_SELECTING || dhcpState == DHCPST_RENEWING || dhcpState == DHCPST_REBINDING) {
01459
01460 if (retries) {
01461 if (NutGetSeconds() - aqsTime > 0xffffUL) {
01462 secs = 0xffff;
01463 } else {
01464 secs = (u_short) (NutGetSeconds() - aqsTime);
01465 }
01466 }
01467
01468 else {
01469 aqsTime = NutGetSeconds();
01470 secs = 0;
01471 }
01472 }
01473
01474
01475
01476
01477 if (dhcpState == DHCPST_BOUND || dhcpState == DHCPST_IDLE) {
01478 if (sock) {
01479 NutUdpDestroySocket(sock);
01480 sock = 0;
01481 }
01482 if (bp) {
01483 free(bp);
01484 bp = 0;
01485 }
01486 }
01487
01488
01489
01490
01491 else {
01492
01493
01494
01495 if (dhcpConfig == 0 && nif->if_local_ip) {
01496
01497
01498 dhcpState = DHCPST_IDLE;
01499 continue;
01500 }
01501
01502 if (sock == 0 || bp == 0) {
01503 if (sock == 0) {
01504 sock = NutUdpCreateSocket(DHCP_CLIENTPORT);
01505 }
01506 if (bp == 0) {
01507 bp = malloc(sizeof(BOOTP));
01508 }
01509 if (sock == 0 || bp == 0) {
01510
01511 dhcpError = DHCPERR_SYSTEM;
01512 dhcpState = DHCPST_IDLE;
01513
01514
01515
01516 continue;
01517 }
01518 #if MAX_DHCP_BUFSIZE
01519 {
01520 u_short max_ms = MAX_DHCP_BUFSIZE;
01521 NutUdpSetSockOpt(sock, SO_RCVBUF, &max_ms, sizeof(max_ms));
01522 }
01523 #endif
01524 }
01525 }
01526
01527
01528
01529
01530 if (dhcpState == DHCPST_INIT) {
01531
01532 retries = 0;
01533
01534 xid++;
01535
01536 if ((last_ip & confnet.cdn_ip_mask) == 0) {
01537
01538 dhcpState = DHCPST_SELECTING;
01539 } else {
01540
01541
01542 dhcpState = DHCPST_REBOOTING;
01543 }
01544 }
01545
01546
01547
01548
01549 else if (dhcpState == DHCPST_SELECTING) {
01550 if (retries++ > MAX_DCHP_RETRIES) {
01551
01552 dhcpError = DHCPERR_TIMEOUT;
01553 dhcpState = DHCPST_IDLE;
01554 }
01555
01556 else if (DhcpBroadcastDiscover(sock, bp, xid, last_ip, secs) < 0) {
01557
01558 dhcpState = DHCPST_IDLE;
01559 } else {
01560
01561 while ((n = DhcpRecvMessage(sock, xid, bp, tmo)) > 0) {
01562
01563 if ((dhcpConfig = CheckOffer(dhcpConfig, bp, n)) != 0) {
01564
01565
01566 if (dhcpApiTimeout < MIN_DHCP_WAIT * 3) {
01567 break;
01568 }
01569
01570
01571 tmo = MIN_DHCP_WAIT;
01572 }
01573 }
01574
01575 if (n < 0) {
01576 dhcpState = DHCPST_IDLE;
01577 }
01578
01579
01580 else if (dhcpConfig) {
01581 retries = 0;
01582 dhcpState = DHCPST_REQUESTING;
01583 }
01584 }
01585 }
01586
01587
01588
01589
01590 else if (dhcpState == DHCPST_REQUESTING) {
01591 if (retries++ > MAX_DCHP_RETRIES) {
01592
01593 dhcpState = DHCPST_INIT;
01594 }
01595
01596
01597 else if (DhcpBroadcastRequest(sock, bp, xid, 0, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid, secs) < 0) {
01598
01599 dhcpState = DHCPST_IDLE;
01600 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01601
01602 dhcpState = DHCPST_IDLE;
01603 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01604
01605 if (reply->dyn_msgtyp == DHCP_ACK) {
01606 ReleaseDynCfg(dhcpConfig);
01607 dhcpConfig = reply;
01608 reply = 0;
01609 leaseTime = aqsTime;
01610 dhcpState = DHCPST_BOUND;
01611 }
01612
01613
01614 else if (reply->dyn_msgtyp == DHCP_NAK) {
01615 dhcpState = DHCPST_INIT;
01616 }
01617 }
01618 }
01619
01620
01621
01622
01623 else if (dhcpState == DHCPST_REBOOTING) {
01624 if (++retries > MAX_DCHP_RETRIES) {
01625
01626 last_ip = 0;
01627 dhcpState = DHCPST_INIT;
01628 }
01629
01630 else if (DhcpBroadcastRequest(sock, bp, xid, 0, last_ip, 0, secs) < 0) {
01631
01632 dhcpState = DHCPST_IDLE;
01633 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01634
01635 dhcpState = DHCPST_IDLE;
01636 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01637 if (reply->dyn_msgtyp == DHCP_ACK) {
01638 ReleaseDynCfg(dhcpConfig);
01639 dhcpConfig = reply;
01640 reply = 0;
01641 leaseTime = aqsTime;
01642 dhcpState = DHCPST_BOUND;
01643 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01644
01645
01646
01647 last_ip = 0;
01648 dhcpState = DHCPST_INIT;
01649 }
01650 }
01651 }
01652
01653
01654
01655
01656 else if (dhcpState == DHCPST_BOUND) {
01657 retries = 0;
01658 NutEventBroadcast(&dhcpDone);
01659 if (dhcpConfig->dyn_renewalTime <= NutGetSeconds() - leaseTime) {
01660 dhcpState = DHCPST_RENEWING;
01661 } else {
01662
01663 napTime = dhcpConfig->dyn_renewalTime - (NutGetSeconds() - leaseTime);
01664 if (napTime > MAX_DHCP_NAPTIME) {
01665 napTime = MAX_DHCP_NAPTIME;
01666 }
01667 NutEventWait(&dhcpWake, napTime * 1000UL);
01668 }
01669 }
01670
01671
01672
01673
01674 else if (dhcpState == DHCPST_RENEWING) {
01675 retries++;
01676 if (tmo / 1000 > dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime)) {
01677 tmo = dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime) * 1000;
01678 }
01679 if (dhcpConfig->dyn_rebindTime <= NutGetSeconds() - leaseTime) {
01680 retries = 0;
01681 dhcpState = DHCPST_REBINDING;
01682 }
01683
01684
01685 else if (DhcpSendRequest(sock, dhcpConfig->dyn_sid, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) <
01686 0) {
01687
01688 retries = 0;
01689 dhcpState = DHCPST_REBINDING;
01690 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01691
01692 dhcpState = DHCPST_IDLE;
01693 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01694 if (reply->dyn_msgtyp == DHCP_ACK) {
01695
01696 ReleaseDynCfg(dhcpConfig);
01697 dhcpConfig = reply;
01698 reply = 0;
01699 leaseTime = aqsTime;
01700 dhcpState = DHCPST_BOUND;
01701 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01702
01703 retries = 0;
01704 dhcpState = DHCPST_REBINDING;
01705 }
01706 }
01707 }
01708
01709
01710
01711
01712 else if (dhcpState == DHCPST_REBINDING) {
01713 retries++;
01714 if (tmo > dhcpConfig->dyn_rebindTime - (NutGetSeconds() - leaseTime)) {
01715 tmo = dhcpConfig->dyn_rebindTime - NutGetSeconds() - leaseTime;
01716 }
01717 if (dhcpConfig->dyn_rebindTime <= NutGetSeconds() - leaseTime) {
01718 retries = 0;
01719 dhcpState = DHCPST_REBINDING;
01720 }
01721
01722
01723 else if (DhcpBroadcastRequest(sock, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_yiaddr, 0, secs) < 0) {
01724
01725 dhcpState = DHCPST_IDLE;
01726 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01727
01728 dhcpState = DHCPST_IDLE;
01729 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01730 if (reply->dyn_msgtyp == DHCP_ACK) {
01731
01732 ReleaseDynCfg(dhcpConfig);
01733 dhcpConfig = reply;
01734 reply = 0;
01735 leaseTime = aqsTime;
01736 dhcpState = DHCPST_BOUND;
01737 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747 dhcpState = DHCPST_INIT;
01748 }
01749 }
01750 }
01751
01752
01753
01754
01755 else if (dhcpState == DHCPST_INFORMING) {
01756 if (retries++ > MAX_DCHP_RETRIES) {
01757 dhcpState = DHCPST_IDLE;
01758 } else if (DhcpSendInform(sock, server_ip, bp, xid, nif->if_local_ip) < 0) {
01759 if (server_ip == INADDR_BROADCAST) {
01760 dhcpState = DHCPST_IDLE;
01761 }
01762 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) != 0) {
01763 if (n > 0 &&
01764 (reply = ParseReply(bp, n)) != 0 &&
01765 reply->dyn_msgtyp == DHCP_ACK) {
01766
01767 ReleaseDynCfg(dhcpConfig);
01768 dhcpConfig = reply;
01769 reply = 0;
01770 }
01771 dhcpState = DHCPST_IDLE;
01772 }
01773 }
01774
01775
01776
01777
01778 else if (dhcpState == DHCPST_RELEASING) {
01779 if (dhcpConfig == 0 ||
01780 retries++ > MAX_DCHP_RELEASE_RETRIES ||
01781 DhcpSendRelease(sock, server_ip, bp, xid, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_sid) < 0) {
01782 if (server_ip == INADDR_BROADCAST) {
01783 dhcpState = DHCPST_IDLE;
01784 }
01785 } else if ((n = DhcpRecvMessage(sock, xid, bp, tmo)) < 0) {
01786
01787 dhcpState = DHCPST_IDLE;
01788 } else if (n > 0 && (reply = ParseReply(bp, n)) != 0) {
01789 if (reply->dyn_msgtyp == DHCP_ACK) {
01790 dhcpState = DHCPST_IDLE;
01791 } else if (reply->dyn_msgtyp == DHCP_NAK) {
01792 dhcpState = DHCPST_IDLE;
01793 }
01794 }
01795 }
01796
01797
01798
01799
01800
01801
01802
01803
01804 else if (dhcpState == DHCPST_IDLE) {
01805 ReleaseDynCfg(dhcpConfig);
01806 dhcpConfig = 0;
01807 retries = 0;
01808 NutEventBroadcast(&dhcpDone);
01809 NutEventWait(&dhcpWake, NUT_WAIT_INFINITE);
01810 }
01811
01812
01813 if (reply) {
01814 ReleaseDynCfg(reply);
01815 reply = 0;
01816 }
01817 }
01818 }
01819
01834 static int DhcpKick(CONST char *name, u_char state, u_long timeout)
01835 {
01836 NUTDEVICE *dev;
01837 IFNET *nif;
01838
01839
01840 if ((dev = NutDeviceLookup(name)) == 0 ||
01841 dev->dev_type != IFTYP_NET ||
01842 (nif = dev->dev_icb) == 0 ||
01843 nif->if_type != IFT_ETHER) {
01844 dhcpError = DHCPERR_BADDEV;
01845 return -1;
01846 }
01847
01848
01849 dhcpApiStart = NutGetMillis();
01850 dhcpApiTimeout = timeout;
01851
01852 dhcpState = state;
01853 if (dhcpThread == 0) {
01854 #ifdef __arm__
01855 dhcpDev = dev;
01856 #endif
01857 dhcpThread = NutThreadCreate("dhcpc", NutDhcpClient, dev, NUT_THREAD_DHCPSTACK);
01858 }
01859 NutEventPost(&dhcpWake);
01860 NutEventWait(&dhcpDone, NUT_WAIT_INFINITE);
01861
01862 return 0;
01863 }
01864
01904 int NutDhcpIfConfig(CONST char *name, u_char * mac, u_long timeout)
01905 {
01906 u_char mac0[6];
01907 u_char macF[6];
01908 NUTDEVICE *dev;
01909 IFNET *nif;
01910
01911
01912
01913
01914 if ((dev = NutDeviceLookup(name)) == 0 ||
01915 dev->dev_type != IFTYP_NET ||
01916 (nif = dev->dev_icb) == 0 ||
01917 nif->if_type != IFT_ETHER) {
01918 dhcpError = DHCPERR_BADDEV;
01919 return -1;
01920 }
01921
01922
01923
01924
01925
01926 memset(mac0, 0x00, sizeof(mac0));
01927 memset(macF, 0xFF, sizeof(macF));
01928 if (memcmp(nif->if_mac, mac0, 6) == 0 || memcmp(nif->if_mac, macF, 6) == 0) {
01929
01930
01931
01932
01933 if (mac) {
01934 memcpy(confnet.cdn_mac, mac, sizeof(confnet.cdn_mac));
01935 }
01936
01937
01938
01939
01940
01941
01942
01943 else if (NutNetLoadConfig(name)) {
01944 dhcpError = DHCPERR_NOMAC;
01945 return -1;
01946 }
01947
01948
01949
01950
01951
01952 memcpy(nif->if_mac, confnet.cdn_mac, 6);
01953 NutSleep(500);
01954 }
01955
01956
01957
01958
01959 if ((confnet.cdn_cip_addr & confnet.cdn_ip_mask) != 0) {
01960 confnet.cdn_ip_addr = confnet.cdn_cip_addr;
01961 NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
01962 return 0;
01963 }
01964
01965
01966
01967
01968
01969
01970 if (DhcpKick(name, DHCPST_INIT, timeout) == 0) {
01971
01972
01973
01974
01975 if (dhcpState == DHCPST_BOUND) {
01976 #ifdef NUTDEBUG
01977 if (__tcp_trf) {
01978 fprintf(__tcp_trs, "[DHCP-Config %s]", inet_ntoa(dhcpConfig->dyn_yiaddr));
01979 }
01980 #endif
01981 NutNetIfSetup(dev, dhcpConfig->dyn_yiaddr, dhcpConfig->dyn_netmask, dhcpConfig->dyn_gateway);
01982 NutDnsConfig2(0, 0, dhcpConfig->dyn_pdns, dhcpConfig->dyn_sdns);
01983 return 0;
01984 }
01985
01986
01987
01988
01989
01990 if (nif->if_local_ip) {
01991 #ifdef NUTDEBUG
01992 if (__tcp_trf) {
01993 fprintf(__tcp_trs, "[DHCP-External %s]", inet_ntoa(nif->if_local_ip));
01994 }
01995 #endif
01996 return 0;
01997 }
01998
01999
02000
02001
02002
02003 if ((confnet.cdn_ip_addr & confnet.cdn_ip_mask) != 0) {
02004 #ifdef NUTDEBUG
02005 if (__tcp_trf) {
02006 fprintf(__tcp_trs, "[DHCP-Reusing %s]", inet_ntoa(confnet.cdn_ip_addr));
02007 }
02008 #endif
02009 NutNetIfConfig2(name, confnet.cdn_mac, confnet.cdn_ip_addr, confnet.cdn_ip_mask, confnet.cdn_gateway);
02010 return 0;
02011 }
02012 }
02013 return -1;
02014 }
02015
02032 int NutDhcpRelease(CONST char *name, u_long timeout)
02033 {
02034
02035 if (dhcpState != DHCPST_BOUND) {
02036 dhcpError = DHCPERR_STATE;
02037 return -1;
02038 }
02039
02040
02041 return DhcpKick(name, DHCPST_RELEASING, timeout);
02042 }
02043
02054 int NutDhcpInform(CONST char *name, u_long timeout)
02055 {
02056
02057 if (dhcpState != DHCPST_IDLE) {
02058 dhcpError = DHCPERR_STATE;
02059 return -1;
02060 }
02061
02062
02063 return DhcpKick(name, DHCPST_INFORMING, timeout);
02064 }
02065
02083 int NutDhcpStatus(CONST char *name)
02084 {
02085 return dhcpState;
02086 }
02087
02106 int NutDhcpError(CONST char *name)
02107 {
02108 int rc = dhcpError;
02109 dhcpError = 0;
02110 return rc;
02111 }
02112
02120 int NutDhcpIsConfigured(void)
02121 {
02122 return (dhcpState == DHCPST_BOUND);
02123 }
02124