This is Webservice SDK for mbed. LPCXpresso1769/LPC1768/FRDM-K64F/LPC4088

Dependents:   MbedFileServer_1768MiniDK2 RedWireBridge IssueDebug_gcc MiMicRemoteMCU-for-Mbed ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers NyLPC_cDhcpClient.c Source File

NyLPC_cDhcpClient.c

00001 /*********************************************************************************
00002  * PROJECT: MiMic
00003  * --------------------------------------------------------------------------------
00004  *
00005  * This file is part of MiMic
00006  * Copyright (C)2011-2013 Ryo Iizuka
00007  *
00008  * MiMic is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU Lesser General Public License as published
00010  * by the Free Software Foundation, either version 3 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public License
00019  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00020  *
00021  * For further information please contact.
00022  *  http://nyatla.jp/
00023  *  <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
00024  *
00025  *********************************************************************************/
00026 #include "NyLPC_cDhcpClient.h"
00027 #include "../NyLPC_cNet.h"
00028 #include <stdio.h>
00029 #include <string.h>
00030 
00031 struct NyLPC_TDhcpHeader
00032 {
00033     NyLPC_TUInt8 op;
00034     NyLPC_TUInt8 htype;
00035     NyLPC_TUInt8 hlen;
00036     NyLPC_TUInt8 hops;
00037     NyLPC_TUInt32 xid;
00038     NyLPC_TUInt16 secs;
00039     NyLPC_TUInt16 flags;
00040     NyLPC_TUInt32 ciaddr;
00041     NyLPC_TUInt32 yiaddr;
00042     NyLPC_TUInt32 siaddr;
00043     NyLPC_TUInt32 giaddr;
00044     struct{
00045         struct NyLPC_TEthAddr emac;
00046         NyLPC_TChar padding[10];
00047     }chaddr;
00048     NyLPC_TChar sname[64];
00049     NyLPC_TChar file[128];
00050 }PACK_STRUCT_END;
00051 
00052 #define NyLPC_TDhcpHeader_BOOTREQUEST 1
00053 #define NyLPC_TDhcpHeader_BOOTREPLY   2
00054 
00055 #define DHCP_OPT_ID_ROUTER 3
00056 #define DHCP_OPT_ID_SERVER_ID 54
00057 #define DHCP_OPT_ID_NETMASK 1
00058 #define DHCP_OPT_ID_MESSAGETYPE 53
00059 
00060 
00061 
00062 /**
00063  * DHCPパケットから32bit値を読み出す。
00064  * @return
00065  * ネットワークオーダー
00066  */
00067 static NyLPC_TBool getUInt32Option(const NyLPC_TUInt8* i_buf,NyLPC_TUInt16 len,NyLPC_TUInt8 i_id,NyLPC_TUInt32* o_v)
00068 {
00069     const NyLPC_TUInt8* p=i_buf+sizeof(struct NyLPC_TDhcpHeader)+4;
00070     while(*p!=0x00 && p<(i_buf+len-5)){
00071         if(*p==i_id){
00072             if(*(p+1)==4){
00073                 *o_v=*((NyLPC_TUInt32*)(p+2));
00074                 return NyLPC_TBool_TRUE;
00075             }
00076         }else{
00077             p+=(*(p+1))+2;
00078         }
00079     }
00080     return NyLPC_TBool_FALSE;
00081 }
00082 static NyLPC_TBool getUInt8Option(const NyLPC_TUInt8* i_buf,NyLPC_TUInt16 len,NyLPC_TUInt8 i_id,NyLPC_TUInt8* o_v)
00083 {
00084     const NyLPC_TUInt8* p=i_buf+sizeof(struct NyLPC_TDhcpHeader)+4;
00085     while(*p!=0x00 && p<(i_buf+len-5)){
00086         if(*p==i_id){
00087             if(*(p+1)==1){
00088                 *o_v=*(p+2);
00089                 return NyLPC_TBool_TRUE;
00090             }
00091         }else{
00092             p+=(*(p+1))+2;
00093         }
00094     }
00095     return NyLPC_TBool_FALSE;
00096 }
00097 static NyLPC_TBool NyLPC_TDhcpHeader_parseDHCPOFFER(const NyLPC_TUInt8* i_buf,NyLPC_TUInt16 i_len,NyLPC_TUInt32 i_xid,NyLPC_TcDhcpClient_t* i_inst)
00098 {
00099     struct NyLPC_TDhcpHeader* p=(struct NyLPC_TDhcpHeader*)i_buf;
00100     //XIDのチェック
00101     if(p->xid!=NyLPC_HTONL(i_xid)){
00102         return NyLPC_TBool_FALSE;
00103     }
00104     //OFFERのclient IPアドレスをresultへ保存情報の保存
00105     i_inst->_result->ip_addr.v=p->yiaddr;
00106     //SERVER IDを保存
00107     if(!getUInt32Option(i_buf,i_len,DHCP_OPT_ID_SERVER_ID,&i_inst->_offerserver.v)){
00108         return NyLPC_TBool_FALSE;
00109     }
00110     return NyLPC_TBool_TRUE;
00111 }
00112 
00113 static NyLPC_TBool NyLPC_TDhcpHeader_parseDHCPACK(const NyLPC_TUInt8* i_buf,NyLPC_TUInt16 i_len,NyLPC_TUInt32 i_xid,NyLPC_TcIPv4Config_t* result)
00114 {
00115     struct NyLPC_TDhcpHeader* p=(struct NyLPC_TDhcpHeader*)i_buf;
00116     //XIDのチェック
00117     if(p->xid!=NyLPC_HTONL(i_xid)){
00118         return NyLPC_TBool_FALSE;
00119     }
00120     if(!getUInt32Option(i_buf,i_len,DHCP_OPT_ID_ROUTER,&result->dr_addr.v)){
00121         result->dr_addr=NyLPC_TIPv4Addr_ZERO;
00122     }
00123     if(!getUInt32Option(i_buf,i_len,DHCP_OPT_ID_NETMASK,&result->netmask.v)){
00124         result->netmask=NyLPC_TIPv4Addr_ZERO;
00125     }
00126     result->ip_addr.v=p->yiaddr;
00127     return NyLPC_TBool_TRUE;
00128 }
00129 
00130 static void NyLPC_TDhcpHeader_setDHCPDISCOVER(char* i_buf,NyLPC_TUInt32 i_xid,const struct NyLPC_TEthAddr* emac,NyLPC_TUInt16* o_len)
00131 {
00132     struct NyLPC_TDhcpHeader* p=(struct NyLPC_TDhcpHeader*)i_buf;
00133     memset(i_buf,0,sizeof(struct NyLPC_TDhcpHeader));
00134     p->op=NyLPC_TDhcpHeader_BOOTREQUEST;
00135     p->htype=1;
00136     p->hlen=6;
00137     p->xid=NyLPC_HTONL(i_xid);
00138     p->chaddr.emac=*emac;
00139     p->flags=NyLPC_HTONS(0x8000);
00140     memcpy(i_buf+sizeof(struct NyLPC_TDhcpHeader),
00141         "\x63\x82\x53\x63"      //4
00142         "\x35\x01\x01"          //3 MESSAGE TYPE
00143         "\x37\x03\x01\x03\x06"  //5 REQUEST LIST(1,3,6)
00144         "\x3d\x07\x01\x00\x00\x00\x00\x00\x00" //9 CLIENT INDIFIRE
00145         "\xff",4+3+5+9+1);
00146     //emacの上書き
00147     memcpy((i_buf+sizeof(struct NyLPC_TDhcpHeader)+4+3+5+3),emac->addr,6);
00148     //送信するパケットの長さ
00149     *o_len=sizeof(struct NyLPC_TDhcpHeader)+4+3+5+9+1;
00150     return;
00151 }
00152 static void NyLPC_TDhcpHeader_setDHCPREQUEST(char* i_buf,NyLPC_TUInt32 i_xid,const struct NyLPC_TIPv4Addr* i_sid,const struct NyLPC_TIPv4Addr* i_reqid,const struct NyLPC_TEthAddr* emac,NyLPC_TUInt16* o_len)
00153 {
00154     struct NyLPC_TDhcpHeader* p=(struct NyLPC_TDhcpHeader*)i_buf;
00155     memset(i_buf,0,sizeof(struct NyLPC_TDhcpHeader));
00156     p->op=NyLPC_TDhcpHeader_BOOTREQUEST;
00157     p->htype=1;
00158     p->hlen=6;
00159     p->xid=NyLPC_HTONL(i_xid);
00160     p->chaddr.emac=*emac;
00161     p->flags=NyLPC_HTONS(0x8000);
00162     memcpy(i_buf+sizeof(struct NyLPC_TDhcpHeader),
00163         "\x63\x82\x53\x63"      //4
00164         "\x35\x01\x03"          //3 MESSAGE TYPE
00165         "\x37\x03\x01\x03\x06"  //5 REQUEST LIST(1,3,6)
00166         "\x3d\x07\x01\x00\x00\x00\x00\x00\x00" //9 CLIENT INDIFIRE
00167         "\x36\x04\x00\x00\x00\x00" // 6 SERVER ID
00168         "\x32\x04\x00\x00\x00\x00" // 6 Reqested IP
00169         "\xff",4+3+5+9+6+6+1);
00170     //emacの上書き
00171     memcpy((i_buf+sizeof(struct NyLPC_TDhcpHeader)+4+3+5+3),emac->addr,6);
00172     //sidの上書き
00173     memcpy((i_buf+sizeof(struct NyLPC_TDhcpHeader)+4+3+5+9+2),i_sid,4);
00174     //reqidの上書き
00175     memcpy((i_buf+sizeof(struct NyLPC_TDhcpHeader)+4+3+5+9+6+2),i_reqid,4);
00176     //送信するパケットの長さ
00177     *o_len=sizeof(struct NyLPC_TDhcpHeader)+4+3+5+9+6+6+1;
00178     return;
00179 }
00180 
00181 
00182 
00183 #define TcDhcpSock_ST_WAIT_OFFER    1
00184 #define TcDhcpSock_ST_WAIT_OFFER_OK 2
00185 #define TcDhcpSock_ST_WAIT_ACK 3
00186 #define TcDhcpSock_ST_WAIT_ACK_OK 4
00187 #define TcDhcpSock_ST_DONE_NG 3
00188 #define TcDhcpSock_ST_DONE_OK 4
00189 
00190 
00191 
00192 
00193 #define DHCP_OPT_ID_MESSAGETYPE_ACK   5
00194 #define DHCP_OPT_ID_MESSAGETYPE_OFFER 2
00195 
00196 static NyLPC_TBool onPacket(NyLPC_TiUdpSocket_t* i_inst,const void* i_buf,const struct NyLPC_TIPv4RxInfo* i_info);
00197 
00198 /**
00199  * DHCPソケットを作成します。
00200  */
00201 NyLPC_TBool NyLPC_cDhcpClient_initialize(NyLPC_TcDhcpClient_t* i_inst)
00202 {
00203     i_inst->_socket=NyLPC_cNet_createUdpSocketEx(68,NyLPC_TSocketType_UDP_NOBUF);
00204     if(i_inst->_socket==NULL){
00205         return NyLPC_TBool_FALSE;
00206     }
00207     i_inst->_socket->_tag=i_inst;
00208     NyLPC_iUdpSocket_setBroadcast(i_inst->_socket);
00209     NyLPC_iUdpSocket_setOnRxHandler(i_inst->_socket,onPacket);
00210     return NyLPC_TBool_TRUE;
00211 }
00212 void NyLPC_cDhcpClient_finalize(NyLPC_TcDhcpClient_t* i_inst)
00213 {
00214     NyLPC_iUdpSocket_finalize(i_inst->_socket);
00215 }
00216 #define TIMEOUT_SOCKAPI_MS 1000
00217 #define TIMEOUT_RECVMSG_MS 3000
00218 
00219 /**
00220  * ネットワークを更新します。
00221  * emac/default_mssを設定したネットワークが必要です。
00222  */
00223 static NyLPC_TBool NyLPC_cDhcpClient_dhcpRequest(NyLPC_TcDhcpClient_t* i_inst,NyLPC_TcIPv4Config_t* i_result)
00224 {
00225     char* buf;
00226     NyLPC_TcStopwatch_t sw;
00227     NyLPC_TUInt16 s;
00228     NyLPC_TInt16 hint=sizeof(struct NyLPC_TDhcpHeader)+128;
00229     i_inst->txid+=(*(NyLPC_TUInt16*)(&(i_result->eth_mac.addr[2])))+(*(NyLPC_TUInt16*)(&(i_result->eth_mac.addr[4])));
00230     i_inst->_result=i_result;
00231     buf=NyLPC_iUdpSocket_allocSendBuf(i_inst->_socket,hint,&s,TIMEOUT_SOCKAPI_MS);
00232     if(buf==NULL || s<hint){
00233         return NyLPC_TBool_FALSE;
00234     }
00235     NyLPC_TDhcpHeader_setDHCPDISCOVER(buf,i_inst->txid,&i_inst->_result->eth_mac,&s);
00236     i_inst->_status=TcDhcpSock_ST_WAIT_OFFER;
00237     if(!NyLPC_iUdpSocket_psend(i_inst->_socket,&NyLPC_TIPv4Addr_BROADCAST,67,buf,s)){
00238         NyLPC_iUdpSocket_releaseSendBuf(i_inst->_socket,buf);
00239         return NyLPC_TBool_FALSE;
00240     }
00241     NyLPC_cStopwatch_initialize(&sw);
00242     NyLPC_cStopwatch_startExpire(&sw,TIMEOUT_RECVMSG_MS);
00243     while(i_inst->_status==TcDhcpSock_ST_WAIT_OFFER){
00244         if(NyLPC_cStopwatch_isExpired(&sw)){
00245             return NyLPC_TBool_FALSE;
00246         }
00247     }
00248     //レスポンスのチェック
00249     if(i_inst->_status!=TcDhcpSock_ST_WAIT_OFFER_OK)
00250     {
00251         return NyLPC_TBool_FALSE;
00252     }
00253     buf=NyLPC_iUdpSocket_allocSendBuf(i_inst->_socket,hint,&s,TIMEOUT_SOCKAPI_MS);
00254     if(buf==NULL || s<hint){
00255         return NyLPC_TBool_FALSE;
00256     }
00257     NyLPC_TDhcpHeader_setDHCPREQUEST(buf,i_inst->txid,&(i_inst->_offerserver),&(i_inst->_result->ip_addr),&i_inst->_result->eth_mac,&s);
00258     i_inst->_status=TcDhcpSock_ST_WAIT_ACK;
00259     if(!NyLPC_iUdpSocket_psend(i_inst->_socket,&NyLPC_TIPv4Addr_BROADCAST,67,buf,s)){
00260         NyLPC_iUdpSocket_releaseSendBuf(i_inst->_socket,buf);
00261         return NyLPC_TBool_FALSE;
00262     }
00263     NyLPC_cStopwatch_startExpire(&sw,TIMEOUT_RECVMSG_MS);
00264     while(i_inst->_status==TcDhcpSock_ST_WAIT_ACK){
00265         if(NyLPC_cStopwatch_isExpired(&sw)){
00266             return NyLPC_TBool_FALSE;
00267         }
00268     }
00269     //レスポンスのチェック
00270     if(i_inst->_status!=TcDhcpSock_ST_WAIT_ACK_OK)
00271     {
00272         return NyLPC_TBool_FALSE;
00273     }
00274     return NyLPC_TBool_TRUE;
00275 }
00276 
00277 /**
00278  * NyLPC_TcIPv4Config_tをDHCPで更新します。
00279  * この関数をコールする時は、サービスは停止中でなければなりません。
00280  * @param i_cfg
00281  * 更新するi_cfg構造体。
00282  * emac,default_mssは設定済である必要があります。他のフィールド値は不定で構いません。
00283  * 更新されるフィールドは、ip,netmast,default_rootの3つです。
00284  * @return
00285  * 更新に成功した場合TRUE
00286  */
00287 NyLPC_TBool NyLPC_cDhcpClient_requestAddr(NyLPC_TcDhcpClient_t* i_inst,NyLPC_TcIPv4Config_t* i_cfg,NyLPC_TInt16 i_repeat)
00288 {
00289     NyLPC_TInt16 i;
00290     NyLPC_TBool ret=NyLPC_TBool_FALSE;
00291     NyLPC_TcIPv4Config_t c2;
00292     //工場出荷時設定でリセットしてIPを0に
00293     NyLPC_cIPv4Config_initialzeCopy(&c2,i_cfg);
00294     NyLPC_cIPv4Config_setIp(&c2,&NyLPC_TIPv4Addr_ZERO,&NyLPC_TIPv4Addr_ZERO);
00295     NyLPC_cIPv4Config_setDefaultRoute(&c2,&NyLPC_TIPv4Addr_ZERO);
00296     //netを開始
00297     NyLPC_cNet_start(&c2);
00298     for(i=i_repeat-1;i>=0;i--){
00299         ret=NyLPC_cDhcpClient_dhcpRequest(i_inst,i_cfg);
00300         if(ret){
00301             break;
00302         }
00303     }
00304     NyLPC_cNet_stop();
00305     NyLPC_cIPv4Config_finalize(&c2);
00306     return ret;
00307 }
00308 
00309 
00310 
00311 static NyLPC_TBool onPacket(NyLPC_TiUdpSocket_t* i_inst,const void* i_buf,const struct NyLPC_TIPv4RxInfo* i_info)
00312 {
00313     NyLPC_TUInt8 mt;//message type
00314     NyLPC_TcDhcpClient_t* inst=(NyLPC_TcDhcpClient_t*)i_inst->_tag;
00315     struct NyLPC_TDhcpHeader* dnsh=(struct NyLPC_TDhcpHeader*)i_buf;
00316     if(i_info->size<sizeof(struct NyLPC_TDhcpHeader)+1){
00317         return NyLPC_TBool_FALSE;//DROP
00318     }
00319     switch(inst->_status)
00320     {
00321     case TcDhcpSock_ST_WAIT_ACK:
00322         if(dnsh->op!=NyLPC_TDhcpHeader_BOOTREPLY){
00323             return NyLPC_TBool_FALSE;
00324             }
00325         if(!getUInt8Option(i_buf,i_info->size,DHCP_OPT_ID_MESSAGETYPE,&mt)){
00326             return NyLPC_TBool_FALSE;
00327         }
00328         if(mt!=DHCP_OPT_ID_MESSAGETYPE_ACK){
00329             return NyLPC_TBool_FALSE;
00330         }
00331         if(!NyLPC_TDhcpHeader_parseDHCPACK(i_buf,i_info->size,inst->txid,inst->_result)){
00332             return NyLPC_TBool_FALSE;
00333         }
00334         inst->_status=TcDhcpSock_ST_WAIT_ACK_OK;
00335         break;
00336     case TcDhcpSock_ST_WAIT_OFFER:
00337         if(dnsh->op!=NyLPC_TDhcpHeader_BOOTREPLY){
00338             return NyLPC_TBool_FALSE;
00339             }
00340         if(!getUInt8Option(i_buf,i_info->size,DHCP_OPT_ID_MESSAGETYPE,&mt)){
00341             return NyLPC_TBool_FALSE;
00342         }
00343         if(mt!=DHCP_OPT_ID_MESSAGETYPE_OFFER){
00344             return NyLPC_TBool_FALSE;
00345         }
00346         if(!NyLPC_TDhcpHeader_parseDHCPOFFER(i_buf,i_info->size,inst->txid,inst)){
00347             return NyLPC_TBool_FALSE;
00348         }
00349         inst->_status=TcDhcpSock_ST_WAIT_OFFER_OK;
00350         break;
00351     }
00352     return NyLPC_TBool_FALSE;
00353 
00354 }