Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [rom/] [dhcpclient.asm] - Blame information for rev 384

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 76 winston
;The MIT License
2
;
3
;Copyright (c) 2008 Dylan Smith
4
;
5
;Permission is hereby granted, free of charge, to any person obtaining a copy
6
;of this software and associated documentation files (the "Software"), to deal
7
;in the Software without restriction, including without limitation the rights
8
;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
;copies of the Software, and to permit persons to whom the Software is
10
;furnished to do so, subject to the following conditions:
11
;
12
;The above copyright notice and this permission notice shall be included in
13
;all copies or substantial portions of the Software.
14
;
15
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
;THE SOFTWARE.
22
 
23
; DHCP Client
24 381 winston
.include        "spectranet.inc"
25
.include        "sysvars.inc"
26
.include        "dhcpdefs.inc"
27
.include        "ctrlchars.inc"
28 384 winston
.include        "sockdefs.inc"
29 381 winston
.text
30 76 winston
;-------------------------------------------------------------------------
31
; F_dhcp
32
; Performs all the actions of a DHCP client, displaying helpful messages
33
; on the console as the process proceeds.
34
; In summary, this consists of:
35
;   - Generate DHCPDISCOVER. This generates the XID, initializes the
36
;     hardware (no IP address) and broadcasts a DHCPDISCOVER message.
37
;   - Wait for and receive DHCPOFFER. This message is an offer from a
38
;     server - the first offer to come back is processed (a network
39
;     can have more than one DHCP server).
40
;   - In response to the DHCPOFFER, send a DHCPREQUEST. This contains
41
;     a readback of the information offered by the previous DHCPOFFER.
42
;   - Wait for and process the DHCPACK. Once a correct DHCPACK is received,
43
;     the hardware is set up with the data returned.
44
; The DHCP client requests an IP address, subnet mask and default gateway,
45
; and any DNS servers.
46 79 winston
 
47 381 winston
.globl F_dhcp
48
F_dhcp:
49 89 winston
        ld bc, 0xFFFF           ; delay for long enough for hw to init
50 381 winston
.delay1:
51 109 winston
        push hl                 ; waste a load of time
52
        push bc
53
        push de
54
        pop de
55
        pop bc
56
        pop hl
57 89 winston
        dec bc
58
        ld a, b
59
        or c
60 381 winston
        jr nz, .delay1
61 89 winston
 
62 76 winston
        ld hl, STR_dhcpinit
63 79 winston
        call PRINT42
64 76 winston
        ld hl, STR_dhcpdiscover
65 79 winston
        call PRINT42
66 76 winston
 
67 109 winston
        ld b, 8                 ; num of retries
68 381 winston
.retrydiscover1:
69 109 winston
        push bc
70 89 winston
 
71 76 winston
        call F_dhcpdiscover
72 381 winston
        jr c, .borked1
73 76 winston
 
74
        call F_dhcprecvoffer
75 381 winston
        jr nc, .offer1
76 109 winston
        cp DHCP_INTERRUPTED     ; BREAK pressed?
77 381 winston
        jr z, .break1
78 109 winston
        ld a, '.'
79
        call PUTCHAR42
80
        pop bc
81 381 winston
        djnz .retrydiscover1
82 109 winston
 
83
        push af                 ; ran out of retries
84 381 winston
        ld a, NEWLINE           ; so put a CR
85 109 winston
        call PUTCHAR42
86 89 winston
        pop af
87 381 winston
        jr .borked1             ; then report the error
88 89 winston
 
89 381 winston
.break1:
90 109 winston
        pop bc                  ; fix stack
91 381 winston
        jr .borked1
92 109 winston
 
93 381 winston
.offer1:
94 109 winston
        pop bc                  ; fix stack
95 76 winston
        ld hl, STR_dhcpoffer
96 79 winston
        call PRINT42
97 76 winston
 
98
        ld hl, STR_dhcprequest
99 79 winston
        call PRINT42
100 76 winston
        call F_dhcpsendrequest
101 381 winston
        jr c, .borked1
102 76 winston
 
103
        call F_dhcprecvack
104 381 winston
        jr c, .borked1
105 76 winston
        ld hl, STR_dhcpack
106 79 winston
        call PRINT42
107 76 winston
 
108
        ; Display the IP address that we got back.
109
        ld hl, STR_ipaddr
110 79 winston
        call PRINT42
111 76 winston
        ld hl, v_dhcpreqaddr
112
        ld de, buf_workspace
113 79 winston
        call LONG2IPSTRING
114 76 winston
        ld hl, buf_workspace
115 79 winston
        call PRINT42
