Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of libMiMic by
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 }
Generated on Tue Jul 12 2022 16:22:57 by
