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