116 381 winston
        ld a, NEWLINE
117 95 winston
        call PUTCHAR42
118 76 winston
        ret
119
 
120 381 winston
.borked1:
121 76 winston
        push af
122
        ld hl, STR_failed
123 79 winston
        call PRINT42
124 76 winston
        pop af
125
        ld hl, v_workspace
126 79 winston
        call ITOA8
127 76 winston
        ld hl, v_workspace
128 79 winston
        call PRINT42
129 381 winston
        ld a, NEWLINE
130 109 winston
        call PUTCHAR42
131
 
132
        ; pause - TODO: something a bit better (perhaps a keypress?)
133
        ld bc, 0xFFFF
134 381 winston
.bdelay1:
135 109 winston
        dec bc
136
        push hl
137
        push de
138
        push bc
139
        pop bc
140
        pop de
141
        pop hl
142
        ld a, b
143
        or c
144 381 winston
        jr nz, .bdelay1
145 109 winston
 
146 76 winston
        ret
147
 
148 381 winston
STR_dhcpinit:   defb "Press BREAK to interrupt.\n",0
149
STR_dhcpdiscover:       defb "DHCPDISCOVER",0
150
STR_dhcpoffer:          defb "\nDHCPOFFER\n",0
151
STR_dhcprequest:                defb "DHCPREQUEST\n",0
152
STR_dhcpack:            defb "DHCPACK\n",0
153
STR_failed:             defb "DHCP failed with return code ",0
154
STR_ipaddr:             defb "Allocated IP address ",0
155
STR_interrupted:                defb "\nBREAK pressed\n",0
156 76 winston
 
157
;-------------------------------------------------------------------------
158
; F_dhcpdiscover
159
; Creates and sends the DHCPDISCOVER message.
160 381 winston
.globl F_dhcpdiscover
161
F_dhcpdiscover:
162 76 winston
        ; Most of the DHCPDISCOVER message is zeros, so we can
163
        ; save a lot of effort by starting with a workspace set to that.
164
        ld hl, buf_message
165
        ld de, buf_message+1
166
        ld bc, dhcp_msglen
167
        ld (hl), 0
168
        ldir
169
 
170
        ; Set the standard parts of the header.
171
        ld hl, buf_message
172
        ld (hl), dhcp_opval     ; dhcp op
173
        inc l
174
        ld (hl), dhcp_htypeval  ; dhcp htype
175
        inc l
176
        ld (hl), dhcp_hlenval   ; dhcp htype length
177
 
178
        ; Create a session identifier
179 79 winston
        call RAND16
180 76 winston
        ld (buf_message+dhcp_xid), hl
181
        ld (v_dhcpxid), hl
182 79 winston
        call RAND16
183 76 winston
        ld (buf_message+dhcp_xid+2), hl
184
        ld (v_dhcpxid+2), hl
185
 
186
        ; Copy the request options data to the buffer.
187
        ld hl, DHCPDISCOVER_BLOCK
188
        ld de, buf_message+dhcp_options
189 381 winston
        ld bc, DHCPBLOCKSZ
190 76 winston
        ldir
191
 
192 93 winston
        ; Copy the hardware address to the memory pointed by de
193
        call GETHWADDR
194 76 winston
 
195
        ; Copy the hardware address into the header, too.
196
        ld de, buf_message+dhcp_chaddr
197 93 winston
        call GETHWADDR
198 76 winston
 
199
        ; Re-initialize other hardware registers to zero
200 93 winston
        call DECONFIG
201 381 winston
.send2:
202 76 winston
        ; Send the assembled DHCP message.
203
        ld c, SOCK_DGRAM        ; Datagram (UDP) socket
204 79 winston
        call SOCKET
205 76 winston
        ret c                   ; error on carry
206
        ld (v_dhcpfd), a        ; save the socket fd
207
 
208
        ; The DHCP request should come from port 68 and go to port 67
209
        ld hl, v_dhcpsockinfo   ; socket info structure
210
        ld b, 4
211 381 winston
.fill2:
212
        ld (hl), 0xFF           ; dest address = 255.2552.2552.2552
213 76 winston
        inc l
214 381 winston
        djnz .fill2
215 76 winston
        ld hl, 67               ; destination port
216
        ld (v_dhcpsockinfo+4), hl
217
        inc l
218
        ld (v_dhcpsockinfo+6), hl
219
 
220
        ; send the request
221
        ld a, (v_dhcpfd)
222
        ld hl, v_dhcpsockinfo
223
        ld de, buf_message
224
        ld bc, dhcp_msglen
225 79 winston
        call SENDTO
