| Line No. | Rev | Author | Line |
|---|---|---|---|
| 1 | 6 | kaklik | /*! \file dhcp.c \brief DHCP Protocol Library. */ |
| 2 | //***************************************************************************** |
||
| 3 | // |
||
| 4 | // File Name : 'dhcp.c' |
||
| 5 | // Title : DHCP Protocol Library |
||
| 6 | // Author : Pascal Stang |
||
| 7 | // Created : 9/17/2005 |
||
| 8 | // Revised : 9/17/2005 |
||
| 9 | // Version : 0.1 |
||
| 10 | // Target MCU : Atmel AVR series |
||
| 11 | // Editor Tabs : 4 |
||
| 12 | // |
||
| 13 | //***************************************************************************** |
||
| 14 | |||
| 15 | #include "global.h" |
||
| 16 | #include "net.h" |
||
| 17 | #include "nic.h" |
||
| 18 | #include "ip.h" |
||
| 19 | #include "netstack.h" |
||
| 20 | |||
| 21 | #include "dhcp.h" |
||
| 22 | |||
| 23 | #include "rprintf.h" |
||
| 24 | |||
| 25 | // global variables |
||
| 26 | uint32_t DhcpServerIP; ///< IP address of the DHCP server that offered lease |
||
| 27 | uint32_t DhcpTransactID; ///< Unique transaction ID that identifies DHCP request/replies |
||
| 28 | uint32_t DhcpLeaseTime; ///< Number of seconds left in DHCP lease |
||
| 29 | |||
| 30 | void dhcpInit(void) |
||
| 31 | { |
||
| 32 | uint8_t macaddr[6]; |
||
| 33 | |||
| 34 | // get interface mac address |
||
| 35 | nicGetMacAddress(macaddr); |
||
| 36 | // set transaction ID based on mac address |
||
| 37 | DhcpTransactID = *((uint32_t*)&macaddr); |
||
| 38 | // reset lease time |
||
| 39 | DhcpLeaseTime = 0; |
||
| 40 | } |
||
| 41 | |||
| 42 | void dhcpIn(unsigned int len, struct netDhcpHeader* packet) |
||
| 43 | { |
||
| 44 | uint8_t msgtype; |
||
| 45 | uint32_t sid; |
||
| 46 | uint8_t* optptr; |
||
| 47 | uint32_t val; |
||
| 48 | uint32_t netmask; |
||
| 49 | uint32_t gateway; |
||
| 50 | |||
| 51 | #if NET_DEBUG >= 3 |
||
| 52 | dhcpPrintHeader(packet); |
||
| 53 | #endif |
||
| 54 | |||
| 55 | // check that this is a reply, and for me |
||
| 56 | if((packet->bootp.op != BOOTP_OP_BOOTREPLY) || (packet->bootp.xid != DhcpTransactID)) |
||
| 57 | return; |
||
| 58 | |||
| 59 | // process incoming packet |
||
| 60 | // check reply type |
||
| 61 | dhcpGetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &msgtype); |
||
| 62 | #if NET_DEBUG >= 2 |
||
| 63 | rprintf("DHCP: Received msgtype = %d\r\n", msgtype); |
||
| 64 | #endif |
||
| 65 | |||
| 66 | if(msgtype == DHCP_MSG_DHCPOFFER) |
||
| 67 | { |
||
| 68 | // get DHCP server ID |
||
| 69 | dhcpGetOption(packet->options, DHCP_OPT_SERVERID, 4, &sid); |
||
| 70 | #ifdef DHCP_DEBUG |
||
| 71 | rprintfProgStrM("DHCP: Got offer from server "); netPrintIPAddr(htonl(sid)); rprintfCRLF(); |
||
| 72 | #endif |
||
| 73 | |||
| 74 | // build DHCP request (on top of this reply) |
||
| 75 | packet->bootp.op = BOOTP_OP_BOOTREQUEST; // request type |
||
| 76 | // set operation |
||
| 77 | val = DHCP_MSG_DHCPREQUEST; |
||
| 78 | optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val); |
||
| 79 | // set the server ID |
||
| 80 | optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &sid); |
||
| 81 | // request the IP previously offered |
||
| 82 | optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.yiaddr); |
||
| 83 | // request additional information |
||
| 84 | ((uint8_t*)&val)[0] = DHCP_OPT_NETMASK; |
||
| 85 | ((uint8_t*)&val)[1] = DHCP_OPT_ROUTERS; |
||
| 86 | ((uint8_t*)&val)[2] = DHCP_OPT_DNSSERVERS; |
||
| 87 | ((uint8_t*)&val)[3] = DHCP_OPT_DOMAINNAME; |
||
| 88 | optptr = dhcpSetOption(optptr, DHCP_OPT_PARAMREQLIST, 4, &val); |
||
| 89 | |||
| 90 | #ifdef DHCP_DEBUG |
||
| 91 | rprintfProgStrM("DHCP: Sending request in response to offer\r\n"); |
||
| 92 | #endif |
||
| 93 | // send DHCP request |
||
| 94 | DhcpServerIP = htonl(sid); |
||
| 95 | udpSend(DhcpServerIP, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+6+6+6+1, (uint8_t*)packet); |
||
| 96 | |||
| 97 | } |
||
| 98 | else if(msgtype == DHCP_MSG_DHCPACK) |
||
| 99 | { |
||
| 100 | // get netmask |
||
| 101 | dhcpGetOption(packet->options, DHCP_OPT_NETMASK, 4, &val); |
||
| 102 | netmask = htonl(val); |
||
| 103 | // get gateway |
||
| 104 | dhcpGetOption(packet->options, DHCP_OPT_ROUTERS, 4, &val); |
||
| 105 | gateway = htonl(val); |
||
| 106 | // get gateway |
||
| 107 | dhcpGetOption(packet->options, DHCP_OPT_LEASETIME, 4, &val); |
||
| 108 | DhcpLeaseTime = htonl(val); |
||
| 109 | |||
| 110 | // assign new network info |
||
| 111 | ipSetConfig(htonl(packet->bootp.yiaddr), netmask, gateway); |
||
| 112 | |||
| 113 | #ifdef DHCP_DEBUG |
||
| 114 | rprintf("DHCP: Got request ACK, bind complete\r\n"); |
||
| 115 | //debugPrintHexTable(len-DHCP_HEADER_LEN, (packet->options)); |
||
| 116 | // print info |
||
| 117 | ipPrintConfig(ipGetConfig()); |
||
| 118 | rprintfProgStrM("LeaseTm : "); rprintfNum(10,8,FALSE,' ',DhcpLeaseTime); rprintfCRLF(); |
||
| 119 | #endif |
||
| 120 | } |
||
| 121 | } |
||
| 122 | |||
| 123 | void dhcpRequest(void) |
||
| 124 | { |
||
| 125 | struct netDhcpHeader* packet; |
||
| 126 | uint32_t val; |
||
| 127 | |||
| 128 | packet = (struct netDhcpHeader*)&netstackGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN]; |
||
| 129 | |||
| 130 | // build BOOTP/DHCP header |
||
| 131 | packet->bootp.op = BOOTP_OP_BOOTREQUEST; // request type |
||
| 132 | packet->bootp.htype = BOOTP_HTYPE_ETHERNET; |
||
| 133 | packet->bootp.hlen = BOOTP_HLEN_ETHERNET; |
||
| 134 | packet->bootp.ciaddr = htonl(ipGetConfig()->ip); |
||
| 135 | packet->bootp.yiaddr = HTONL(0l); |
||
| 136 | packet->bootp.siaddr = HTONL(0l); |
||
| 137 | packet->bootp.giaddr = HTONL(0l); |
||
| 138 | nicGetMacAddress(&packet->bootp.chaddr[0]); // fill client hardware address |
||
| 139 | packet->bootp.xid = DhcpTransactID; |
||
| 140 | packet->bootp.flags = HTONS(1); |
||
| 141 | |||
| 142 | // build DHCP request |
||
| 143 | // begin with magic cookie |
||
| 144 | packet->cookie = 0x63538263; |
||
| 145 | // set operation |
||
| 146 | val = DHCP_MSG_DHCPDISCOVER; |
||
| 147 | dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val); |
||
| 148 | |||
| 149 | #ifdef DHCP_DEBUG |
||
| 150 | rprintfProgStrM("DHCP: Sending Query\r\n"); |
||
| 151 | //dhcpPrintHeader(packet); |
||
| 152 | #endif |
||
| 153 | |||
| 154 | // send request |
||
| 155 | udpSend(0xFFFFFFFF, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+1, (uint8_t*)packet); |
||
| 156 | } |
||
| 157 | |||
| 158 | void dhcpRelease(void) |
||
| 159 | { |
||
| 160 | struct netDhcpHeader* packet; |
||
| 161 | uint32_t val; |
||
| 162 | uint8_t* optptr; |
||
| 163 | |||
| 164 | packet = (struct netDhcpHeader*)&netstackGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN]; |
||
| 165 | |||
| 166 | // build BOOTP/DHCP header |
||
| 167 | packet->bootp.op = BOOTP_OP_BOOTREQUEST; // request type |
||
| 168 | packet->bootp.htype = BOOTP_HTYPE_ETHERNET; |
||
| 169 | packet->bootp.hlen = BOOTP_HLEN_ETHERNET; |
||
| 170 | packet->bootp.ciaddr = htonl(ipGetConfig()->ip); |
||
| 171 | packet->bootp.yiaddr = HTONL(0l); |
||
| 172 | packet->bootp.siaddr = HTONL(0l); |
||
| 173 | packet->bootp.giaddr = HTONL(0l); |
||
| 174 | nicGetMacAddress(&packet->bootp.chaddr[0]); // fill client hardware address |
||
| 175 | packet->bootp.xid = DhcpTransactID; // set trans ID (use part of MAC address) |
||
| 176 | packet->bootp.flags = HTONS(1); |
||
| 177 | |||
| 178 | // build DHCP request |
||
| 179 | // begin with magic cookie |
||
| 180 | packet->cookie = 0x63538263; |
||
| 181 | // set operation |
||
| 182 | val = DHCP_MSG_DHCPRELEASE; |
||
| 183 | optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val); |
||
| 184 | // set the server ID |
||
| 185 | val = htonl(DhcpServerIP); |
||
| 186 | optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &val); |
||
| 187 | // request the IP previously offered |
||
| 188 | optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.ciaddr); |
||
| 189 | |||
| 190 | #ifdef DHCP_DEBUG |
||
| 191 | rprintfProgStrM("DHCP: Sending Release to "); netPrintIPAddr(DhcpServerIP); rprintfCRLF(); |
||
| 192 | //dhcpPrintHeader(packet); |
||
| 193 | #endif |
||
| 194 | |||
| 195 | // send release |
||
| 196 | udpSend(DhcpServerIP, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+6+6+1, (uint8_t*)packet); |
||
| 197 | |||
| 198 | // deconfigure ip addressing |
||
| 199 | ipSetConfig(0,0,0); |
||
| 200 | DhcpLeaseTime = 0; |
||
| 201 | } |
||
| 202 | |||
| 203 | void dhcpTimer(void) |
||
| 204 | { |
||
| 205 | // this function to be called once per second |
||
| 206 | |||
| 207 | // decrement lease time |
||
| 208 | if(DhcpLeaseTime) |
||
| 209 | DhcpLeaseTime--; |
||
| 210 | } |
||
| 211 | |||
| 212 | uint8_t dhcpGetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, void* optvalptr) |
||
| 213 | { |
||
| 214 | uint8_t i; |
||
| 215 | |||
| 216 | // parse for desired option |
||
| 217 | for (;;) |
||
| 218 | { |
||
| 219 | // skip pad characters |
||
| 220 | if(*options == DHCP_OPT_PAD) |
||
| 221 | options++; |
||
| 222 | // break if end reached |
||
| 223 | else if(*options == DHCP_OPT_END) |
||
| 224 | break; |
||
| 225 | // check for desired option |
||
| 226 | else if(*options == optcode) |
||
| 227 | { |
||
| 228 | // found desired option |
||
| 229 | // limit size to actual option length |
||
| 230 | optlen = MIN(optlen, *(options+1)); |
||
| 231 | //if(*(options+1) < optlen) |
||
| 232 | // optlen = *(options+1); |
||
| 233 | |||
| 234 | // copy contents of option |
||
| 235 | for(i=0; i<optlen; i++) |
||
| 236 | *(((uint8_t*)optvalptr)+i) = *(options+i+2); |
||
| 237 | // return length of option |
||
| 238 | return *(options+1); |
||
| 239 | } |
||
| 240 | else |
||
| 241 | { |
||
| 242 | // skip to next option |
||
| 243 | options++; |
||
| 244 | options+=*options; |
||
| 245 | options++; |
||
| 246 | } |
||
| 247 | } |
||
| 248 | // failed to find desired option |
||
| 249 | return 0; |
||
| 250 | } |
||
| 251 | |||
| 252 | |||
| 253 | uint8_t* dhcpSetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, void* optvalptr) |
||
| 254 | { |
||
| 255 | // use current options address as write point |
||
| 256 | |||
| 257 | // set optcode |
||
| 258 | *options++ = optcode; |
||
| 259 | // set optlen |
||
| 260 | *options++ = optlen; |
||
| 261 | // copy in argument/data |
||
| 262 | while(optlen--) |
||
| 263 | { |
||
| 264 | *options++ = *(uint8_t*)optvalptr++; |
||
| 265 | } |
||
| 266 | // write end marker |
||
| 267 | *options = DHCP_OPT_END; |
||
| 268 | |||
| 269 | // return address of end marker, to be used as a future write point |
||
| 270 | return options; |
||
| 271 | } |
||
| 272 | |||
| 273 | |||
| 274 | #ifdef DHCP_DEBUG_PRINT |
||
| 275 | void dhcpPrintHeader(struct netDhcpHeader* packet) |
||
| 276 | { |
||
| 277 | rprintfProgStrM("DHCP Packet:\r\n"); |
||
| 278 | // print op |
||
| 279 | rprintfProgStrM("Op : "); |
||
| 280 | switch(packet->bootp.op) |
||
| 281 | { |
||
| 282 | case BOOTP_OP_BOOTREQUEST: rprintfProgStrM("BOOTREQUEST"); break; |
||
| 283 | case BOOTP_OP_BOOTREPLY: rprintfProgStrM("BOOTREPLY"); break; |
||
| 284 | default: rprintfProgStrM("UNKNOWN"); break; |
||
| 285 | } |
||
| 286 | rprintfCRLF(); |
||
| 287 | // print transaction ID |
||
| 288 | rprintfProgStrM("XID : 0x"); rprintfu32(packet->bootp.xid); rprintfCRLF(); |
||
| 289 | // print client IP address |
||
| 290 | rprintfProgStrM("ClIpAddr: "); netPrintIPAddr(htonl(packet->bootp.ciaddr)); rprintfCRLF(); |
||
| 291 | // print 'your' IP address |
||
| 292 | rprintfProgStrM("YrIpAddr: "); netPrintIPAddr(htonl(packet->bootp.yiaddr)); rprintfCRLF(); |
||
| 293 | // print server IP address |
||
| 294 | rprintfProgStrM("SvIpAddr: "); netPrintIPAddr(htonl(packet->bootp.siaddr)); rprintfCRLF(); |
||
| 295 | // print gateway IP address |
||
| 296 | rprintfProgStrM("GwIpAddr: "); netPrintIPAddr(htonl(packet->bootp.giaddr)); rprintfCRLF(); |
||
| 297 | // print client hardware address |
||
| 298 | rprintfProgStrM("ClHwAddr: "); netPrintEthAddr((struct netEthAddr*)packet->bootp.chaddr); rprintfCRLF(); |
||
| 299 | } |
||
| 300 | #endif |
Powered by WebSVN v2.8.3