gscifs/src/SMBDEMO.S

2715 lines
63 KiB
ArmAsm

*
* Marinetti / SMB1 Test (THIS IS NOT SMB2), Mark II
*
* CHANGELOG
* Thursday, April 30, 2015 - Restarted effort, ported code from ORCA/M to Merlin32 and debugged Merlin32 environment
* Friday, May 1, 2015 - Ported more code to Merlin32, set up Merlin32 equates
* Saturday, May 2, 2015 - Formatting fixes, refactoring, rewritten SMB Negotiation code
* Saturday, May 9, 2015 - Receive and interpret NEG_PROT reply and start login
* Sunday, May 24, 2015 - Some bugfixes, Tool128 and Tool129 requirement for hashing and DES, LM password hashing support
* Also introducing successful SMB_Tree_ANDX message. We connect to remote shares now.
* Also introducing SMB_Open_ANDX message. We open a file now.
* Monday, May 25, 2015 - Bugfixes on SMB_Open_ANDX; file opening now successful
* Also introducing SMB_Read_ANDX message. We read a file now.
*
* REFERENCES
* smb.c / smb.h from libOGC
* http://www.ubiqx.org/cifs/SMB.html
*
rel
dsk smbdemo.l
* Macros (mostly from Merlin32 dist)
use GsOs.Macs
use Util.Macs
use Misc.Macs
use Locator.Macs
use Mem.Macs
use Qd.Macs
use QdAux.Macs
use Event.Macs
use Window.Macs
use Ctl.Macs
use Menu.Macs
use Desk.Macs
use Sound.Macs
use Line.Macs
use Dialog.Macs
use TCPIP.Macs ; from MOSP CVS
* Equates (ripped off from Merlin 16)
use E16.Dialog.Macs
use E16.GsOs.Macs
* Equates (from MOSP/Tools/Orca.M/e16.tcpip)
use E16.TCPIP.Macs
*-----------------------------------------------------------------------------
* DP variables and local equates
*-----------------------------------------------------------------------------
* DUM $000000 is broken on merlin32, if you want LDA (DP) $A5 opcode, write one-byte equates instead
* cause merlin32 will always give you $AD (LDAL)
* dum 0
*AppMMID
* ds 2,0 ; Memory Manager ID
*HndlRef
* ds 2,0 ; For Dereferencing MM Handle
*DPBase
* ds 1,0 ; Deref'd handle
* dend
* workaround: do this instead for DP variables
AppMMID = $0
HndlRef = $2
DPBase = $4
*-----------------------------------------------------------------------------
* GS/OS Program Entry Point
*-----------------------------------------------------------------------------
Entry mx %00
phk
plb
brl Main
*
* Check for toolbox errors
* too-simple error handler
*
CheckError bcs SysDeath
rts
SysDeath pha
PushLong #0000
_SysFailMgr
*
* StartUpTools - start up the various toolsets
*
StartUpTools _TLStartUp
pha
_MMStartUp
jsr CheckError
PullWord AppMMID
_MTStartUp
pha
pha
PushLong #$900 ; 9 pages of DP space
PushWord AppMMID
PushWord #$C005 ; Fixed, Page-Aligned, Locked, Unpurgeable
PushLong #$000000 ; in Bank $00, $0000
_NewHandle
jsr CheckError
PullLong HndlRef
lda [HndlRef]
sta DPBase
pha ; save dp pointer for later
pha
PushWord #$0080 ; Screen Mode ($0000 = 320, $0080 = 640)
PushWord #$00A0 ; Pixel Map Size ($0050 = 320, $00A0 = 640)
PushWord AppMMID
_QDStartUp
jsr CheckError
pla ; saved dp pointer
clc
adc #$300
pha ; save dp pointer for later
pha
PushWord #20 ; Event Queue size
PushWord #0 ; Min X clamp
PushWord #640 ; Max X clamp
PushWord #0 ; Min Y clamp
PushWord #200 ; Max Y clamp
PushWord AppMMID
_EMStartUp
jsr CheckError
PushWord #0
_SetBackColor
PushWord #3
_SetForeColor
PushWord #50 ; X position
PushWord #85 ; Y position
_MoveTo
PushLong #OneMoment
_DrawCString
PushLong #ToolList
_LoadTools
jsr CheckError
PushWord AppMMID
_WindStartUp
jsr CheckError
pla ; saved dp pointer
clc
adc #$100
pha ; save it for later
tax ; save dp pointer in x
PushWord AppMMID
phx
_CtlStartUp
jsr CheckError
pla
clc
adc #$100
pha
tax
PushWord AppMMID
phx
_LEStartUp
jsr CheckError
PushWord AppMMID
_DialogStartUp
jsr CheckError
pla
clc
adc #$100
pha
tax
PushWord AppMMID
phx
_MenuStartUp
jsr CheckError
_DeskStartUp
jsr CheckError
pla
clc
adc #$100
pha
pha
_SoundStartUp
jsr CheckError
_TCPIPStartUp
jsr CheckError
Tool $280 ; HashStartUp
jsr CheckError
pla
clc
adc #$100
pha
Tool $281 ; CryptoStartUp
rts
*
* ShutDownTools - shut em back down
*
ShutDownTools lda ToolList
asl
asl
tax
lda ToolList-2,x
cmp #$2 ; Memory Manager?
bne ShutDownOne ; Nope, do it normally
PushWord AppMMID
_DisposeAll
PushWord AppMMID
lda #$2 ; set up for toolset #2 (MM)
ShutDownOne ora #$300 ; Call #3 (Shutdown)
tax
jsl $E10000
dec ToolList
bne ShutDownTools
rts
*
* Main - main sequence of events
*
Main jsr StartUpTools
jsr PrepDeskTop
sep $20
ldal $e0c034
sta ScreenColorByte
lda #00
stal $e0c034
rep $30
* pretty corner rounding
PushWord #0000
_SetForeColor
* upper left
PushWord #0001
PushWord #0000
_MoveTo
PushWord #0001
PushWord #0002
_LineTo
PushWord #0002
PushWord #0000
_MoveTo
PushWord #0002
PushWord #0001
_LineTo
PushWord #0003
PushWord #0000
_MoveTo
PushWord #0003
PushWord #0000
_LineTo
* upper right
PushWord #0638
PushWord #0000
_MoveTo
PushWord #0638
PushWord #0002
_LineTo
PushWord #0637
PushWord #0000
_MoveTo
PushWord #0637
PushWord #0001
_LineTo
* lower left
PushWord #0000
PushWord #0195
_MoveTo
PushWord #0000
PushWord #0199
_LineTo
PushWord #0001
PushWord #0197
_MoveTo
PushWord #0001
PushWord #0199
_LineTo
PushWord #0002
PushWord #0199
_MoveTo
PushWord #0002
PushWord #0199
_LineTo
* lower right
PushWord #0639
PushWord #0195
_MoveTo
PushWord #0639
PushWord #0199
_LineTo
PushWord #0638
PushWord #0197
_MoveTo
PushWord #0638
PushWord #0199
_LineTo
PushWord #0637
PushWord #0199
_MoveTo
PushWord #0637
PushWord #0199
_LineTo
EventLoop pha ; Result Space
PushWord #$ffff ; Event Mask
PushLong #EventRec
_TaskMaster
pla
beq EventLoop
cmp #$11 ; wInMenuBar?
bne EventLoop ; no, so ignore
jsr MenuDispatch
bit QuitFlag
bpl EventLoop
sep $20
lda ScreenColorByte
stal $e0c034
rep $30
jsr ShutDownTools
iGSOS _Quit;QParams;1
*
* Prepare Desktop
*
PrepDeskTop PushLong #0000
_RefreshDesktop
_InitCursor
NextMenu pha
pha
lda MenuTbl
asl
tax
lda MenuTbl,x
phb
phb
pha
_NewMenu
PushWord #0000
_InsertMenu
dec MenuTbl
bne NextMenu
PushWord #1
_FixAppleMenu
pha
_FixMenuBar
pla
_DrawMenuBar
rts
*
* Apple Menu: About
*
About PushLong #AboutString
jsr InfoDialog
rts
*
* File Menu: Quit
*
Quit dec QuitFlag
rts
*
* TCP/IP Test
*
TCPIPTest pha
PushWord #0000
_TCPIPGetConnectStatus
pla
cmp #$0000
bne tgood
PushLong #MarinettiBad
jsr InfoDialog
bra tret
tgood PushLong #MarinettiGood
jsr InfoDialog
tret pla
rts
*
* Connect To Server
*
ConnectToSvr PushLong #$00000000 ; space for result
PushLong #CTSRect
_GetNewModalDialog
PullLong CTSWinPtr
PushLong CTSWinPtr
_BeginUpdate
PushLong CTSWinPtr
_DrawDialog
PushLong CTSWinPtr
_EndUpdate
PushLong #00000000
_TCPIPConnect ; make sure marinetti is connected
PushLong #00000000
_TCPIPGetMyIPAddress
plx
ply
PushWord #0000
phy
phx
PushLong #ascaddr
PushWord #0000
_TCPIPConvertIPToASCII ; convert our address to ASCII
pla
PushLong CTSWinPtr
PushWord #1360
PushLong #ascaddr
_SetIText ; show it
CTSLoop1 PushWord #0000 ; space for result
PushLong #00000000 ; nil filter
_ModalDialog
pla ; get item hit
cmp #2 ; Cancel?
beq CTSClose
cmp #1 ; Connect?
bne CTSLoop1
bra CTSConnect
CTSClose PushLong CTSWinPtr
_CloseDialog
rts
CTSConnect PushLong #00000000
PushLong CTSWinPtr
PushWord #0001
_GetControlDItem
plx
ply
PushWord #255
phy
phx
_HiliteControl ; dim/disable 'Connect' button
PushLong #00000000
PushLong CTSWinPtr
PushWord #1349
_GetControlDItem
plx
ply
PushWord #255
phy
phx
_HiliteControl ; dim/disable 'Address' text input
PushLong CTSWinPtr
PushWord #1349
PushLong #fqdnptr
_GetIText
PushWord CTSText4 ; preserve old length byte (word)
sep #$30
mx %11
lda fqdnptr
tax
clc
adc CTSText4
sta CTSText4
hostcopy lda fqdnptr,x
sta inhost-1,x
dex
bne hostcopy
rep #$30
mx %00
PushLong CTSWinPtr
PushWord #1350
PushLong #CTSText4
_SetIText ; show 'resolving' status string
pla
sta CTSText4
PushWord #0000
PushWord #$F800
PushLong #fqdnptr
_TCPIPMangleDomainName ; mangle entered domain name
pla ; port number; trash
PushWord #0000
PushLong #fqdnptr
_TCPIPValidateIPString
pla
beq resolve ; engage DNS if this wasn't an ip address
PushLong #ipaddrip
PushLong #fqdnptr
_TCPIPConvertIPToHex ; else just convert to long
bra Connect ; and on with the show
resolve PushLong #fqdnptr
PushLong #ipaddr
_TCPIPDNRNameToIP ; resolve fqdn
ResolvLoop PushWord #0000 ; check for mouse events (cancel)
PushWord #$0006 ; with _EventAvail
PushLong #EventRec ; because _ModalDialog will block
_EventAvail
pla
beq noevent
PushWord #0000
PushLong #00000000
_ModalDialog
pla
cmp #2
beq CTSClose2
noevent _TCPIPPoll
lda ipaddr
cmp #$0001
beq Connect ; continue to Connect if resolved okay
cmp #$0000
beq ResolvLoop ; pending; stay in 'Resolving' loop
bra CTSBadDNS
CTSClose2 PushLong CTSWinPtr
_CloseDialog
rts
CTSBadDNS PushLong CTSWinPtr
PushWord #1350
PushLong #CTSText5
_SetIText
bra CTSClose2
Connect PushWord #0000
PushLong ipaddrip
PushLong #destaddr
PushWord #0000
_TCPIPConvertIPToASCII
pla
PushWord CTSText6 ; preserve old length byte (word)
sep #$30
mx %11
lda destaddr
tax
clc
adc CTSText6
sta CTSText6
ipcopy lda destaddr,x
sta ascdest-1,x
dex
bne ipcopy
rep #$30
mx %00
PushLong CTSWinPtr
PushWord #1350
PushLong #CTSText6
_SetIText ; change status to 'Connecting'
pla
sta CTSText6 ; restore length byte
PushWord #0000 ; space for result
PushWord AppMMID ; our Memory Manager handle
PushLong ipaddrip ; ipaddress to connect to
PushWord #0445 ; try port 445 first
PushWord #0000 ; default TOS: 0000
PushWord #$0040 ; default TTL: 64
_TCPIPLogin
pla
sta MyIPID
PushWord #$0000
PushWord MyIPID
_TCPIPOpenTCP
pla
beq ConnectLoop
jmp CTSClose3
ConnectLoop PushWord #0000
PushWord #$0006
PushLong #EventRec
_EventAvail
pla
beq noevent2
PushWord #0000 ; space for result
PushLong #00000000 ; nil filter procedure
_ModalDialog
pla
cmp #2
bne noevent2
jmp CTSClose3
noevent2 _TCPIPPoll
PushWord #0000
PushWord MyIPID
PushLong #statbuf
_TCPIPStatusTCP
pla
beq notbroke
jmp CTSClose3 ; something broke
notbroke lda statbuf
cmp #$0004
beq estab
cmp #$0000
beq closed_trampoline
bra ConnectLoop
;
; SMB_Negot_Prot
;
estab PushLong CTSWinPtr
PushWord #1350
PushLong #CTSText9
_SetIText
PushLong MyIPID
jsr SMB_Init ; feed our Marinetti IPID into SMB system
PullLong MySMBHandle ; get back our SMB handle
PushLong MySMBHandle ; SMB_Negotiate wants our SMB handle
jsr SMB_Negotiate ; and hopefully we send a SMB Negotiate Protocol Request and get a response
bra ct_far
closed_trampoline jmp closed
ct_far
sendloop2 PushWord #0000
PushWord #$0006
PushLong #EventRec
_EventAvail
pla
beq noevent3
PushWord #0000
PushLong #00000000
_ModalDialog
pla
cmp #2
bne noevent3
jmp CTSClose3
noevent3 PushLong MySMBHandle
jsr SMB_Negotiate_Poll
pla ; get negotiation status
bcc sendloop2
;
; SMB_Setup_ANDX
;
login PushLong CTSWinPtr
PushWord #1350
PushLong #CTSTextB
_SetIText
PushLong MySMBHandle
jsr SMB_SetupAndX
sendloop3 PushWord #0000
PushWord #$0006
PushLong #EventRec
_EventAvail
pla
beq noevent4
PushWord #0000
PushLong #00000000
_ModalDialog
pla
cmp #2
bne noevent4
jmp CTSClose3
noevent4 PushLong MySMBHandle
jsr SMB_Setup_Poll
pla ; get negotiation status
bcc sendloop3
;
; SMB_Tree_ANDX
;
; fun fact: change 'treex' to 'tree' to coredump Merlin32 v1.0
; inside a65816_Line.c function CheckForDuplicatedLabel()
treex PushLong CTSWinPtr
PushWord #1350
PushLong #CTSTextC
_SetIText
PushLong MySMBHandle
jsr SMB_TreeAndX
sendloop4 PushWord #0000
PushWord #$0006
PushLong #EventRec
_EventAvail
pla
beq noevent5
PushWord #0000
PushLong #00000000
_ModalDialog
pla
cmp #2
bne noevent5
jmp CTSClose3
noevent5 PushLong MySMBHandle
jsr SMB_TreeX_Poll
pla
bcc sendloop4
;
; SMB_OpenFile
;
openf PushLong CTSWinPtr
PushWord #1350
PushLong #CTSTextC
_SetIText
PushLong MySMBHandle
PushLong #SMB_target_file
jsr SMB_OpenFile
sendloop5 PushWord #0000
PushWord #$0006
PushLong #EventRec
_EventAvail
pla
beq noevent6
PushWord #0000
PushLong #00000000
_ModalDialog
pla
cmp #2
bne noevent6
jmp CTSClose3
noevent6 PushLong MySMBHandle
jsr SMB_OpenFile_Poll
bcc sendloop5
tax
pla
phx ; save SFID
;
; SMB_ReadFile
;
readf PushLong CTSWinPtr
PushWord #1350
PushLong #CTSTextD
_SetIText
; SFID already on stack still
PushLong MySMBHandle
PushLong #$E12000 ; read buffer = SHR screen
PushLong #$8000 ; size of read buffer
PushLong #0000 ; offset into file
jsr SMB_ReadFile
sendloop6 PushWord #0000
PushWord #$0006
PushLong #EventRec
_EventAvail
pla
beq noevent7
PushWord #0000
PushLong #00000000
_ModalDialog
pla
cmp #2
bne noevent7
jmp CTSClose3
noevent7 PushLong MySMBHandle
jsr SMB_ReadFile_Poll
bcc sendloop6
;
; Display what was downloaded
;
; squish length byte a little closer to the string
lda SMB_input+SMB_header_size+25
xba
sta SMB_input+SMB_header_size+25
PushLong #SMB_input+SMB_header_size+26
jsr InfoDialog
jmp SMB_staging_brk
;
; Closed
;
closed PushLong CTSWinPtr
PushWord #1350
PushLong #CTSTextA
_SetIText
;
; Kill dialog window and TCPIP connection
;
CTSClose3 PushWord #MyIPID
_TCPIPLogout ; get rid of our IPID
PushLong CTSWinPtr ; and close the dialog window
_CloseDialog
rts
*
* Menu Dispatcher
*
MenuDispatch lda TaskData
and #$00ff
asl
tax
jsr (MenuDispatchTbl,x)
PushWord #0000
PushWord TaskData+2
_HiliteMenu
rts
*
* Information Dialog
*
InfoDialog plx ; preserve return address
PullLong dialogMsg
phx ; put return back on stack
pha ; room for result
PushLong #OurAlert ; pointer to dialog
PushLong #$0000
_NoteAlert
pla ; get the item selected
rts
*
* Non-DP Variables
*
QuitFlag dw 00,00
ScreenColorByte dw 00
MyIPID dw 00 ; Marinetti IPID
MySMBHandle dw 00,00 ; SMB driver handle
CTSWinPtr dw 00,00 ; Connect To Server grafport ptr
fqdnptr ds 101 ; 101 bytes for user-entered hostname
ipaddr dw 00 ; DNS resolution status
ipaddrip dw 00,00 ; Resolved IP address
ascaddr ds 16 ; My IP address, in ASCII
destaddr ds 16 ; Destination IP address, in ASCII
statbuf ds 2 ; TCP state, statbuf+0
ds 2 ; ICMP error code, statbuf+2
ds 4 ; sendq size, statbuf+4
ds 4 ; recvq size, statbuf+8
ds 4 ; dest ip
ds 2 ; dest port
ds 2 ; connection type
ds 2 ; accept count
readbuf ds 4 ; rrBuffCount
ds 4 ; rrBuffHandle
ds 2 ; rrMoreFlag
ds 2 ; rrPushFlag
ds 2 ; rrUrgentFlag
*
* Tool List
*
ToolList dw 15 ; Tool Count
dw 01,00 ; Tool Locator, any vers
dw 02,00 ; Memory Manager, any vers
dw 03,00 ; Misc Tools, any vers
dw 04,00 ; QuickDraw II, any vers
dw 06,00 ; Event Manager, any vers
dw 14,00 ; Window Manager, any vers
dw 16,00 ; Control Manager, any vers
dw 15,00 ; Menu Manager, any vers
dw 05,00 ; Desk Manager, any vers
dw 08,00 ; Sound Manager, any vers
dw 20,00 ; Line Edit, any vers
dw 21,00 ; Dialog Manager, any vers
dw 54,00 ; Marinetti, any vers
dw 128,00 ; HashTool, any vers (MD2/MD4/MD5/SHA1 hashing for NTLMv2)
dw 129,00 ; Crypto tool, any vers (DES for NTLMv1)
ToolListEnd
*
* Menu Structures
*
MenuDispatchTbl dw About
dw Quit
dw TCPIPTest
dw ConnectToSvr
MenuTbl dw 4 ; count
dw Menu1
dw Menu2
dw Menu3
dw Menu4
MenuTblEnd
Menu1 asc '>>@\XN1'00
asc '--About This Program...\N256*??'00
asc '---\D'00
asc '>'
Menu2 asc '>> File \N2'00
asc '--Quit\N257*Qq'00
asc '>'
Menu3 asc '>> Edit \N3D'00
asc '--Undo\N250V*Zz'00
asc '--Cut\N251*Xx'00
asc '--Copy\N252*Cc'00
asc '--Paste\N253V*Vv'00
asc '--Clear\N254'00
asc '>'
Menu4 asc '>> Test \N4'00
asc '--TCP/IP Test\N258*Tt'00
asc '--Connect to Server\N259*Uu'00
asc '>'
*
* Event Record
*
EventRec
Event_What ds 2
Event_Msg ds 4
Event_When ds 4
Event_Where ds 4
Event_Mods ds 2
TaskData ds 4
TaskMask dw $1fff,$0000
*
* Strings
*
OneMoment asc 'One Moment Please...'00
MarinettiGood str 'Marinetti is Up.'
MarinettiBad str 'Marinetti is Not Up.'
AboutString str 'TCPIP Test Program'
But1 str 'OK'
*
* Connect To Server Dialog
*
CTSRect dw 30,120,120,520 ; bounds rect
CTSVis dw 0001 ; visible
CTSRef dw 0000,0000 ; refcon
CTSiptr1 adrl CTSItem1 ; string 'Host To Connect To'
CTSiptr2 adrl CTSItem2 ; edit line
CTSiptr3 adrl CTSItem3 ; connect button
CTSiptr4 adrl CTSItem4 ; cancel button
CTSiptr5 adrl CTSItem5 ; status line
CTSiptr6 adrl CTSItem6 ; My IP Address
CTSiptr7 adrl CTSItem7 ; "My Ip Address: "
dw 0000 ; end of the line
CTSItem1 dw 1348 ; id
dw 5,10,15,300 ; bounds
dw statText+$8000 ; type + disabled
adrl CTSText1
dw 00 ; item value
dw 00 ; item flag
adrl 00 ; end
CTSText1 str 'Address Of CIFS Server To Connect To:'
CTSItem2 dw 1349 ; id
dw 25,10,38,200 ; bounds
dw editLine
adrl CTSText2
dw 100
dw 00
adrl 00
CTSText2 str 'example.com'
CTSItem3 dw 1
dw 50,10,60,100
dw buttonItem
adrl But2
dw 00
dw 00
adrl 00
But2 str 'Connect'
CTSItem4 dw 2
dw 50,111,60,210
dw buttonItem
adrl But3
dw 00
dw 00
adrl 00
But3 str 'Cancel'
CTSItem5 dw 1350 ; id
dw 65,10,75,300 ; bounds
dw statText+$8000 ; type + disabled
adrl CTSText3
dw 00
dw 00
adrl 00
CTSText3 str 'Status: Awaiting Input'
CTSText4 str 'Status: Resolving Hostname '
inhost ds 101
CTSText5 str 'Status: Resolution Failure'
CTSText6 str 'Status: Connecting to '
ascdest ds 20
CTSText9 str 'Status: Connected, CIFS negotiating'
CTSTextA str 'Status: Connect Failed'
CTSTextB str 'Status: Logging In'
CTSTextC str 'Status: Mounting Share'
CTSTextD str 'Status: Opening \\testfile'
CTSTextE str 'Status: Reading testfile'
ascdata ds 100 ; we download this from testfile
CTSItem6 dw 1360 ; id
dw 77,120,87,300 ; bounds
dw statText+$8000
adrl CTSText7
dw 00
dw 00
adrl 00
CTSText7 str '0.0.0.0'
CTSItem7 dw 1361 ; id
dw 77,10,87,120 ; bounds
dw statText+$8000
adrl CTSText8
dw 00
dw 00
adrl 00
CTSText8 str 'My IP Address:'
*
* TCPIP Test Output Dialog
*
OurAlert dw 30,120,80,520 ; bounds rect
dw 2374 ; id
db $80
db $80
db $80
db $80
adrl item1
adrl item2
adrl 00
item1 dw 1 ; id
dw 25,320,0,0 ; bounds rect for button
dw buttonItem ; type
adrl But1 ; item descriptor
dw 00 ; item value
dw 00 ; item flag
adrl 00 ; item color
item2 dw 1348 ; id
dw 11,72,200,640 ; bounds rect for message
dw statText+$8000 ; type + disabled
dialogMsg adrl MarinettiGood ; item descriptor
dw 00 ; item value
dw 00 ; item flag
adrl 00 ; item color
*
* GS/OS Quit Params
*
QParams ds 4
ds 4
*** CIFS / SMB internals only past this point (will eventually be its own linker segment)
*
* SMB equates (should move into Library/E16.CIFS.Macs.s eventually)
*
* offsets into SMB header
SMB_offset_tcplength = 1 ; tcp length: all dgram length including header
SMB_offset_proto = 0+4
SMB_offset_cmd = 4+4
SMB_offset_ntstatus = 5+4
SMB_offset_eclass = 5+4
SMB_offset_flags = 9+4
SMB_offset_flags2 = 10+4
SMB_offset_extra = 12+4
SMB_offset_tid = 24+4
SMB_offset_pid = 26+4
SMB_offset_uid = 28+4
SMB_offset_mid = 30+4
SMB_header_size = 32+4 ; SMB headers are always 32 bytes long
* message / commands
NBT_session_msg = 00
SMB_neg_protocol = $72
SMB_setup_ANDX = $73
SMB_treec_ANDX = $75
* keepalive
NBT_keepalive_msg = $85
keepalive_size = 4
* SMBTrans2
SMB_trans2 = $32
SMB_open2 = 0
SMB_find_first2 = 1
SMB_find_next2 = 2
SMB_query_fs_info = 3
SMB_query_path_info = 5
SMB_set_path_info = 6
SMB_query_file_info = 7
SMB_set_file_info = 8
SMB_create_dir = 13
SMB_find_close2 = $34
SMB_query_file_all_info = $107
* File I/O
SMB_open_ANDX = $2d
SMB_write_ANDX = $2f
SMB_read_ANDX = $2e
SMB_close = $04
* SMB_COM
SMB_COM_create_directory = $00
SMB_COM_delete_directory = $01
SMB_COM_delete = $06
SMB_COM_rename = $07
SMB_COM_query_information_disk = $80
* TRANS2 offsets
T2_word_cnt = SMB_header_size
T2_prm_cnt = T2_word_cnt+1
T2_data_cnt = T2_prm_cnt+2
T2_maxprm_cnt = T2_data_cnt+2
T2_maxbuffer = T2_maxprm_cnt+2
T2_setup_cnt = T2_maxbuffer+2
T2_sprm_cnt = T2_setup_cnt+10
T2_sprm_ofs = T2_sprm_cnt+2
T2_sdata_cnt = T2_sprm_ofs+2
T2_sdata_ofs = T2_sdata_cnd+2
T2_ssetup_cnt = T2_sdata_ofs+2
T2_sub_cmd = T2_ssetup_cnt+2
T2_byte_cnt = T2_sub_cmd+2
SMB_proto1 = $53ff ; $ff + 'S'
SMB_proto2 = $424d ; 'MB'
SMB_max_net_read_size = 16384
SMB_max_net_write_size = 4096
SMB_max_transmit_size = 16384
CAP_large_files = $00000008 ; 64-bit file sizes and offsets supported
CAP_unicode = $00000004 ; unicode supported
CIFS_flags1 = $08 ; paths are caseless
CIFS_flags2_unicode = $8001 ; server may return long components in paths in the response - Unicode supported
CIFS_flags2 = $0001 ; server may return long components in paths in the response - ASCII supported
SMB_connhandles_max = 8
SMB_filehandles_max = (32*SMB_connhandles_max)
SMB_objtype_handle = 7
* NBT session service packet type codes
SESS_msg = $0
SESS_req = $81
SESS_pos_resp = $82
SESS_neg_resp = $83
SESS_retarget = $84
SESS_keepalive = $85
SMB_maxpath = 4096
* SMB error codes
SMB_success = 0
SMB_error = $ffff ; -1
SMB_bad_protocol = $fffe ; -2
SMB_bad_command = $fffd ; -3
SMB_proto_fail = $fffc ; -4
SMB_not_user = $fffb ; -5
SMB_bad_keylen = $fffa ; -6
SMB_bad_datalen = $fff9 ; -7
SMB_bad_logindata = $fff8 ; -8
* SMB file open function
SMB_of_open = 1
SMB_of_truncate = 2
SMB_of_create = 16
* FileSearch
SMB_srch_readonly = 1
SMB_srch_hidden = 2
SMB_srch_system = 4
SMB_srch_volume = 8
SMB_srch_directory = 16
SMB_srch_archive = 32
* SMB file access modes
SMB_open_reading = 0
SMB_open_writing = 1
SMB_open_readwrite = 2
SMB_open_compatible = 0
SMB_deny_readwrite = $10
SMB_deny_write = $20
SMB_deny_read = $30
SMB_deny_none = $40
*
* SMB variable space
*
* SMB DP variables
SMB_sessid = 8
SMB_tmp1 = 12
SMB_tmp2 = 14
SMB_tmp3 = 16
SMB_tmp4 = 18
SMB_tmp5 = 20
SMB_tmp6 = 22
SMB_tmp7 = 24
SMB_tmp8 = 26
* SMB session information
* TODO dynamically allocate these - see SMB_Init
SMB_sess_begin
SMB_sess_ipid dw 0 ; Marinetti IPID
SMB_sess_tid dw 0 ; SMB TID
SMB_sess_pid dw $dead ; SMB PID
SMB_sess_uid dw 0 ; SMB UID
SMB_sess_mid dw $0001 ; SMB MID
SMB_sess_skey dw 0,0 ; sKey
SMB_sess_caps dw 0,0 ; capabilities
SMB_sess_maxbuffer dw 0,0 ; max buffer
SMB_sess_seclvl dw 0 ; server security level
SMB_sess_maxmpx dw 0 ; server max pending outstanding requests
SMB_sess_maxvcs dw 0 ; server max virtual circuits
SMB_sess_challenge_used dw 0 ; challenge Used?
SMB_sess_challenge dw 0,0,0,0 ; challenge
SMB_sess_domain ds 32 ; sloppy 32 byte buffer to hold SMB domain
* Strings
SMB_dialect asc 02'NT LM 0.12'00 ; the only dialect we're gonna speak
SMB_os asc 'GS/OS'00 ; native Operating System
SMB_lanman asc 'Apple IIgs'00 ; native LAN Manager
SMB_lm_username asc 'PI'00,00,00,00,00,00,00,00,00,00,00,00 ; lanman hash login username
SMB_lm_password asc 'APPLE2'00,00,00,00,00,00,00,00 ; lanman hash login password
SMB_lm_magic asc 'KGS!@#$%' ; lanman hash magic DES crypt string
SMB_lm_hash ds 21 ; LM Hash, actually 16 bytes but the extra zeroes make response easier to generate
SMB_lm_response ds 24 ; LM Response
SMB_target_tree asc '\\LIVINGROOM\GSFILES'00 ; remote tree to connect to
SMB_target_svc asc '?????'00 ; service type (wildcard)
SMB_target_file asc '\TESTFILE'00 ; file to download
* SMB packet staging area
* TODO these will probably be dynamically allocated too?
* also SMB_max_transmit size should go up to 65535 and use an allocated bank like Marinetti does
SMB_staging_brk brk 00 ; jump here to crash somewhere where you can easily inspect the generated SMB datagram
SMB_staging ds SMB_max_transmit_size+2
SMB_input_brk brk 00
SMB_input ds SMB_max_net_read_size ; TODO Memory Manage this eh
*
* SMB Subroutines
*
* SMB_Init - Call me to tell me about your Marinetti IPID and get a session handle returned for future SMB calls
* Arguments:
* Marinetti IPID (one word, on stack)
* Returns:
* SMB session handle (two words, on stack)
* Carry flag set if error
* TODO: make this support multiple sessions in the future
SMB_Init plx ; return address
pla
sta SMB_sess_ipid
PushLong #SMB_sess_begin
phx ; saved return address
clc
rts
* SMB_Negotiate - Call me when you've opened a TCPIP connection and want to perform Negotiate Protocol Request
* Arguments:
* SMB session handle (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_Negotiate plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_neg_protocol ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
sep $30
mx %11
ldy #0
ldx #0
dialect_copy lda SMB_dialect,x ; 8-bit copy of dialect string into SMB staging area
beq dialect_done
sta SMB_staging+SMB_header_size+3,x
inx
iny
bra dialect_copy
dialect_done sta SMB_staging+SMB_header_size+3,x ; do write the trailing zero
inx
iny
rep $30
mx %00
tya
sta SMB_staging+SMB_header_size+1 ; save byte count
clc
adc #SMB_header_size+3
pha ; 'length' parameter for _SMB_Send
dec
dec
dec
dec
xba
sta SMB_staging+SMB_offset_tcplength+1 ; save length for naked-TCP dgram
jsr _SMB_Send
clc
rts
* SMB_Negotiate_Poll - Call me until I tell you to stop, to receive and complete SMB negotiation
* Arguments:
* SMB session handle (two words, on stack)
* Things I return on stack:
* Negotiation status (word)
* $0000 - Negotiation proceeding
* $0001 - Negotiation finished
* $0002 - Negotiation failed
* Carry flag set means you can stop calling me
SMB_Negotiate_Poll
plx ; our return address
PullLong SMB_sessid ; your smb sessid
phx
_TCPIPPoll
PushWord #0000 ; space for result
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; push Marinetti IPID for this SMB_sessid
PushLong #statbuf
_TCPIPStatusTCP ; see if marinetti has anything for us
pla
cmp #terrNOCONNECTION
beq nf_trampoline
cmp #terrBADIPID
beq nf_trampoline
lda statbuf+8 ; get recvq size, low word
cmp #0000 ; yeah i know. for clarity.
beq np_trampoline ; poll us again later, marinetti got nothing
PushWord #0000 ; space for result
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; push Marinetti IPID for this SMB_sessid
PushWord #0000 ; bufftype: static pre-allocated buffer
PushLong #SMB_input ; where it's all goin
PushLong #SMB_max_net_read_size
PushLong #readbuf
_TCPIPReadTCP
pla
cmp #terrNOCONNECTION
beq nf_trampoline
cmp #terrBADIPID
beq nf_trampoline
jsr _SMB_Check ; do basic check to make sure we received SMB data
bcs np_trampoline ; if not, wait for them to send again i guess
` lda SMB_input+SMB_offset_cmd
cmp #SMB_neg_protocol
bne np_trampoline ; punt if not protocol negotiation reply
lda SMB_input+SMB_offset_eclass
cmp #0000
bne nf_trampoline ; they returned an error, kbye
lda SMB_input+SMB_header_size
and #$ff
cmp #17
bne nf_trampoline ; they should always return 17 words
lda SMB_input+SMB_header_size
xba
and #$ff
cmp #00
bne nf_trampoline ; they should always select dialect 0
bra nft_far
nf_trampoline jmp nego_failed
np_trampoline jmp nego_proceeding
nft_far
lda SMB_input+SMB_header_size+3
and #$01
ldy #SMB_sess_seclvl-SMB_sess_begin
sta [SMB_sessid],y ; save session security level (1=user level, 0=share level)
lda SMB_input+SMB_header_size+4
and #$ff
ldy #SMB_sess_maxmpx-SMB_sess_begin
sta [SMB_sessid],y ; save session MaxMPX
lda SMB_input+SMB_header_size+6
and #$ff
ldy #SMB_sess_maxvcs-SMB_sess_begin
sta [SMB_sessid],y ; save session MaxVCS
lda SMB_input+SMB_header_size+8
ldy #SMB_sess_maxbuffer-SMB_sess_begin
sta [SMB_sessid],y ; save session maxbuffer
lda SMB_input+SMB_header_size+16
ldy #SMB_sess_skey-SMB_sess_begin
sta [SMB_sessid],y ; save skey
lda SMB_input+SMB_header_size+20
ldy #SMB_sess_caps-SMB_sess_begin
sta [SMB_sessid],y
iny
iny
lda SMB_input+SMB_header_size+22
sta [SMB_sessid],y ; save server capabilities
; TODO serverTime
lda SMB_input+SMB_header_size+33
and #$ff
cmp #8
bne challenge_used
cmp #0
bne nego_failed ; should be either 8 or zero
lda #$0000
ldy #SMB_sess_challenge_used
sta [SMB_sessid],y
bra getdomain
challenge_used lda #$0001
ldy #SMB_sess_challenge_used-SMB_sess_begin
sta [SMB_sessid],y
lda SMB_input+SMB_header_size+37
ldy #SMB_sess_challenge-SMB_sess_begin
sta [SMB_sessid],y
iny
iny
lda SMB_input+SMB_header_size+39
sta [SMB_sessid],y
iny
iny
lda SMB_input+SMB_header_size+41
sta [SMB_sessid],y
iny
iny
lda SMB_input+SMB_header_size+43
sta [SMB_sessid],y ; save 8-byte challenge
getdomain ldy #SMB_sess_domain-SMB_sess_begin
ldx #00
gdloop lda SMB_input+SMB_header_size+45,x
and #$00ff
cmp #0000
beq eod
sta [SMB_sessid],y ; if this looks off to you, see how
iny ; the domain name is actually encoded
inx ; W\00O\00R\00K\00G\00R\00O\00U\00P\00
inx
bra gdloop
eod sta [SMB_sessid],y ; save terminating zero
nego_finished plx ; our return address
PushWord #0001 ; finished!
phx
sec
rts
nego_failed plx ; our return address
PushWord #0002 ; failure
phx
sec
rts
nego_proceeding plx ; our return address
PushWord #0000 ; in progress
phx
clc
rts
*
* SMB_SetupAndX - Next step after negotiating protocol, includes authentication
* Arguments:
* SMB session handle (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_SetupAndX plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_setup_ANDX ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
sep $30
mx %11
lda #13
sta SMB_staging+SMB_header_size ; word count
lda #$ff
sta SMB_staging+SMB_header_size+1 ; next AndX
lda #00
sta SMB_staging+SMB_header_size+2 ; reserved
rep $30
mx %00
ldy #SMB_sess_maxbuffer-SMB_sess_begin
lda [SMB_sessid],y
sta SMB_staging+SMB_header_size+5 ; max buffer size
ldy #SMB_sess_maxmpx-SMB_sess_begin
lda [SMB_sessid],y
sta SMB_staging+SMB_header_size+7 ; max MPX
ldy #SMB_sess_maxvcs-SMB_sess_begin
lda [SMB_sessid],y
sta SMB_staging+SMB_header_size+9 ; max VCS
ldy #SMB_sess_skey-SMB_sess_begin
lda [SMB_sessid],y
sta SMB_staging+SMB_header_size+11 ; session key
lda #0
sta SMB_staging+SMB_header_size+13 ; session key (upper, should always be zero?)
lda #24
sta SMB_staging+SMB_header_size+15 ; password length (case insensitive)
lda #0
sta SMB_staging+SMB_header_size+17 ; password length (case sensitive/NTLM)
lda #0
sta SMB_staging+SMB_header_size+19 ; reserved
sta SMB_staging+SMB_header_size+21 ; reserved
ldy #SMB_sess_caps-SMB_sess_begin
lda [SMB_sessid],y
sta SMB_staging+SMB_header_size+23
iny
iny
lda [SMB_sessid],y
sta SMB_staging+SMB_header_size+25 ; session capabilities
jsr SMB_LM_Hash ; generate NTLMv1 Hash
jsr SMB_LM_Response ; generate NTLMv1 Response
lda #0
sta SMB_tmp5 ; initialize pointer
; Case Insensitive Password (LM Response)
PushLong #SMB_lm_response ; source
pea #^SMB_staging
lda #SMB_staging+SMB_header_size+29
clc
adc SMB_tmp5
pha
ldx #24
jsr _strncpy
lda #24
clc
adc SMB_tmp5
sta SMB_tmp5
; Case Sensitive Password (NTLM Response)
clc
adc #24
sta SMB_tmp5 ; skip it / zero it for now
; Account
PushLong #SMB_lm_username ; source
pea #^SMB_staging ; destination
lda #SMB_staging+SMB_header_size+29
clc
adc SMB_tmp5
pha
jsr _strcpy
tya
clc
adc SMB_tmp5
sta SMB_tmp5
; Domain
PushLong #SMB_sess_domain ; source
pea #^SMB_staging ; destination
lda #SMB_staging+SMB_header_size+29
clc
adc SMB_tmp5
pha
jsr _strcpy
tya
clc
adc SMB_tmp5
sta SMB_tmp5
; OS
PushLong #SMB_os ; source
pea #^SMB_staging ; destination
lda #SMB_staging+SMB_header_size+29
clc
adc SMB_tmp5
pha
jsr _strcpy
tya
clc
adc SMB_tmp5
sta SMB_tmp5
; LanMan
PushLong #SMB_lanman
pea #^SMB_staging ; destination
lda #SMB_staging+SMB_header_size+29
clc
adc SMB_tmp5
pha
jsr _strcpy
tya
clc
adc SMB_tmp5
sta SMB_tmp5
sta SMB_staging+SMB_header_size+27 ; update byte count
clc
adc #SMB_header_size+29
pha ; 'length' parameter for _SMB_Send
dec
dec
dec
dec
xba
sta SMB_staging+SMB_offset_tcplength+1 ; save length for naked-TCP dgram
jsr _SMB_Send ; send our reply!
clc
rts
* SMB_LM_Hash - operate on the SMB_lm_username and SMB_lm_password values to produce
* SMB_lm_hash, using V1 DES-based operation. Requires TOOL129 (Crypto Tool)
*
* The password has been uppercased and chopped to 14 bytes, with 0x00 padding
* We take it in two 7-byte pieces, add parity, and use each piece to DES-encrypt the string
* 'KGS!@#$%'. The result is the LM hash.
SMB_LM_Hash PushLong #SMB_tmp1 ; SMB_tmp1 will have our parity-enhanced key
PushLong #SMB_lm_password ; key to add parity to
Tool $0A81 ; DESAddParity
PushLong #SMB_lm_hash ; where DES-encrypted data will go
PushLong #SMB_tmp1 ; parity-enhanced key
PushLong #SMB_lm_magic ; the magic string we're encrypting
PushWord #0000 ; operation: encrypt
Tool $0981 ; DESCipher
; now do the same thing with the second 7 bytes of the password
PushLong #SMB_tmp1
PushLong #SMB_lm_password+7
Tool $0A81 ; DesAddParity
PushLong #SMB_lm_hash+8
PushLong #SMB_tmp1
PushLong #SMB_lm_magic
PushWord #0000
Tool $0981
; SMB_lm_hash should now contain the NTLMv1 hash of the password
clc
rts
* SMB_LM_Response - operate on SMB_lm_hash and 8-byte challenge to produce
* SMB_lm_response, using V1 DES-based operation. Requires TOOL129 (Crypto Tool)
*
* LM Hash is padded out to 21 bytes, each of which gets parity added and is
* used to DES encrypt the session challenge. The result is the LM response.
SMB_LM_Response
PushLong #SMB_tmp1 ; SMB_tmp1 will have our parity-enhanced key
PushLong #SMB_lm_hash ; key to add parity to
Tool $0A81 ; DESAddParity
PushLong #SMB_lm_response ; where the DES-encrypted data will go
PushLong #SMB_tmp1 ; parity-enhanced key
ldy #SMB_sess_challenge-SMB_sess_begin
lda [SMB_sessid],y ; PushLong [SMB_sessid],y
pha
iny
iny
lda [SMB_sessid],y
pha
PushWord #0000 ; operation: encrypt
Tool $0981 ; DESCipher
; second 7 bytes of hash
PushLong #SMB_tmp1
PushLong #SMB_lm_hash+7
Tool $0A81 ; DESAddParity
PushLong #SMB_lm_response+8
PushLong #SMB_tmp1
ldy #SMB_sess_challenge-SMB_sess_begin
lda [SMB_sessid],y ; PushLong [SMB_sessid],y
pha
iny
iny
lda [SMB_sessid],y
pha
PushWord #0000
Tool $0981 ; DESCipher
; third 7 bytes of hash
PushLong #SMB_tmp1
PushLong #SMB_lm_hash+14
Tool $0A81 ; DesAddParity
PushLong #SMB_lm_response+16
PushLong #SMB_tmp1
ldy #SMB_sess_challenge-SMB_sess_begin
lda [SMB_sessid],y
pha
iny
iny
lda [SMB_sessid],y
pha
PushWord #0000
Tool $0981 ; DESCipher
clc
rts
* SMB_Setup_Poll - Call me until I tell you to stop, to receive and complete SMB setup
* Arguments:
* SMB session handle (two words, on stack)
* Things I return on stack:
* Setup status (word)
* $0000 - Setup proceeding
* $0001 - Setup finished
* $0002 - Setup failed
* Carry flag set means you can stop calling me
SMB_Setup_Poll
plx ; our return address
PullLong SMB_sessid ; your smb sessid
phx
_TCPIPPoll
PushWord #0000 ; space for result
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; push Marinetti IPID for this SMB_sessid
PushLong #statbuf
_TCPIPStatusTCP ; see if marinetti has anything for us
pla
cmp #terrNOCONNECTION
beq sf_trampoline
cmp #terrBADIPID
beq sf_trampoline
lda statbuf+8 ; get recvq size, low word
cmp #0000 ; yeah i know. for clarity.
beq sp_trampoline ; poll us again later, marinetti got nothing
PushWord #0000 ; space for result
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; push Marinetti IPID for this SMB_sessid
PushWord #0000 ; bufftype: static pre-allocated buffer
PushLong #SMB_input ; where it's all goin
PushLong #SMB_max_net_read_size
PushLong #readbuf
_TCPIPReadTCP
pla
cmp #terrNOCONNECTION
beq sf_trampoline
cmp #terrBADIPID
beq sf_trampoline
jsr _SMB_Check ; do basic check to make sure we received SMB data
bcs sp_trampoline ; if not, wait for them to send again i guess
bra sft_far
sf_trampoline jmp setup_failed
sp_trampoline jmp setup_proceeding
sft_far
lda SMB_input+SMB_offset_cmd
cmp #SMB_setup_ANDX
bne sp_trampoline ; punt if not setup_ANDX reply
lda SMB_input+SMB_offset_eclass
cmp #0000
bne sf_trampoline ; they returned an error, kbye
lda SMB_input+SMB_offset_uid
ldy #SMB_sess_uid-SMB_sess_begin
sta [SMB_sessid],y ; save returned UID
* TODO save far end's OS, Lan Manager, and Workgroup?
setup_finished plx ; our return address
PushWord #0001 ; finished!
phx
sec
rts
setup_failed plx ; our return address
PushWord #0002 ; failure
phx
sec
rts
setup_proceeding
plx ; our return address
PushWord #0000 ; in progress
phx
clc
rts
*
* SMB_TreeAndX - Connect to the remote share
* Arguments:
* SMB session handle (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_TreeAndX plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_treec_ANDX ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
sep $30
mx %11
lda #4
sta SMB_staging+SMB_header_size ; word count
lda #$ff
sta SMB_staging+SMB_header_size+1 ; next AndX
rep $30
mx %00
lda #0000
sta SMB_staging+SMB_header_size+3 ; reserved
lda #0000
sta SMB_staging+SMB_header_size+5 ; flags
lda #1
sta SMB_staging+SMB_header_size+7 ; password length (1 if user-level security)
lda #0
sta SMB_tmp5 ; initialize pointer
; Share password
lda #00
sta SMB_staging+SMB_header_size+11 ; 0x00 (nul password, no share level security)
inc SMB_tmp5
; Target Tree
PushLong #SMB_target_tree
pea #^SMB_staging ; destination
lda #SMB_staging+SMB_header_size+11
clc
adc SMB_tmp5
pha
jsr _strcpy
tya
clc
adc SMB_tmp5
sta SMB_tmp5
; Target Service Type
PushLong #SMB_target_svc
pea #^SMB_staging ; destination
lda #SMB_staging+SMB_header_size+11
clc
adc SMB_tmp5
pha
jsr _strcpy
tya
clc
adc SMB_tmp5
sta SMB_tmp5
sta SMB_staging+SMB_header_size+9 ; update byte count
clc
adc #SMB_header_size+11
pha ; 'length' parameter for _SMB_Send
dec
dec
dec
dec
xba
sta SMB_staging+SMB_offset_tcplength+1 ; save length for naked-TCP dgram
jsr _SMB_Send ; send our reply!
clc
rts
* SMB_TreeX_Poll - Call me until I tell you to stop, to receive and complete SMB Tree_ANDX
* Arguments:
* SMB session handle (two words, on stack)
* Things I return on stack:
* Setup status (word)
* $0000 - Setup proceeding
* $0001 - Setup finished
* $0002 - Setup failed
* Carry flag set means you can stop calling me
SMB_TreeX_Poll
plx ; our return address
PullLong SMB_sessid ; your smb sessid
phx
_TCPIPPoll
PushWord #0000 ; space for result
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; push Marinetti IPID for this SMB_sessid
PushLong #statbuf
_TCPIPStatusTCP ; see if marinetti has anything for us
pla
cmp #terrNOCONNECTION
beq tf_trampoline
cmp #terrBADIPID
beq tf_trampoline
lda statbuf+8 ; get recvq size, low word
cmp #0000 ; yeah i know. for clarity.
beq tp_trampoline ; poll us again later, marinetti got nothing
PushWord #0000 ; space for result
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; push Marinetti IPID for this SMB_sessid
PushWord #0000 ; bufftype: static pre-allocated buffer
PushLong #SMB_input ; where it's all goin
PushLong #SMB_max_net_read_size
PushLong #readbuf
_TCPIPReadTCP
pla
cmp #terrNOCONNECTION
beq tf_trampoline
cmp #terrBADIPID
beq tf_trampoline
jsr _SMB_Check ; do basic check to make sure we received SMB data
bcs tp_trampoline ; if not, wait for them to send again i guess
bra tft_far
tf_trampoline jmp treex_failed
tp_trampoline jmp treex_proceeding
tft_far
lda SMB_input+SMB_offset_cmd
cmp #SMB_treec_ANDX
bne tp_trampoline ; punt if not setup_ANDX reply
lda SMB_input+SMB_offset_eclass
cmp #0000
bne tf_trampoline ; they returned an error, kbye
lda SMB_input+SMB_offset_tid
ldy #SMB_sess_tid-SMB_sess_begin
sta [SMB_sessid],y ; save returned TID
* TODO save remote servicetype or filesystem type?
treex_finished plx ; our return address
PushWord #0001 ; finished!
phx
sec
rts
treex_failed plx ; our return address
PushWord #0002 ; failure
phx
sec
rts
treex_proceeding
plx ; our return address
PushWord #0000 ; in progress
phx
clc
rts
*
* SMB_OpenFile - Open a file on the remote share
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to filename (two words, on stack)
* Things I return on stack:
* A = SMB filehandle id
* Carry flag set if error
SMB_OpenFile plx ; return address
PullLong SMB_tmp7 ; filename
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_open_ANDX ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
sep $30
mx %11
lda #15
sta SMB_staging+SMB_header_size ; word count
lda #$ff
sta SMB_staging+SMB_header_size+1 ; next AndX
lda #$00
sta SMB_staging+SMB_header_size+2 ; AndX Reserved
rep $30
mx %00
lda #$0000
sta SMB_staging+SMB_header_size+3 ; AndX Offset
lda #$0000
sta SMB_staging+SMB_header_size+5 ; Flags
lda #SMB_open_reading
sta SMB_staging+SMB_header_size+7 ; Access Mode
lda #0000
sta SMB_staging+SMB_header_size+9 ; SearchAttrib (6 = HIDDEN & SYSTEM?)
lda #0000
sta SMB_staging+SMB_header_size+11 ; file attributes
lda #0000
sta SMB_staging+SMB_header_size+13 ; file time (don't care, let server decide)
sta SMB_staging+SMB_header_size+15
lda #SMB_of_open
sta SMB_staging+SMB_header_size+17 ; openmode
lda #0000
sta SMB_staging+SMB_header_size+19 ; allocation size
lda #0000
sta SMB_staging+SMB_header_size+21 ; allocation size
lda #0000
sta SMB_staging+SMB_header_size+23 ; timeout
lda #0000
sta SMB_staging+SMB_header_size+25 ; timeout
lda #0000
sta SMB_staging+SMB_header_size+27 ; reserved[0] must be zero
lda #0000
sta SMB_staging+SMB_header_size+29 ; reserved[1] must be zero
lda #0000
sta SMB_staging+SMB_header_size+31 ; byte count
lda #0
sta SMB_tmp5 ; initialize pointer
; Target File
PushLong SMB_tmp7 ; source
pea #^SMB_staging ; destination
lda #SMB_staging+SMB_header_size+33
clc
adc SMB_tmp5
pha
jsr _strcpy
tya
clc
adc SMB_tmp5
sta SMB_tmp5
sta SMB_staging+SMB_header_size+31 ; update byte count
clc
adc #SMB_header_size+33
pha ; 'length' parameter for _SMB_Send
dec
dec
dec
dec
xba
sta SMB_staging+SMB_offset_tcplength+1 ; save length for naked-TCP dgram
jsr _SMB_Send ; send our reply!
clc
rts
* SMB_OpenFile_Poll - Call me until I tell you to stop, to receive and complete SMB Tree_ANDX
* Arguments:
* SMB session handle (two words, on stack)
* Things I return on stack:
* Setup status (word)
* $0000 - Setup proceeding
* $0001 - Setup finished
* $0002 - Setup failed
* Carry flag set means you can stop calling me
SMB_OpenFile_Poll
plx ; our return address
PullLong SMB_sessid ; your smb sessid
phx
_TCPIPPoll
PushWord #0000 ; space for result
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; push Marinetti IPID for this SMB_sessid
PushLong #statbuf
_TCPIPStatusTCP ; see if marinetti has anything for us
pla
cmp #terrNOCONNECTION
beq of_trampoline
cmp #terrBADIPID
beq of_trampoline
lda statbuf+8 ; get recvq size, low word
cmp #0000 ; yeah i know. for clarity.
beq op_trampoline ; poll us again later, marinetti got nothing
PushWord #0000 ; space for result
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; push Marinetti IPID for this SMB_sessid
PushWord #0000 ; bufftype: static pre-allocated buffer
PushLong #SMB_input ; where it's all goin
PushLong #SMB_max_net_read_size
PushLong #readbuf
_TCPIPReadTCP
pla
cmp #terrNOCONNECTION
beq of_trampoline
cmp #terrBADIPID
beq of_trampoline
jsr _SMB_Check ; do basic check to make sure we received SMB data
bcs op_trampoline ; if not, wait for them to send again i guess
bra oft_far
of_trampoline jmp openx_failed
op_trampoline jmp openx_proceeding
oft_far
lda SMB_input+SMB_offset_cmd
cmp #SMB_open_ANDX
bne op_trampoline ; punt if not setup_ANDX reply
lda SMB_input+SMB_offset_eclass
cmp #0000
bne of_trampoline ; they returned an error, kbye
lda SMB_input+SMB_header_size+5 ; saved returned sfid
openx_finished plx ; our return address
PushWord #0001 ; finished!
phx
sec
rts
openx_failed plx ; our return address
PushWord #0002 ; failure
phx
sec
rts
openx_proceeding
plx ; our return address
PushWord #0000 ; in progress
phx
clc
rts
*
* SMB_CloseFile - Close an open file on the remote share
* Arguments:
* SMB session handle (two words, on stack)
* A = SMB filehandle id
* Things I return on stack:
* Carry flag set if error
SMB_CloseFile plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_close ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
* TODO
rts
*
* SMB_CreateDirectory - Create a directory on the remote share
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to filename (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_CreateDirectory
plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_COM_create_directory ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
* TODO
rts
*
* SMB_DeleteDirectory - Delete a directory on the remote share
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to filename (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_DeleteDirectory
plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_COM_delete_directory ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
* TODO
rts
*
* SMB_DeleteFile - Delete a file on the remote share
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to filename (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_DeleteFile plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_COM_delete ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
* TODO
rts
*
* SMB_RenameFile - Rename a file on the remote share
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to old filename (two words, on stack)
* Long pointer to new filename (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_RenameFile plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_COM_rename ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
* TODO
rts
*
* SMB_DiskInformation - Get information about the remote share
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to disk statbuf (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_DiskInformation
plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_COM_query_information_disk ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
* TODO
rts
*
* SMB_ReadFile - Read an open file from the remote share
* Arguments:
* SFID of open file (one word, on stack)
* SMB session handle (two words, on stack)
* Long pointer to read buffer (two words, on stack)
* Size of read buffer (two words, on stack)
* Offset into file (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_ReadFile plx ; return address
PullLong SMB_tmp7 ; SMB_tmp7/SMB_tmp8 = offset
PullLong SMB_tmp5 ; SMB_tmp5/SMB_tmp6 = sizeof read_buffer
PullLong SMB_tmp3 ; SMB_tmp3/SMB_tmp4 = *read_buffer
PullLong SMB_sessid
PullWord SMB_tmp1 ; SMB_tmp1 = SFID
phx ; saved return address
PushWord #SMB_read_ANDX ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
sep $30
mx %11
lda #12
sta SMB_staging+SMB_header_size ; word count
lda #$ff
sta SMB_staging+SMB_header_size+1 ; next AndX
lda #$00
sta SMB_staging+SMB_header_size+2 ; AndX Reserved
rep $30
mx %00
lda #$0000
sta SMB_staging+SMB_header_size+3 ; AndX Offset
lda SMB_tmp1
sta SMB_staging+SMB_header_size+5 ; SFID
lda SMB_tmp7
sta SMB_staging+SMB_header_size+7 ; Offsetlow
lda SMB_tmp8
sta SMB_staging+SMB_header_size+9 ; Offsetlow2
lda #1024
sta SMB_staging+SMB_header_size+11 ; maxcountbytestoreturn
lda #0000
sta SMB_staging+SMB_header_size+13 ; mincountbytestoreturn
lda #0000
sta SMB_staging+SMB_header_size+15 ; timeout
lda #0000
sta SMB_staging+SMB_header_size+17 ; timeout2
lda #0000
sta SMB_staging+SMB_header_size+19 ; remaining
lda #0000
sta SMB_staging+SMB_header_size+21 ; offsethigh
lda #0000
sta SMB_staging+SMB_header_size+23 ; offsethigh2
lda #0000
sta SMB_staging+SMB_header_size+25 ; byte count (always 0)
clc
adc #SMB_header_size+27
pha ; 'length' parameter for _SMB_Send
dec
dec
dec
dec
xba
sta SMB_staging+SMB_offset_tcplength+1 ; save length for naked-TCP dgram
jsr _SMB_Send ; send our reply!
clc
rts
* SMB_ReadFile_Poll - Call me until I tell you to stop, to receive and complete SMB Tree_ANDX
* Arguments:
* SMB session handle (two words, on stack)
* Things I return on stack:
* Setup status (word)
* $0000 - Setup proceeding
* $0001 - Setup finished
* $0002 - Setup failed
* Carry flag set means you can stop calling me
SMB_ReadFile_Poll
plx ; our return address
PullLong SMB_sessid ; your smb sessid
phx
_TCPIPPoll
PushWord #0000 ; space for result
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; push Marinetti IPID for this SMB_sessid
PushLong #statbuf
_TCPIPStatusTCP ; see if marinetti has anything for us
pla
cmp #terrNOCONNECTION
beq rf_trampoline
cmp #terrBADIPID
beq rf_trampoline
lda statbuf+8 ; get recvq size, low word
cmp #0000 ; yeah i know. for clarity.
beq rp_trampoline ; poll us again later, marinetti got nothing
PushWord #0000 ; space for result
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; push Marinetti IPID for this SMB_sessid
PushWord #0000 ; bufftype: static pre-allocated buffer
PushLong #SMB_input ; where it's all goin
PushLong #SMB_max_net_read_size
PushLong #readbuf
_TCPIPReadTCP
pla
cmp #terrNOCONNECTION
beq rf_trampoline
cmp #terrBADIPID
beq rf_trampoline
jsr _SMB_Check ; do basic check to make sure we received SMB data
bcs rp_trampoline ; if not, wait for them to send again i guess
bra rft_far
rf_trampoline jmp readx_failed
rp_trampoline jmp readx_proceeding
rft_far
lda SMB_input+SMB_offset_cmd
cmp #SMB_read_ANDX
bne rp_trampoline ; punt if not read_ANDX reply
lda SMB_input+SMB_offset_eclass
cmp #0000
bne rf_trampoline ; they returned an error, kbye
; TODO something
readx_finished plx ; our return address
PushWord #0001 ; finished!
phx
sec
rts
readx_failed plx ; our return address
PushWord #0002 ; failure
phx
sec
rts
readx_proceeding
plx ; our return address
PushWord #0000 ; in progress
phx
clc
rts
*
* SMB_WriteFile - Write to an open file from the remote share
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to data buffer (two words, on stack)
* Size of data buffer (two words, on stack)
* Offset into file (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_WriteFile plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_write_ANDX ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
* TODO
rts
*
* SMB_PathInfo - Get information about a file/path on the remote share
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to pathname (two words, on stack)
* Long pointer to smb direntry struct buffer (two words, on stack)
* Things I return on stack:
* Carry flag set if error
SMB_PathInfo plx ; return address
PullLong SMB_sessid
phx ; saved return address
PushWord #SMB_query_path_info ; command
PushWord #CIFS_flags1 ; flags1
PushWord #CIFS_flags2 ; flags2
jsr _InitSMBHeader ; make an SMB header with this information
* TODO
rts
*
* SMB_FindFirst - Find first file in a directory listing
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to pathname (two words, on stack)
* Flags (one word, on stack)
* Long pointer to smb direntry struct buffer (two words, on stack)
* Things I return on stack:
* Carry flag set if error
* TODO TRANS2 call
*
* SMB_FindNext - Find next file in a directory listing
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to smb direntry struct buffer (two words, on stack)
* Things I return on stack:
* Carry flag set if error
* TODO TRANS2 call
*
* SMB_FindClose - Close a directory listing
* Arguments:
* SMB session handle (two words, on stack)
* Long pointer to smb direntry struct buffer (two words, on stack)
* Things I return on stack:
* Carry flag set if error
* TODO TRANS2 call
*
* Internal subroutines for SMB stuff
*
* _strcpy - Copy a string somewhere...
* Arguments:
* Pointer to source (two words, on stack)
* Pointer to destination (two words, on stack)
* returns:
* Y = number of bytes copied (including terminating zero)
_strcpy plx
PullLong SMB_tmp1 ; Destination
PullLong SMB_tmp3 ; Source
phx
ldy #00
sep #$30
mx %11
_sclp lda [SMB_tmp3],y
sta [SMB_tmp1],y
cmp #00
beq _scrt
iny
bra _sclp
_scrt rep #$30
mx %00
iny
rts
* _strncpy - Copy a string somewhere, only n bytes
* Arguments:
* Pointer to source (two words, on stack)
* Pointer to destination (two words, on stack)
* X = number of bytes to copy
_strncpy txy
plx
PullLong SMB_tmp1 ; Destination
PullLong SMB_tmp3 ; Source
phx
tyx
ldy #00
sep #$30
mx %11
_snclp lda [SMB_tmp3],y
sta [SMB_tmp1],y
dex
cpx #00
beq _sncrt
iny
bra _snclp
_sncrt rep #$30
mx %00
rts
* _SMB_Check - Check to see if TCP received data is SMB
_SMB_Check lda SMB_input+SMB_offset_proto
cmp #SMB_proto1
bne check_inv
lda SMB_input+SMB_offset_proto+2
cmp #SMB_proto2
bne check_inv ; starts with 'SMB'\ff
clc
rts
check_inv sec
rts
* _SMB_Send - Send the SMB datagram staging area out to Marinetti
* Arguments:
* length (word, pushed on stack first)
_SMB_Send plx ; save return address
PullWord SMB_tmp1
phx ; restore return address
lda #0
sta SMB_tmp2
PushWord #0000
ldy #SMB_sess_ipid-SMB_sess_begin
lda [SMB_sessid],y
pha ; IPID for Marinetti
PushLong #SMB_staging
PushLong SMB_tmp1 ; length
PushWord #0001 ; Samba sets PSH, so will I
PushWord #0000
_TCPIPWriteTCP
pla
rts
* _InitSMBHeader - Zero-out old SMB datagram data and start with some fresh header values
* Arguments:
* Command (word, pushed on stack first)
* Flags1 (word, pushed on stack second)
* Flags2 (word, pushed on stack third)
* Session Handle (already stored in DP SMB_sessid)
* Things I return on stack:
* Carry flag set if error
_InitSMBHeader ldx #00
lda #00
zero_loop sta SMB_staging,x ; loop to zero-out any old data from SMB header staging place
inx
inx
cpx #SMB_max_transmit_size
blt zero_loop
lda #SMB_proto1
sta SMB_staging+SMB_offset_proto
lda #SMB_proto2
sta SMB_staging+SMB_offset_proto+2 ; $FF + 'SMB' at start of header
ldy #SMB_sess_tid-SMB_sess_begin
lda [SMB_sessid],y
sta SMB_staging+SMB_offset_tid ; set session TID
ldy #SMB_sess_pid-SMB_sess_begin
lda [SMB_sessid],y
sta SMB_staging+SMB_offset_pid ; set session PID
ldy #SMB_sess_uid-SMB_sess_begin
lda [SMB_sessid],y
sta SMB_staging+SMB_offset_uid ; set session UID
ldy #SMB_sess_mid-SMB_sess_begin
lda [SMB_sessid],y
sta SMB_staging+SMB_offset_mid ; set session MID
plx ; save return address
pla ; flags2 (word)
sta SMB_staging+SMB_offset_flags2 ; set Flags2
pla ; flags1 (word, but written as byte)
ora SMB_staging+SMB_offset_flags
sta SMB_staging+SMB_offset_flags ; write one-byte value where it goes
pla ; command (word, but written as byte)
ora SMB_staging+SMB_offset_cmd
sta SMB_staging+SMB_offset_cmd ; write one-byte value where it goes
phx
rts