226 76 winston
        jp c, F_closeonerror
227
        ret
228
 
229
;---------------------------------------------------------------------------
230
; F_dhcprecvoffer
231
; Wait for a DHCPOFFER message. The assumption is that F_dhcpdiscover
232
; was called, and has opened a UDP socket for the DHCP messages.
233 381 winston
.globl F_dhcprecvoffer
234
F_dhcprecvoffer:
235 76 winston
        ; bind to port 68 for the incoming message
236
        ld a, (v_dhcpfd)
237
        ld de, 68               ; port 68
238 79 winston
        call BIND
239 76 winston
        ret c
240
 
241
        call F_waitfordhcpmsg   ; poll for message
242
        ret c
243
 
244
        ld hl, v_dhcpsockinfo
245
        ld de, buf_message
246
        ld bc, dhcp_msglen
247
        ld a, (v_dhcpfd)
248 79 winston
        call RECVFROM
249 76 winston
        jp c, F_closeonerror    ; leave on error
250
 
251
        ; Check the XID.
252 78 winston
        ;call F_comparexid
253
        ;ret c                  ; bad XID, return now
254 76 winston
 
255
        ; Retrieve the server address from the options block, we need
256
        ; it for the subsequent DHCPREQUEST.
257
        ld hl, buf_message+dhcp_options+4
258
        ld de, v_dhcpserver
259
        ld b, dhcp_opt_server
260
        call F_dhcpgetoption
261
        jp c, F_closeonerror    ; leave on error
262
 
263
        ; Get the lease
264
        ld hl, buf_message+dhcp_options+4
265
        ld de, v_dhcplease
266
        ld b, dhcp_opt_lease
267
        call F_dhcpgetoption
268
        jp c, F_closeonerror    ; leave on error
269
 
270
        ; Save the YIADDR parameter, this is the IP the server wants
271
        ; to give us, this needs to be sent back in the DHCPREQUEST.
272
        ld hl, buf_message+dhcp_yiaddr
273
        ld de, v_dhcpreqaddr
274
        ldi
275
        ldi
276
        ldi
277
        ldi
278
        ret
279
 
280
;---------------------------------------------------------------------------
281
; F_dhcpsendrequest
282
; Turn around the data sent in the DHCPOFFER message with the right
283
; bits tweaked to turn it into a DHCPREQUEST.
284 381 winston
.globl F_dhcpsendrequest
285
F_dhcpsendrequest:
286 76 winston
        ; Most of the DHCPDISCOVER message is zeros, so we can
287
        ; save a lot of effort by starting with a workspace set to that.
288
        ld hl, buf_message
289
        ld de, buf_message+1
290
        ld bc, dhcp_msglen
291
        ld (hl), 0
292
        ldir
293
 
294
        ; Set the standard parts of the header.
295
        ld hl, buf_message
296
        ld (hl), dhcp_opval     ; dhcp op
297
        inc l
298
        ld (hl), dhcp_htypeval  ; dhcp htype
299
        inc l
300
        ld (hl), dhcp_hlenval   ; dhcp htype length
301
 
302
        ; Copy the XID
303
        ld hl, v_dhcpxid
304
        ld de, buf_message+dhcp_xid
305
        ldi
306
        ldi
307
        ldi
308
        ldi
309
 
310
        ; Copy the request options data to the buffer.
311
        ld hl, DHCPDISCOVER_BLOCK
312
        ld de, buf_message+dhcp_options
313 381 winston
        ld bc, DHCPBLOCKSZ
314 76 winston
        ldir
315
        ; modify the message from DISCOVER to REQUEST
316
        ld hl, buf_message+dhcp_options+6
317
        ld (hl), dhcp_request
318
 
319 93 winston
        ; Get the hardware address into the buffer at de
320
        call GETHWADDR
321 76 winston
 
322
        ; Add options for server address and client IP
323
        ex de, hl                       ; move pointer back to hl
324
        ld (hl), dhcp_opt_server        ; Server ID
325
        inc hl
326
        ld (hl), 4                      ; 4 bytes
327
        inc hl
328
        ld de, v_dhcpserver             ; passed to us in the OFFER msg
329
        ex de, hl
330
        ldi                             ; copy it into the DHCPREQUEST
331
        ldi
332
        ldi
333
        ldi
334
        ex de, hl
335
        ld (hl), dhcp_opt_reqaddr       ; Request the address we were offered
336
        inc hl
337
        ld (hl), 4                      ; which is 4 bytes long
338
        inc hl
339
        ld de, v_dhcpreqaddr            ; and was passed in the DHCPOFFER
340
        ex de, hl
341
        ldi
