-
Notifications
You must be signed in to change notification settings - Fork 1
/
netware.asm
651 lines (543 loc) · 18 KB
/
netware.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
struc NETWAREHEADER
.length resw 1
.subFunction resb 1
.size:
endstruc
struc NETWARE_PIPE
.pipeStatus resb 1 ; 0 = no connection attempts
; 1 = connection request sent
; 2 = connection request received
; 3 = connected. :-)
.ipxAddress:
.remoteNetAddr resb 4 ; address of the remote computer.
.remoteNodeAddr resb 6
.size:
endstruc
struc IPX_COMMAND_HEADER
.command resb 1
.connectionNumber resb 1
.length resb 1
.data:
.size:
endstruc
struc NETWARE_SEND
.length resw 1
.subFunction resb 1
.numConnections resb 1
.connectionList:
.size:
endstruc
struc NETWARE_GET_REPLY
.length resw 1
.senderConnectionNumber resb 1
.msgLength resb 1
.message:
.size:
endstruc
struc RECEIVE_BUFFER
.senderConnectionNumber resb 1
.msgLength resb 1
.buffer resb 126
.size:
endstruc
%define SEND_PACKET_CMD 1
%define OPEN_PIPE_CMD 2
%define CLOSE_PIPE_CMD 3
%define CONN_ESTABLISHED_CMD 3
%define NUMBER_OF_RECEIVE_BUFFERS 6
int21e1Handler:
;TODO dispatch to other functions based on sub function code.
push ax
mov al, byte [ds:si + NETWAREHEADER.subFunction]
cmp al, 4
jnz .checkSubfunction5
jmp sendPacketHandler
.checkSubfunction5:
cmp al, 5
jnz .checkSubfunction6
jmp getPacketHandler
.checkSubfunction6:
cmp al, 6
jnz .checkSubfunction7
jmp openPipeHandler
.checkSubfunction7:
cmp al, 7
jnz .checkSubfunction8
jmp closePipeHandler
.checkSubfunction8:
cmp al, 8
jz near checkPipeStatusHandler
; fall through to existing handler.
.existingHandler:
pop ax
jmp existingHandler ; call the original interrupt handler here.
sendPacketHandler:
pop ax
; request buffer in DS:SI
; reply buffer in ES:DI
; write message to open pipes
push ax
push bx
push cx
push dx
mov al, byte [si + NETWARE_SEND.numConnections]
mov cl, al ; number of connections to send to.
mov byte [es:di + 2], al ; write the number of connections to reply buffer.
inc al
mov ah, 0
mov word [es:di], ax ; write length of reply data. num connections + 1
mov dx, di
add dx, 3 ; dx points to start of reply buffer connection status list
mov ch, 0
mov bx, si
add bx, NETWARE_SEND.connectionList ; bx pointing to start of connection list.
.loopStart:
cmp ch, cl ; while (ch < numConnections)
jge .loopEnd
mov al, byte [bx] ; get next connection number from list
call getConnectionStatus ; status returned in AH
push bx
mov bx, dx
mov byte [es:bx], ah ; write connection status out to reply buffer.
pop bx
cmp ah, 0
jnz .skipSend ; only send if connected. eg connections status == 0
call sendPacketToPipe
.skipSend:
inc dx
inc bx
inc ch
jmp .loopStart
.loopEnd:
pop dx
pop cx
pop bx
pop ax
jmp _netwareExitInterrupt
;;;;;;;;;;;;;;;; Netware - Get Personal Message ;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
getPacketHandler:
; reply in ES:DI
pop ax
push cx
push si
lea si, [recvBuffers]
mov al, byte [cs:recvBufferNextRead]
mov cl, al
mov ch, RECEIVE_BUFFER.size
mul ch
add si, ax ; si now points to recvBuffers[recvBufferNextRead]
mov al, byte [cs:si + RECEIVE_BUFFER.senderConnectionNumber]
cmp al, 0 ; no message waiting if senderConnectionNumber is 0.
jz .noMessage
mov byte [es:di + 2], al ; write sender connection number
mov byte [cs:si + RECEIVE_BUFFER.senderConnectionNumber], 0 ; zero out this sender connection number so the buffer can be reused.
mov cl, byte [cs:si + RECEIVE_BUFFER.msgLength]
mov ch, 0
;cx is now the message length
inc cx
inc cx
mov word [es:di], cx ; write length to reply buffer (msgLength + 2)
dec cx
dec cx ; cx is now the length of the message data.
mov byte [es:di + 3], cl ; write length of message to reply buffer
push di
push si
push ds
push cs
pop ds
add si, RECEIVE_BUFFER.buffer
add di, 4
rep movsb ; copy message data to reply buffer.
pop ds
pop si
pop di
mov al, byte [cs:recvBufferNextRead]
inc al ; increment recv buffer pointer index.
cmp al, NUMBER_OF_RECEIVE_BUFFERS
jl .saveRecvPointer
; wrap pointer back to 0
mov al, 0
.saveRecvPointer:
mov byte [cs:recvBufferNextRead], al ; save recvBuffer index.
jmp .exit
.noMessage:
mov word [es:di + NETWARE_GET_REPLY.length], 2
mov word [es:di + NETWARE_GET_REPLY.senderConnectionNumber], 0
mov word [es:di + NETWARE_GET_REPLY.msgLength], 0
.exit:
pop si
pop cx
mov al, 0 ; success.
jmp _netwareExitInterrupt
;;;;;;;;;;;;;;;; Netware - Open connection pipes ;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
openPipeHandler:
pop ax
; set requested pipe array based on values in
; number of open requests in byte at ds:si + 3
; connection numbers stored at ds:si + 4
push bx
push cx
push dx
push si
push di
mov cl, byte [ds:si + 3] ; number of connections to open
mov bl, cl
mov bh, 0
inc bx
mov word [es:di], bx ; write the size of the reply buffer. number of connections + 1
mov byte [es:di + 2], cl ; write the number of connections to the reply buffer.
mov ch, 0
add si, 4 ; advance si to point to connection number data
.loopStart: ; loop over all requested connections
cmp ch, cl
jge .loopEnd
mov al, byte [ds:si] ; load connection number.
lea bx, [sendBuffer]
add bx, IPX_COMMAND_HEADER.size ; skip over ipx command header bytes
push ax
mov al, ch
mov ah, 0
add bx, ax ; bx = &sendBuffer[2 + ch]
pop ax
mov byte [cs:bx], al ; write connection number to ipx send buffer.
cmp al, 0 ; if(connectionNumber == 0) continue;
jz .continue
dec al ; connectionNumber--
mov dl, NETWARE_PIPE.size
mul dl ; ax = al * dl
lea bx, [netwarePipes]
add bx, ax ; bx = netwarePipes[connectionNumber - 1];
mov al, byte [cs:bx + NETWARE_PIPE.pipeStatus] ; get existing pipe status for connection
or al, 1
mov byte [cs:bx + NETWARE_PIPE.pipeStatus], al ; mark that we want to open this pipe.
mov ah, 0xfe ; pipe connection incomplete status
cmp al, 3 ; jump if pipe is not connected
jnz .writeStatus
mov ah, 0 ; successfully connected pipe status
.writeStatus:
mov byte [es:di + 3], ah
.continue:
inc di
inc si ; increment si to point to next connection number.
inc ch
jmp .loopStart
.loopEnd:
mov al, cl
add al, IPX_COMMAND_HEADER.size
mov byte [cs:sendPacketLength], al ; size of ipx packet. 2 header bytes + number of connection requests.
lea bx, [sendBuffer] ; write ipx send header details
mov byte [cs:bx + IPX_COMMAND_HEADER.command], OPEN_PIPE_CMD ; write command byte
mov al, byte [cs:netWareConnectionNumber]
mov byte [cs:bx + IPX_COMMAND_HEADER.connectionNumber], al ; write our connection number to msg.
mov byte [cs:bx + IPX_COMMAND_HEADER.length], cl ; write number of connections
pop di
pop si
pop dx
pop cx
pop bx
call ipxsendbroadcastmessage ; send ipx message.
mov al, 0 ; success.
jmp _netwareExitInterrupt
;;;;;;;;;;;;;;;; Netware - Close pipes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
closePipeHandler:
pop ax
call ipxsendbroadcastmessage
jmp _netwareExitInterrupt
;;;;;;;;;;;;;;;; Netware - Check pipe status ;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
checkPipeStatusHandler:
pop ax
; check pipe status for connection array based on values in
; number of pipe requests in byte at ds:si + 3
; connection numbers stored at ds:si + 4
push bx
push cx
push dx
push si
push di
mov cl, byte [ds:si + 3] ; number of connections to check
mov bl, cl
mov bh, 0
inc bx
mov word [es:di], bx ; write the size of the reply buffer. number of connections + 1
mov byte [es:di + 2], cl ; write the number of connections to the reply buffer.
mov ch, 0
add si, 4 ; advance si to point to connection number data
.loopStart: ; loop over all pipe connections to check
cmp ch, cl
jge .loopEnd
mov al, byte [ds:si] ; load connection number.
cmp al, 0 ; if(connectionNumber == 0) continue;
jz .continue
dec al ; connectionNumber--
mov dl, NETWARE_PIPE.size
mul dl ; ax = al * dl
lea bx, [netwarePipes]
add bx, ax ; bx = netwarePipes[connectionNumber - 1];
mov al, byte [cs:bx + NETWARE_PIPE.pipeStatus] ; get existing pipe status for connection
mov ah, 0xfe ; pipe connection incomplete status
cmp al, 0 ; check if pipe is closed
jnz .checkForOpen
mov ah, 0xff ; closed status
jmp .writeStatus
.checkForOpen:
cmp al, 3 ; check if pipe connected
jnz .writeStatus
mov ah, 0 ; successfully connected pipe status
.writeStatus:
mov byte [es:di + 3], ah
.continue:
inc di
inc si ; increment si to point to next connection number.
inc ch
jmp .loopStart
.loopEnd:
pop di
pop si
pop dx
pop cx
pop bx
mov al, 0 ; success.
jmp _netwareExitInterrupt
_netwareExitInterrupt:
popf
iret
;;;;;;;;;; Netware broadcast listener ESR ;;;;;;;;;;;;;;;;;;;
; call back used to process broadcast messages open/close pipe, connection established.
netwareESR:
; TODO handle conn established messages here.
mov al, byte [cs:recvBroadcastBuffer + IPX_COMMAND_HEADER.command] ; read the command from the incoming message
cmp al, OPEN_PIPE_CMD
jz .openPipeCommand
cmp al, CLOSE_PIPE_CMD
jz .closePipeCommand
jmp .exitESR
.openPipeCommand:
call doesCommandTargetMe ; check if this command is targeting us.
cmp al, 0
jz .exitESR
mov al, byte [cs:recvBroadcastBuffer + IPX_COMMAND_HEADER.connectionNumber] ; get the connection number of the sender.
dec al
lea bx, [netwarePipes]
mov dl, NETWARE_PIPE.size
mul dl ; ax = (SenderConnectionNumber - 1) * NETWARE_PIPE.size
add bx, ax
mov al, byte [cs:bx + NETWARE_PIPE.pipeStatus] ; get pipe status for the sending connection number
or al, 2 ; set the sender requested open flag in status
mov byte [cs:bx + NETWARE_PIPE.pipeStatus], al
call writeSenderHeaderToPipeList ; write sender address to pipe record currently pointed to by CS:BX
cmp al, 3 ; check if we're connected now.
jnz .exitESR
; We're connected here.
; TODO Send connection established message back to sender if we have previously attempted to connect.
jmp .exitESR
.closePipeCommand:
call doesCommandTargetMe ; check if this command is targeting us.
cmp al, 0
jz .exitESR
; TODO set remote connection to closed in netwarePipes
jmp .exitESR
.exitESR:
; setup ECB to listen for another packet.
lea si, [recvBroadcastECB]
mov ax, cs
mov es, ax
call ipxlistenforpacket ; listen for broadcast messages on 0x2001 and handle them with netwareESR:
retf
;;;; IPX direct message ESR ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Used to listen for direct messages. Messages stored in recvBuffers[] ;
; Start at recvBuffers[recvBufferNextRead] and find the first free
; buffer then write the message to it. (Free buffers have 0 in the
; senderConnectionNumber field)
receiveMsgESR:
; ECB in ES:SI
; find a free buffer to write the message to.
lea di, [recvBuffers]
mov al, byte [cs:recvBufferNextRead]
mov cl, al
mov ch, RECEIVE_BUFFER.size
mul ch
add di, ax ; di now points to recvBuffers[recvBufferNextRead]
mov ch, 0
.loopStart:
cmp ch, NUMBER_OF_RECEIVE_BUFFERS
jge .resetListener ; we've exhausted all 6 buffers so lets exit without saving this message. :(
mov al, byte [cs:di + RECEIVE_BUFFER.senderConnectionNumber]
cmp al, 0
jz .writeMsgToBuffer ; we've found an empty buffer. break out of loop. :)
cmp cl, NUMBER_OF_RECEIVE_BUFFERS ; check if we need to wrap around to the start of the recvBuffers array.
jz .wrapIndex
add di, RECEIVE_BUFFER.size ; move to next buffer
inc cl
jmp .loopEnd
.wrapIndex:
lea di, [recvBuffers]
mov cl, 0
jmp .loopEnd
.loopEnd:
inc ch ; increment loop counter
jmp .loopStart
.writeMsgToBuffer:
; the free receive buffer is stored in CS:DI
mov cx, word [es:si + IPXLISTENER.header + IPXHEADER.length] ; length is packet length + 30 byte header (big endian)
xchg cl, ch ; swap endian
sub cx, 30 ; remove header
; cl = packet length
dec cl ; cl remove the sender number byte. This is now the data length
mov byte [cs:di + RECEIVE_BUFFER.msgLength], cl ; write message length
mov al, byte [es:si + IPXLISTENER.buffer] ; read in sender connection number
mov byte [cs:di + RECEIVE_BUFFER.senderConnectionNumber], al ; write sender connection number
push si
push es
push ds
push es
pop ds
push cs
pop es
add di, RECEIVE_BUFFER.buffer
add si, IPXLISTENER.buffer
inc si ; skip the sender connection number byte.
rep movsb ; copy CX bytes from IPX buffer to recvBuffers slot.
pop ds
pop es
pop si
.resetListener:
mov di, si ; ECB offset
lea ax, [receiveMsgESR]
call ipxInitListenerECB ; reset listener ECB
; es already set to ECB seg here.
mov di, si
call ipxlistenforpacket ; setup ECB to listen for packet.
retf
;;; write the sender address to the netwarePipe record.
; netware pipe record address passed in BX
writeSenderHeaderToPipeList:
; copy from ECB.header.source to cs:BX + remoteNetAddr. 10 bytes
push ax
mov ax, word [cs:recvBroadcastHeader + IPXHEADER.source]
mov word [cs:bx + NETWARE_PIPE.remoteNetAddr], ax
mov ax, word [cs:recvBroadcastHeader + IPXHEADER.source + 2]
mov word [cs:bx + NETWARE_PIPE.remoteNetAddr + 2], ax
mov ax, word [cs:recvBroadcastHeader + IPXHEADER.source + 4]
mov word [cs:bx + NETWARE_PIPE.remoteNetAddr + 4], ax
mov ax, word [cs:recvBroadcastHeader + IPXHEADER.source + 6]
mov word [cs:bx + NETWARE_PIPE.remoteNetAddr + 6], ax
mov ax, word [cs:recvBroadcastHeader + IPXHEADER.source + 8]
mov word [cs:bx + NETWARE_PIPE.remoteNetAddr + 8], ax
pop ax
ret
; returns 1 in AL if our connection number is contained in the connection list. 0 is returned otherwise.
; AH is trashed.
doesCommandTargetMe:
push bx
push cx
lea bx, [recvBroadcastBuffer]
mov cl, byte [cs:recvBroadcastBuffer + IPX_COMMAND_HEADER.length] ; get number of connections in the command
mov ch, 0 ; loop counter
.loopStart:
cmp ch, cl
jge .loopEnd
mov ah, byte [cs:bx + IPX_COMMAND_HEADER.data] ; get the connection number
mov al, byte [cs:netWareConnectionNumber]
cmp ah, al
jz .foundEntry ; if current connection number == our connection number then return true.
inc bx
inc ch
jmp .loopStart
.loopEnd:
mov al, 0 ; we didn't find out connection number in the list
jmp .return
.foundEntry:
mov al, 1 ; success we found our connection number.
.return:
pop cx
pop bx
ret
; gets the current connection status for a given connection number
; connection number passed in with AL
; status returned in AH
; 0xff not connected
; 0xfe partially connected
; 0 connected
getConnectionStatus:
push bx
push dx
mov ah, 0xff ; not connected.
cmp al, 0
jz .return
push ax
dec al
lea bx, [netwarePipes]
mov dl, NETWARE_PIPE.size
mul dl ; ax = (ConnectionNumber - 1) * NETWARE_PIPE.size
add bx, ax
pop ax ; restore al back to original connection number.
mov dl, byte [cs:bx + NETWARE_PIPE.pipeStatus] ; get pipe status for the sending connection number
; check the connection status
mov ah, 0xfe ; incomplete connection.
cmp dl, 0
jnz .checkForConnected
mov ah, 0xff ; not connected
jmp .return
.checkForConnected:
cmp dl, 3
jnz .return
mov ah, 0 ; connected status
.return:
pop dx
pop bx
ret
; send the netware packet to a given pipe.
; connection number passed in through AL
; netware request in DS:SI
sendPacketToPipe:
push ax
push bx
push cx
push dx
push si
push di
push es
mov dl, al ; dl = connectionNumber to send to.
mov al, byte [si + NETWARE_SEND.numConnections] ; number of connections to send to
add si, NETWARE_SEND.connectionList
mov ah, 0
add si, ax ; advance si pointer to the start of the packet data.
; NETWARE_SEND.connectionList + number of connections
mov al, [si] ; number of bytes to send
inc si ; si points to packet data.
mov cx, ax ; cx = number of bytes to send.
inc al
mov byte [cs:sendPacketLength], al ; store total packet length. netware packet + 1 byte for connection number.
mov ax, cs
mov es, ax ; es=cs
lea di, [sendBuffer] ; es:di = &sendBuffer
mov al, byte [cs:netWareConnectionNumber]
mov byte [es:di], al ; write our connection number to start of sendBuffer.
inc di
; write packet to sendBuffer
;cx number of bytes to copy.
;si netware packet data
;di &sendBuffer[1]
rep movsb ; copy bytes.
; get netwarePipe address for destConnectionNumber.
lea di, [netwarePipes]
dec dl ; destConnectionNumber - 1
mov al, NETWARE_PIPE.size
mul dl ; ax = (destConnectionNumber - 1) * netwarePipes.size
add di, ax ; di now pointing at netwarePipes[destConnectionNumber-1]
add di, NETWARE_PIPE.ipxAddress ; di = &netwarePipes[destConnectionNumber-1].remoteNetAddr
; send packet
call ipxInitDirectSendECB ; destination address in CS:DI
call ipxsendpacket ; send to remote computer.
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret