Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | \ ========== Copyright Header Begin ========================================== |
2 | \ | |
3 | \ Hypervisor Software File: dhcp.fth | |
4 | \ | |
5 | \ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | \ | |
7 | \ - Do no alter or remove copyright notices | |
8 | \ | |
9 | \ - Redistribution and use of this software in source and binary forms, with | |
10 | \ or without modification, are permitted provided that the following | |
11 | \ conditions are met: | |
12 | \ | |
13 | \ - Redistribution of source code must retain the above copyright notice, | |
14 | \ this list of conditions and the following disclaimer. | |
15 | \ | |
16 | \ - Redistribution in binary form must reproduce the above copyright notice, | |
17 | \ this list of conditions and the following disclaimer in the | |
18 | \ documentation and/or other materials provided with the distribution. | |
19 | \ | |
20 | \ Neither the name of Sun Microsystems, Inc. or the names of contributors | |
21 | \ may be used to endorse or promote products derived from this software | |
22 | \ without specific prior written permission. | |
23 | \ | |
24 | \ This software is provided "AS IS," without a warranty of any kind. | |
25 | \ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
26 | \ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
27 | \ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
28 | \ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
29 | \ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
30 | \ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN | |
31 | \ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR | |
32 | \ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
33 | \ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
34 | \ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
35 | \ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
36 | \ | |
37 | \ You acknowledge that this software is not designed, licensed or | |
38 | \ intended for use in the design, construction, operation or maintenance of | |
39 | \ any nuclear facility. | |
40 | \ | |
41 | \ ========== Copyright Header End ============================================ | |
42 | id: @(#)dhcp.fth 1.7 02/11/27 | |
43 | purpose: | |
44 | copyright: Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved | |
45 | copyright: Use is subject to license terms. | |
46 | ||
47 | headerless | |
48 | ||
49 | \ Dynamic Host Configuration Protocol (DHCP) RFC 2131, RFC 2132 | |
50 | \ Bootstrap Protocol (BOOTP) RFC 951, RFC 1542 | |
51 | ||
52 | decimal | |
53 | struct ( bootp/dhcp packet ) | |
54 | 1 field >bp-op \ packet type: 1 = request, 2 = reply | |
55 | 1 field >bp-htype \ hardware addr type | |
56 | 1 field >bp-hlen \ hardware addr length | |
57 | 1 field >bp-hops \ gateway hops | |
58 | 4 field >bp-xid \ transaction ID | |
59 | 2 field >bp-secs \ seconds since boot began | |
60 | 2 field >bp-unused | |
61 | 4 field >bp-ciaddr \ client IP address | |
62 | 4 field >bp-yiaddr \ 'your' IP address | |
63 | 4 field >bp-siaddr \ server IP address | |
64 | 4 field >bp-giaddr \ gateway IP address | |
65 | 16 field >bp-chaddr \ client hardware address | |
66 | 64 field >bp-sname \ server host name | |
67 | 128 field >bp-file \ boot file name | |
68 | 4 field >bp-cookie \ Magic cookie | |
69 | 60 field >bp-options \ Can be longer, extending to end of packet | |
70 | constant /dhcp-packet | |
71 | ||
72 | : bp-op ( -- adr ) active-struct@ >bp-op ; | |
73 | : bp-htype ( -- adr ) active-struct@ >bp-htype ; | |
74 | : bp-hlen ( -- adr ) active-struct@ >bp-hlen ; | |
75 | : bp-hops ( -- adr ) active-struct@ >bp-hops ; | |
76 | : bp-xid ( -- adr ) active-struct@ >bp-xid ; | |
77 | : bp-secs ( -- adr ) active-struct@ >bp-secs ; | |
78 | : bp-ciaddr ( -- adr ) active-struct@ >bp-ciaddr ; | |
79 | : bp-yiaddr ( -- adr ) active-struct@ >bp-yiaddr ; | |
80 | : bp-siaddr ( -- adr ) active-struct@ >bp-siaddr ; | |
81 | : bp-giaddr ( -- adr ) active-struct@ >bp-giaddr ; | |
82 | : bp-chaddr ( -- adr ) active-struct@ >bp-chaddr ; | |
83 | : bp-sname ( -- adr ) active-struct@ >bp-sname ; | |
84 | : bp-file ( -- adr ) active-struct@ >bp-file ; | |
85 | : bp-cookie ( -- adr ) active-struct@ >bp-cookie ; | |
86 | : bp-options ( -- adr ) active-struct@ >bp-options ; | |
87 | ||
88 | 67 constant BOOTPS | |
89 | 68 constant BOOTPC | |
90 | ||
91 | 1 constant BOOTREQUEST | |
92 | 2 constant BOOTREPLY | |
93 | ||
94 | \ DHCP Message types | |
95 | 1 constant DHCPDISCOVER | |
96 | 2 constant DHCPOFFER | |
97 | 3 constant DHCPREQUEST | |
98 | 4 constant DHCPDECLINE | |
99 | 5 constant DHCPACK | |
100 | 6 constant DHCPNAK | |
101 | 7 constant DHCPRELEASE | |
102 | 8 constant DHCPINFORM | |
103 | ||
104 | \ DHCP State machine states | |
105 | 1 constant init-state | |
106 | 2 constant init-info-state | |
107 | 3 constant requesting-state | |
108 | 4 constant verify-state | |
109 | 5 constant configured-state | |
110 | ||
111 | instance variable dhcp-state | |
112 | ||
113 | \ Generic BOOTP/DHCP option structure | |
114 | struct ( bootp/dhcp-opt-header ) | |
115 | 1 field >op-code | |
116 | 1 field >op-len | |
117 | 0 field >op-data | |
118 | constant /dhcp-opt | |
119 | ||
120 | : op-code ( -- adr ) active-struct >op-code ; | |
121 | : op-len ( -- adr ) active-struct >op-len ; | |
122 | : op-data ( -- adr ) active-struct >op-data ; | |
123 | ||
124 | \ RFC 1048 magic cookie 99.130.83.99 | |
125 | h# 63.82.53.63 constant boot-magic | |
126 | ||
127 | \ Maximum possible size of BOOTP/DHCP packet | |
128 | d# 1472 constant /dhcp-maxmsg | |
129 | ||
130 | \ Base BOOTP/DHCP packet size - everything but the options, includes cookie | |
131 | d# 240 constant bootp-base-pkt-size | |
132 | ||
133 | instance variable xid | |
134 | ||
135 | instance variable dhcp-pkt-type | |
136 | instance variable offered-ip-addr | |
137 | instance variable dhcp-server-id | |
138 | ||
139 | instance variable max-dhcp-pkt-size | |
140 | instance variable dhcp-sndlen \ Actual length of packet to be sent | |
141 | ||
142 | -1 instance value dhcp-retries | |
143 | -1 instance value #max-retries | |
144 | ||
145 | : dhcp-msg ( adr len -- ) | |
146 | debug-dhcp? if type cr else 2drop then | |
147 | ; | |
148 | ||
149 | : too-many-boot-retries? ( -- flag ) | |
150 | #retries @ #max-retries u>= | |
151 | ; | |
152 | ||
153 | \ Construct class identifier from the root node's "name" | |
154 | \ property, replacing commas with periods | |
155 | d# 32 buffer: my-class-id | |
156 | : init-vend-class-id ( -- ) | |
157 | root-name$ ?dup if | |
158 | my-class-id pack count bounds | |
159 | do | |
160 | i c@ ascii , = if ascii . i c! then | |
161 | loop | |
162 | else | |
163 | drop | |
164 | then | |
165 | ; | |
166 | ||
167 | \ | |
168 | \ Construct client-identifier. This should be | |
169 | \ 1) The clientid option specified on command line, if any; or | |
170 | \ 2) the clientid options specified in "network-boot-args", if any; or | |
171 | \ 3) the root node "dhcp-clientid" property, if it exists. | |
172 | \ | |
173 | \ Only 3 is implemented currently. 1 and 2 are dependent upon | |
174 | \ wanboot which implements 1) revised parameter parsing | |
175 | \ and 2) "network-boot-args". | |
176 | \ | |
177 | d# 32 buffer: my-client-id | |
178 | : init-client-id ( -- ) | |
179 | 0 my-client-id c! | |
180 | dhcp-clientid-prop 0= if ( adr,len ) | |
181 | my-client-id pack drop ( ) | |
182 | then | |
183 | ; | |
184 | ||
185 | 0 instance value bootreply-len | |
186 | : store-bootreply ( -- ) | |
187 | *buffer @ /ether-header + /ip-header + /udp-header + | |
188 | bootreply-len ( bootreply-pkt-adr pkt-len ) | |
189 | dup to selected-reply-size ( bootreply-pkt-adr pkt-len ) | |
190 | selected-bootreply swap cmove ( ) | |
191 | ; | |
192 | ||
193 | d# 128 constant /options-max | |
194 | 0 value next-option | |
195 | ||
196 | : option, ( byte -- ) | |
197 | next-option bp-options + c! next-option 1+ to next-option | |
198 | ; | |
199 | ||
200 | : start-options | |
201 | bp-options /options-max erase 0 to next-option | |
202 | ; | |
203 | ||
204 | : add-option ( adr len code -- ) | |
205 | option, dup option, bounds ?do i c@ option, loop | |
206 | ; | |
207 | ||
208 | : finish-options | |
209 | d# 255 option, | |
210 | ; | |
211 | ||
212 | \ * DHCPDECLINE messages MUST NOT include | |
213 | \ - option 57 (Max DHCP msg size) | |
214 | \ - option 60 (Class identifier) | |
215 | \ * DHCPREQUESTs and DHCPDECLINEs fill | |
216 | \ - option 50 (Requested IP address) | |
217 | \ - option 54 (DHCP server identifier) | |
218 | \ identifying the offer being responded to | |
219 | \ * All client messages MAY include option 61 | |
220 | \ (client identifier) | |
221 | \ | |
222 | : set-dhcp-msg-type ( -- ) dhcp-pkt-type 1 d# 53 add-option ; | |
223 | : set-class-id ( -- ) my-class-id count d# 60 add-option ; | |
224 | : set-max-dhcp-pkt-sz ( -- ) max-dhcp-pkt-size 2 d# 57 add-option ; | |
225 | : set-offered-ipaddr ( -- ) offered-ip-addr 4 d# 50 add-option ; | |
226 | : set-dhcp-server-id ( -- ) dhcp-server-id 4 d# 54 add-option ; | |
227 | : set-req-params-list ( -- ) " "(01 03 0c 2b)" d# 55 add-option ; | |
228 | : set-client-id ( -- ) | |
229 | my-client-id count ?dup if | |
230 | d# 61 add-option | |
231 | else | |
232 | drop | |
233 | then | |
234 | ; | |
235 | ||
236 | : add-dhcp-options ( -- pktlen ) | |
237 | start-options ( ) | |
238 | set-dhcp-msg-type ( ) | |
239 | dhcp-pkt-type c@ DHCPDECLINE <> if ( ) | |
240 | set-class-id set-req-params-list set-max-dhcp-pkt-sz ( ) | |
241 | then ( ) | |
242 | dhcp-pkt-type c@ dup DHCPREQUEST = swap DHCPDECLINE = or if ( ) | |
243 | set-dhcp-server-id set-offered-ipaddr ( ) | |
244 | then ( ) | |
245 | set-client-id | |
246 | finish-options ( ) | |
247 | bootp-base-pkt-size next-option + ( pktlen ) | |
248 | ; | |
249 | ||
250 | : setup-dhcp-pkt ( pkt-type -- ) | |
251 | BOOTPC my-udp-port ! | |
252 | BOOTPS his-udp-port ! | |
253 | ( .. pkt-type ) dhcp-pkt-type c! | |
254 | ||
255 | packet-to-send active-struct ! | |
256 | packet-to-send /dhcp-maxmsg erase | |
257 | BOOTREQUEST bp-op c! | |
258 | 1 ( ARPHRD_ETHER ) bp-htype c! \ Hardware address type | |
259 | 6 bp-hlen c! \ Hardware address length | |
260 | xid @ bp-xid be-l! \ "Random" transaction ID | |
261 | my-ip-addr bp-ciaddr 4 cmove | |
262 | my-en-addr bp-chaddr 6 cmove | |
263 | boot-magic bp-cookie be-l! | |
264 | add-dhcp-options dhcp-sndlen ! | |
265 | ||
266 | broadcast-ip-addr his-ip-addr 4 cmove | |
267 | broadcast-en-addr his-en-addr 6 cmove | |
268 | ; | |
269 | ||
270 | : setup-discover-pkt ( -- ) DHCPDISCOVER setup-dhcp-pkt ; | |
271 | : setup-inform-pkt ( -- ) DHCPINFORM setup-dhcp-pkt ; | |
272 | : setup-decline-pkt ( -- ) DHCPDECLINE setup-dhcp-pkt ; | |
273 | : setup-request-pkt ( -- ) DHCPREQUEST setup-dhcp-pkt ; | |
274 | ||
275 | : boot-magic? ( -- flag ) | |
276 | bp-cookie be-l@ boot-magic = | |
277 | ; | |
278 | ||
279 | : c@++ ( adr -- adr+1 char ) dup ca1+ swap c@ ; | |
280 | ||
281 | \ A 256 element array, indexed by DHCP option number. Each element | |
282 | \ holds the pointer to "op-data". We interpret the options we are | |
283 | \ interested in. | |
284 | ||
285 | 0 instance value options | |
286 | ||
287 | : options-array ( index -- adr ) /n* options + ; | |
288 | ||
289 | \ Scan field for options | |
290 | : field-scan ( adr len -- ) | |
291 | over ca+ >r ( adr ) ( r: end ) | |
292 | begin | |
293 | dup r@ <= | |
294 | while | |
295 | c@++ case | |
296 | 0 of endof | |
297 | d# 255 of r> 2drop exit endof | |
298 | ( default ) | |
299 | >r c@++ over r> options-array ! ca+ 0 | |
300 | endcase | |
301 | repeat | |
302 | r> 2drop | |
303 | ; | |
304 | ||
305 | : option-overload-val ( -- val ) d# 52 options-array @ dup if c@ then ; | |
306 | ||
307 | \ Determine options specified in the BOOTP/DHCP packet. | |
308 | \ First scan the standard options fields. Then scan the specified additional | |
309 | \ fields if "option overload" is set. | |
310 | : scan-options ( bootreply-pkt-adr bootreply-len -- ) | |
311 | swap active-struct ! ( bootreply-len ) | |
312 | 0 options-array d# 256 /n* erase \ Havent read anything yet | |
313 | ||
314 | boot-magic? if ( bootreply-len ) | |
315 | ||
316 | \ Scan standard options fields | |
317 | bp-options swap bootp-base-pkt-size - field-scan | |
318 | ||
319 | \ Scan additional fields | |
320 | option-overload-val ?dup if | |
321 | ( option-overload-val ) case | |
322 | \ "bp-file" holds options | |
323 | 1 of bp-file d# 128 field-scan endof | |
324 | \ "bp-sname" holds options | |
325 | 2 of bp-sname d# 64 field-scan endof | |
326 | \ Both "bp-file" and "bp-sname" hold options | |
327 | 3 of bp-sname d# 192 field-scan endof | |
328 | endcase | |
329 | then | |
330 | ||
331 | else | |
332 | drop | |
333 | then | |
334 | ; | |
335 | ||
336 | : receive-bootreply ( -- flag ) \ True if bootreply received | |
337 | begin | |
338 | receive-udp-packet 0= if false exit then ( udp-adr udp-len ) | |
339 | swap active-struct ! ( udp-len ) | |
340 | udp-dest-port be-w@ BOOTPC <> ( udp-len flag ) | |
341 | /udp-header active-struct +! | |
342 | bp-xid be-l@ xid @ <> or ( udp-len flag' ) | |
343 | bp-op c@ BOOTREPLY <> or ( udp-len flag'' ) | |
344 | while | |
345 | drop | |
346 | repeat ( udp-len ) | |
347 | /udp-header - ( bootp-len ) | |
348 | dup to bootreply-len ( bootp-len ) | |
349 | active-struct @ swap ( bootreply-pkt bootreply-len ) | |
350 | scan-options | |
351 | true | |
352 | ; | |
353 | ||
354 | : bootreply-msg-type ( -- val ) d# 53 options-array @ dup if c@ then ; | |
355 | ||
356 | instance variable rn \ Random number | |
357 | instance variable dhcp-timeout-msecs | |
358 | ||
359 | \ Retransmission delay is doubled with each transmission upto a maximum | |
360 | \ of 64 seconds. Delay intervals are randomized by a period of +/- 1 second | |
361 | : get-dhcp-retrans-time ( -- n ) | |
362 | rn @ d# 199961 * d# 524287 + h# 7FFFFFFF and rn ! | |
363 | rn @ d# 1000 /mod 2 /mod drop if negate then | |
364 | dhcp-timeout-msecs @ + ( n ) | |
365 | dhcp-timeout-msecs @ d# 64000 < if | |
366 | dhcp-timeout-msecs dup @ 2* swap ! | |
367 | then | |
368 | ; | |
369 | ||
370 | : send-dhcp-pkt ( -- ) | |
371 | packet-to-send dhcp-sndlen @ /dhcp-packet max ( pkt len ) | |
372 | prepare-udp-packet ( len ) | |
373 | transmit drop ( ) | |
374 | get-dhcp-retrans-time set-timeout ( ) | |
375 | ; | |
376 | ||
377 | instance defer prepare-dhcp-pkt | |
378 | instance defer receive-dhcp-reply | |
379 | ||
380 | \ Basic DHCP packet exchange logic. | |
381 | : dhcpcom ( -- ok? ) | |
382 | prepare-dhcp-pkt | |
383 | #retries off | |
384 | begin | |
385 | send-dhcp-pkt | |
386 | receive-dhcp-reply | |
387 | ?dup 0= while | |
388 | 1 #retries +! | |
389 | ." Timeout waiting for BOOTP/DHCP reply. Retrying ... " cr | |
390 | too-many-boot-retries? if false exit then | |
391 | repeat | |
392 | ; | |
393 | ||
394 | \ Set "random" transaction ID and random number generator seed | |
395 | : init-dhcp-xid ( -- ) | |
396 | my-en-addr 5 + c@ get-msecs xor dup xid ! rn ! | |
397 | ; | |
398 | ||
399 | \ -------------------------- INIT state ------------------------------- | |
400 | ||
401 | false instance value bootp-config? | |
402 | ||
403 | 0 instance value best-offer-#points | |
404 | ||
405 | : compute-offer-points ( - #points ) | |
406 | 0 | |
407 | bootreply-msg-type if | |
408 | d# 30 + | |
409 | d# 43 options-array @ if d# 80 + then | |
410 | then | |
411 | boot-magic? if | |
412 | d# 5 + | |
413 | d# 1 options-array @ if d# 5 + then | |
414 | d# 3 options-array @ if d# 5 + then | |
415 | d# 12 options-array @ if d# 5 + then | |
416 | bp-siaddr broadcast-ip-addr? 0= if d# 10 + then | |
417 | d# 52 options-array @ 0= if | |
418 | bp-sname cstrlen 0<> if d# 10 + then | |
419 | bp-file cstrlen 0<> if d# 10 + then | |
420 | then | |
421 | then | |
422 | debug-dhcp? if | |
423 | ." This configuration has " dup .d ." points" cr | |
424 | then | |
425 | ; | |
426 | ||
427 | \ Accumulate replies from DHCP/BOOTP servers and pick the best offer. | |
428 | : get-best-offer ( -- flag ) | |
429 | 0 to best-offer-#points 0 to selected-reply-size | |
430 | begin | |
431 | timeout? 0= | |
432 | while | |
433 | receive-bootreply if | |
434 | compute-offer-points ( #pts ) | |
435 | dup best-offer-#points > if | |
436 | to best-offer-#points | |
437 | store-bootreply | |
438 | else drop | |
439 | then | |
440 | then | |
441 | repeat | |
442 | selected-reply-size if | |
443 | selected-bootreply selected-reply-size scan-options | |
444 | bootreply-msg-type DHCPOFFER <> to bootp-config? | |
445 | true | |
446 | else | |
447 | false | |
448 | then | |
449 | ; | |
450 | ||
451 | \ Decode contents of the selected BOOTP/DHCP reply. | |
452 | : process-offer ( -- ) | |
453 | selected-bootreply active-struct ! | |
454 | bootp-config? if | |
455 | \ Accepted BOOTP configuration. Read my IP address | |
456 | bp-yiaddr my-ip-addr 4 cmove | |
457 | else | |
458 | \ Received a DHCPOFFER. Record offered IP address and server identifier | |
459 | bp-yiaddr offered-ip-addr 4 cmove | |
460 | d# 54 options-array @ dhcp-server-id 4 cmove | |
461 | then | |
462 | ; | |
463 | ||
464 | \ Broadcast DHCPDISCOVER messages and wait for configuration parameters from | |
465 | \ a BOOTP/DHCP server. If a BOOTP configuration is selected, move to | |
466 | \ CONFIGURED state; else, go through other states of DHCP state machine | |
467 | : dhcp-init ( -- ) | |
468 | init-dhcp-xid | |
469 | " Requesting an IP address ... " dhcp-msg | |
470 | ['] setup-discover-pkt to prepare-dhcp-pkt | |
471 | ['] get-best-offer to receive-dhcp-reply | |
472 | d# 8000 dhcp-timeout-msecs ! | |
473 | dhcp-retries to #max-retries | |
474 | dhcpcom 0= if | |
475 | ." BOOTP/DHCP retry count exceeded" cr abort | |
476 | else | |
477 | process-offer | |
478 | bootp-config? if configured-state else requesting-state then | |
479 | dhcp-state ! | |
480 | then | |
481 | ; | |
482 | ||
483 | \ ------------------------------- INIT-INFO state --------------------------- | |
484 | ||
485 | : get-config-params ( -- rcvd? ) \ true if reply rcvd from BOOTP/DHCP server | |
486 | begin | |
487 | receive-bootreply 0= if false exit then | |
488 | bootreply-msg-type dup 0= swap DHCPACK = or ?dup | |
489 | until | |
490 | ; | |
491 | ||
492 | \ Broadcast DHCPINFORM and move to CONFIGURED state once a DHCPACK/BOOTREPLY | |
493 | \ is received. If no replies are received even after 4 tries, attempt to | |
494 | \ proceed further in the booting process. | |
495 | : dhcp-init-info ( -- ) | |
496 | init-dhcp-xid | |
497 | ['] setup-inform-pkt to prepare-dhcp-pkt | |
498 | ['] get-config-params to receive-dhcp-reply | |
499 | d# 4000 dhcp-timeout-msecs ! | |
500 | 4 to #max-retries | |
501 | dhcpcom 0= if | |
502 | ." Unable to receive config params " cr | |
503 | ." Attempting to boot anyway! ... " cr | |
504 | else | |
505 | store-bootreply | |
506 | then | |
507 | configured-state dhcp-state ! | |
508 | ; | |
509 | ||
510 | \ ---------------------------- REQUESTING state --------------------------- | |
511 | ||
512 | : get-ack/nak-pkt ( -- ack/nak-rcvd? ) | |
513 | begin | |
514 | receive-bootreply 0= if false exit then | |
515 | bootreply-msg-type dup DHCPACK = swap DHCPNAK = or ?dup | |
516 | until | |
517 | ; | |
518 | ||
519 | \ Broadcast DHCPREQUESTs and move to VERIFY state after a DHCPACK is | |
520 | \ received. If no reply is received even after 4 tries, or if a | |
521 | \ DHCPNAK is received, revert back to INIT state | |
522 | : dhcp-requesting ( -- ) | |
523 | " Requesting offered parameters ..." dhcp-msg | |
524 | ['] setup-request-pkt to prepare-dhcp-pkt | |
525 | ['] get-ack/nak-pkt to receive-dhcp-reply | |
526 | d# 4000 dhcp-timeout-msecs ! | |
527 | 4 to #max-retries | |
528 | dhcpcom 0= if | |
529 | ." Failed to receive config params" cr | |
530 | ." Restarting DHCP process ..." cr | |
531 | 10.000 ms \ Wait for 10 seconds | |
532 | init-state dhcp-state ! | |
533 | else | |
534 | bootreply-msg-type DHCPNAK = if | |
535 | ." Server unable to satisfy request" cr | |
536 | ." Restarting DHCP process ..." cr | |
537 | init-state dhcp-state ! | |
538 | else | |
539 | store-bootreply | |
540 | verify-state dhcp-state ! | |
541 | then | |
542 | then | |
543 | ; | |
544 | ||
545 | \ ------------------------ VERIFY state ---------------------------- | |
546 | ||
547 | \ Broadcast an ARP Reply announcing the IP address I am using and | |
548 | \ clear outdated ARP cache entries on other machines. | |
549 | : announce-my-addr ( -- ) | |
550 | my-ip-addr my-en-addr my-ip-addr my-en-addr ARP_REPLY ARP_TYPE | |
551 | send-arp/rarp-packet drop | |
552 | ; | |
553 | ||
554 | : decline-offer ( -- ) | |
555 | ['] setup-decline-pkt to prepare-dhcp-pkt | |
556 | ['] true to receive-dhcp-reply \ Dont wait for a reply | |
557 | dhcpcom drop | |
558 | ; | |
559 | ||
560 | : valid-ip-addr? ( -- valid? ) | |
561 | " Validating IP address ..." dhcp-msg | |
562 | offered-ip-addr broadcast-en-addr my-ip-addr my-en-addr ARP_REQ ARP_TYPE | |
563 | send-arp/rarp-packet drop | |
564 | arp-timeout-msecs set-timeout | |
565 | begin | |
566 | ARP_TYPE receive-ethernet-packet | |
567 | 0<> while ( adr len ) | |
568 | drop /ether-header + active-struct ! | |
569 | arp-tpa my-ip-addr ip= if \ Addressed to me | |
570 | arp-opcode be-w@ ARP_REPLY = if \ ARP reply | |
571 | debug-dhcp? if | |
572 | ." ARP Reply from: " arp-spa be-l@ .inetaddr | |
573 | arp-sha .enaddr cr | |
574 | then | |
575 | arp-spa offered-ip-addr ip= if | |
576 | false exit | |
577 | then | |
578 | then | |
579 | then | |
580 | repeat ( ) | |
581 | debug-dhcp? if ." No ARP Reply " cr then | |
582 | true | |
583 | ; | |
584 | ||
585 | \ Check if the offered IP address is already in use. If yes, decline | |
586 | \ this offer and start all over again | |
587 | : dhcp-verify ( -- ) | |
588 | valid-ip-addr? if | |
589 | " Address validation successful ..." dhcp-msg | |
590 | offered-ip-addr my-ip-addr 4 cmove | |
591 | announce-my-addr | |
592 | configured-state dhcp-state ! | |
593 | else | |
594 | ." IP address already in use by another client!" cr | |
595 | decline-offer | |
596 | ." Restarting DHCP ..." cr | |
597 | 10.000 ms \ Wait for 10 seconds | |
598 | init-state dhcp-state ! | |
599 | then | |
600 | ; | |
601 | ||
602 | \ -------------------------------------------------------------------- | |
603 | ||
604 | \ Navigate through DHCP state machine till state = CONFIGURED | |
605 | : try-dhcp ( -- ) | |
606 | \ Initialize DHCP client state | |
607 | my-ip-addr l@ 0= if init-state else init-info-state then dhcp-state ! | |
608 | ||
609 | begin | |
610 | dhcp-state @ case | |
611 | init-state of dhcp-init endof | |
612 | init-info-state of dhcp-init-info endof | |
613 | requesting-state of dhcp-requesting endof | |
614 | verify-state of dhcp-verify endof | |
615 | configured-state of exit endof | |
616 | endcase | |
617 | again | |
618 | ; | |
619 | ||
620 | \ Initialize network configuration parameters. Read subnet mask, | |
621 | \ TFTP server and router's IP addresses and bootfilename, if they | |
622 | \ haven't been specified as cmd line arguments, from the | |
623 | \ selected bootreply. | |
624 | : init-config-params ( -- ) | |
625 | selected-bootreply selected-reply-size scan-options | |
626 | subnet-mask broadcast-ip-addr? if | |
627 | d# 1 options-array @ ?dup if subnet-mask 4 cmove then | |
628 | then | |
629 | router-ip-addr broadcast-ip-addr? if | |
630 | d# 3 options-array @ ?dup if router-ip-addr 4 cmove then | |
631 | then | |
632 | server-ip-addr broadcast-ip-addr? if | |
633 | bp-siaddr server-ip-addr 4 cmove | |
634 | then | |
635 | tftp-file cstrlen 0= if | |
636 | \ Read bootfilename from BOOTP/DHCP header OR from the | |
637 | \ "bootfile name" option if "option overload" is specified | |
638 | option-overload-val if | |
639 | d# 67 options-array @ ?dup if | |
640 | dup cstrlen tftp-file-buf pack drop | |
641 | then | |
642 | else | |
643 | bp-file dup cstrlen tftp-file-buf pack drop | |
644 | then | |
645 | then | |
646 | ; | |
647 | ||
648 | : init-dhcp ( -- ) | |
649 | /dhcp-maxmsg alloc-mem to packet-to-send | |
650 | /udp-pseudo-hdr alloc-mem is udp-pseudo-hdr | |
651 | d# 256 /n * alloc-mem is options | |
652 | ||
653 | d# 1514 alloc-mem to selected-bootreply | |
654 | selected-bootreply d# 1514 erase | |
655 | ||
656 | /dhcp-maxmsg max-dhcp-pkt-size be-w! | |
657 | init-vend-class-id | |
658 | init-client-id | |
659 | ; | |
660 | ||
661 | : dhcp-close ( -- ) | |
662 | packet-to-send /dhcp-maxmsg free-mem | |
663 | 0 to packet-to-send | |
664 | udp-pseudo-hdr /udp-pseudo-hdr free-mem | |
665 | 0 is udp-pseudo-hdr | |
666 | options d# 256 /n * free-mem | |
667 | 0 to options | |
668 | selected-bootreply d# 1514 free-mem | |
669 | 0 to selected-bootreply | |
670 | ; | |
671 | ||
672 | : .dhcp-params ( -- ) | |
673 | debug-dhcp? if | |
674 | ." Client IP : " my-ip-addr be-l@ .inetaddr cr | |
675 | ." Server IP : " server-ip-addr be-l@ .inetaddr cr | |
676 | ." Router IP : " router-ip-addr be-l@ .inetaddr cr | |
677 | ." Subnet Mask : " subnet-mask be-l@ .inetaddr cr | |
678 | ." TFTP filename : " tftp-file count type cr | |
679 | ." TFTP Retries : " tftp-retries .d cr | |
680 | ." DHCP Retries : " dhcp-retries .d cr | |
681 | then | |
682 | ; | |
683 | ||
684 | headers | |
685 | ||
686 | : do-dhcp ( -- ) | |
687 | reserve-buffer | |
688 | init-dhcp | |
689 | try-dhcp | |
690 | init-config-params | |
691 | publish-bootp-response | |
692 | my-client-id count ?dup if | |
693 | publish-dhcp-clientid | |
694 | else | |
695 | drop | |
696 | then | |
697 | dhcp-close | |
698 | release-buffer | |
699 | .dhcp-params | |
700 | ; |