342
        ldi
343
        ldi
344
        ldi
345
 
346
        ; Replace the lease with what we were offered.
347
        ld hl, v_dhcplease
348 381 winston
        ld de, DHCPLEASE_OFFSET
349 76 winston
        ldi
350
        ldi
351
        ldi
352
        ldi
353
 
354
        ; Copy the hardware address into the header, too.
355
        ld de, buf_message+dhcp_chaddr
356 93 winston
        call GETHWADDR
357 76 winston
 
358 381 winston
.send4:
359 76 winston
        ; The DHCP request should come from port 68 and go to port 67
360
        ld hl, v_dhcpsockinfo   ; socket info structure
361
        ld b, 4
362 381 winston
.fill4:
363
        ld (hl), 0xFF           ; dest address = 255.2554.2554.2554
364 76 winston
        inc l
365 381 winston
        djnz .fill4
366 76 winston
        ld hl, 67               ; destination port
367
        ld (v_dhcpsockinfo+4), hl
368
        inc l
369
        ld (v_dhcpsockinfo+6), hl
370
 
371
        ; send the request
372
        ld a, (v_dhcpfd)
373
        ld hl, v_dhcpsockinfo
374
        ld de, buf_message
375
        ld bc, dhcp_msglen
376 79 winston
        call SENDTO
377 76 winston
        jp c, F_closeonerror    ; leave on error
378
        ret
379
 
380
;---------------------------------------------------------------------------
381
; F_dhcprecvack
382
; Receives the DHCPACK message and extracts the fields that we require.
383 381 winston
.globl F_dhcprecvack
384
F_dhcprecvack:
385 76 winston
        ; bind to port 68 for the incoming message
386
        ld a, (v_dhcpfd)
387
        ld de, 68               ; port 68
388 79 winston
        call BIND
389 76 winston
        ret c
390
 
391
        ; Receive the ACK (or possibly NAK) message
392
        ld a, (v_dhcpfd)
393
        ld hl, v_dhcpsockinfo
394
        ld de, buf_message
395
        ld bc, dhcp_msglen
396
        ld a, (v_dhcpfd)
397 79 winston
        call RECVFROM
398 76 winston
        jp c, F_closeonerror
399
 
400
        ld a, (v_dhcpfd)
401 79 winston
        call CLOSE
402 76 winston
 
403
        ; Check the XID.
404
        call F_comparexid
405
        ret c                   ; bad XID, return now
406
 
407
        ; Save YIADDR, this should be the same as what was in the
408
        ; DHCPOFFER but we'll take no chances.
409
        ld hl, buf_message+dhcp_yiaddr
410
        ld de, v_dhcpreqaddr
411
        ldi
412
        ldi
413
        ldi
414
        ldi
415
 
416 93 winston
        ; Set the hardware up with the IPv4 address
417 76 winston
        ld hl, buf_message+dhcp_yiaddr
418 93 winston
        call IFCONFIG_INET
419 76 winston
 
420
        ; Now get our options.
421
        ld hl, v_nameserver1    ; initialize nameserver copy
422
        ld (v_nspointer), hl
423
        ld hl, buf_message+dhcp_options+4
424
        ld b, 0                 ; BC = length of option
425 381 winston
.optloop5:
426 76 winston
        ld a, (hl)              ; Option
427
        inc hl
428
        ld c, (hl)              ; Length
429
        inc hl
430
        cp dhcp_opt_msg         ; Message type? (usually 1st in the list)
431 381 winston
        jr z, .checkmsg5
432 76 winston
        cp dhcp_opt_gateway     ; Gateway address?
433 381 winston
        jr z, .copygw5
434 76 winston
        cp dhcp_opt_netmask     ; Netmask?
435 381 winston
        jr z, .copynetmask5
436 76 winston
        cp dhcp_opt_dns         ; DNS server?
437 381 winston
        jr z, .copydns5
438 76 winston
        and a                   ; End of options?
439
        ret z                   ; in which case return now
440
        add hl, bc              ; move hl to next option
441 381 winston
        jr .optloop5
442
.copygw5:
443 93 winston
        call IFCONFIG_GW        ; set the gateway address
444 381 winston
        jr .optloop5
445
.copynetmask5:
446 93 winston
        call IFCONFIG_NETMASK   ; set the netmask
447 381 winston
        jr .optloop5
448
.copydns5:
449 76 winston
        ld de, (v_nspointer)
450
        ld a, v_nsend % 256     ; address of end of nameserver memory
451
        cp e                    ; no more space?
452 381 winston
        jr z, .skipdns5
453 76 winston
        ldir
454
        ld (v_nspointer), de
455 381 winston
        jr .optloop5
456
.skipdns5:
457 76 winston
        ld c, 4
458
        add hl, bc
459 381 winston
        jr .optloop5
460
.checkmsg5:
461 76 winston
        ld a, (hl)              ; Get the message type (always 1 byte long)
462
        cp dhcp_msg_ack         ; check that it's a DHCPACK
463
        inc hl                  ; message is 1 byte long
464 381 winston
        jr z, .optloop5         ; if so, continue
465 76 winston
        ld a, DHCP_NAK          ; if not set error code and exit
466
        scf
467
        ret
468
 
469
;---------------------------------------------------------------------------
470
; F_dhcpgetoption
471
; Gets a single option from the DHCP options field.
472
; HL = pointer to DHCP options block (after the magic cookie)
473
; DE = pointer to memory to copy the result
474
; B = option to search for
475 381 winston
.globl F_dhcpgetoption
476
F_dhcpgetoption:
477 76 winston
        ld a, (hl)      ; get option
478
        and a           ; zero?
479 381 winston
        jr z, .notfound6        ; option not found
480 76 winston
        inc hl
481
        ld c, (hl)      ; get length of option
482
        inc hl
483
        cp b            ; is it the option we're looking for?
484
        ld a, b         ; save option in A
485
        ld b, 0         ; bc now = size of option
486 381 winston
        jr nz, .nextopt6        ; no - go for the next option
487 76 winston
        ldir            ; copy option to destination buffer
488
        ret             ; done
489 381 winston
.nextopt6:
490 76 winston
        add hl, bc      ; add length to hl to point at the next option
491
        ld b, a         ; get back the option
492
        jr F_dhcpgetoption
493 381 winston
.notfound6:
494 76 winston
        scf             ; indicate option not found
495
        ld a, DHCP_OPTNOTFOUND  ; return code
496
        ret
497
 
498
;--------------------------------------------------------------------------
499
; F_comparexid
500
; Compares the XID field received in a DHCP message with the XID that
501
; we sent in the first instance. Carry is set if the compare fails,
502
; and A is set to the DHCP_BAD_XID return code on failure.
503 381 winston
.globl F_comparexid
504
F_comparexid:
505 76 winston
        ld hl, buf_message+dhcp_xid
506
        ld de, v_dhcpxid
507
        ld b, 4
508 381 winston
.cmploop7:
509 76 winston
        ld a, (de)
510
        cp (hl)
511 381 winston
        jr nz, .badxid7
512 76 winston
        inc hl
513
        inc de
514 381 winston
        djnz .cmploop7
515 76 winston
        ret
516 381 winston
.badxid7:
517 76 winston
        ld a, DHCP_BAD_XID
518
        scf
519
        ret
520
 
521
;--------------------------------------------------------------------------
522
; F_waitfordhcpmsg
523
; Waits for DHCP data, and returns with carry set if we poll for too long
524
; and have not got a response. Also allows for user (keyboard) interruption.
525 381 winston
.globl F_waitfordhcpmsg
526
F_waitfordhcpmsg:
527 76 winston
        ld bc, dhcp_polltime
528 381 winston
.loop8:
529 76 winston
        push bc
530 366 winston
        ld bc, 0x7ffe           ; read B to SPACE
531
        in a, (c)               ; check for BREAK
532
        cp 0xBE
533 381 winston
        jr z, .interrupted8
534 76 winston
        ld a, (v_dhcpfd)
535 79 winston
        call POLLFD             ; data ready for this file descriptor?
536 76 winston
        pop bc
537
        jp c, F_closeonerror    ; an error in pollfd
538
        ret nz                  ; data is ready
539
        dec bc
540
        ld a, b
541
        or c                    ; check bc for zero
542 381 winston
        jr nz, .loop8           ; make another loop
543 76 winston
        ld a, DHCP_TIMEOUT      ; error code is timeout
544 109 winston
        jr F_closeonerror       ; close and return
545 381 winston
.interrupted8:
546 366 winston
        pop bc                  ; restore stack
547 109 winston
        ld hl, STR_interrupted
548
        call PRINT42
549
        ld a, DHCP_INTERRUPTED  ; just fall through to closeonerror
550 76 winston
 
551
;--------------------------------------------------------------------------
552
; F_closeonerror
553
; A helper function to close and return with the carry flag set.
554 381 winston
.globl F_closeonerror
555
F_closeonerror:
556 76 winston
        push af
557
        ld a, (v_dhcpfd)
558 79 winston
        call CLOSE
559 76 winston
        pop af
560
        scf
561
        ret
562