;----------------------------------------------------------------------------
;File name:	ICNN_EMU.S			Revision date:	2000.08.13
;Creator:	Ronald Andersson		Creation date:	2000.08.13
;----------------------------------------------------------------------------
	include	sting\transprt.i
	include	sting\layer.i
	include	sting\port.i
	include	sting\domain.i
;-------
	include	sting\bsd\socket.i
	include	sting\bsd\in.i
;-------
	include	sting\icnn\icglobal.i
;-------
	include	RA_LA.I
	include	RA_XB.I
	include	RA_RAM.I
;----------------------------------------------------------------------------
XB_cpu_mode	set	1	;never test mode or call Super in XB-macros
;----------------------------------------------------------------------------
	output	.PRG
;----------------------------------------------------------------------------
M_YEAR	=	2000
M_MONTH	=	8
M_DAY	=	3
;
M_TITLE		MACRO
		dc.b	'IConnect emulator'
		ENDM
M_VERSION	MACRO
		dc.b	'01.00'
		ENDM
M_AUTHOR	MACRO
		dc.b	'Ronald Andersson'
		ENDM
;----------------------------------------------------------------------------
RAM_chunk	= 65000			;The RAM we dispose over
MALLOC_TOTAL	= 60000			;The RAM we tell clients we have
;----------------------------------------------------------------------------
SFD_BASE	= $0400			;legal handle range is $1001..$10FF
SFD_FIRST	= (SFD_BASE+1)
SFD_POWER	= 8			;sfd table has (2^SFD_POWER) entries
SFD_LIM		= (1<<SFD_POWER)
SFD_MASK	= (SFD_LIM-1)
SFD_LONGS	= (1<<(SFD_POWER-5))
;----------------------------------------------------------------------------
HOSTENT_POWER	= 4			;log2(max_unique_hostents)
HOSTENT_LIM	= (1<<HOSTENT_POWER)	;max unique hostent structs
HOSTENT_MASK	= HOSTENT_LIM-1		;max index for hostent_t
IP_S_LIM	= 18			;max room for dotted IP strings
;----------------------------------------------------------------------------
TOS_NORMAL	= 0			;standard IP Type_Of_Service flag
TCP_BSIZE	= 16384
;----------------------------------------------------------------------------
SLOW_CONNECT	= 0			;0 or 1 for undelayed/TESTABLISH
SLOW_SELECT	= 0			;minimum timeout in milliseconds
;----------------------------------------------------------------------------
	struct	TIME_JOB
	struc_p	TJ_next
	struc_p	TJ_prev
	uint16	TJ_delay
	uint16	TJ_count
	func_p	TJ_func
	uint32	TJ_parm
	uint8	TJ_work_f
	uint8	TJ_resvd
	d_end	TIME_JOB
;----------------------------------------------------------------------------
;	Macro definitions for common time-critical needs
;----------------------------------------------------------------------------
;int16	open_c(CAB* cab_p, int16 proto)
;-------------------------------------
open_c	MACRO		cab_p,proto
	sub__open_c.\0	open_c,2,7,<\1>,<\2>,<\3>
	ENDM
;-------------------------------------
sub__open_c		MACRO	func,argc,argf,arg1,arg2
	PUREC_args.\0	\3,<\4>,<\5>,<\6>
	move.l		d3,-(sp)
	cmp		#IPPROTO_TCP,d0
	beq.s		.open_TCP_conn_\@
	cmp		#IPPROTO_UDP,d0
	beq.s		.open_UDP_conn_\@
.error_\@:
	moveq		#E_ERROR,d0
	bra		.open_c_exit_\@
;-------
.open_TCP_conn_\@:
	moveq		#TCP_ACTIVE,d0
	cmp		#INADDR_ANY,CAB_rhost(a0)
	bne.s		.connect_TCP_\@
	moveq		#TCP_PASSIVE,d0
.connect_TCP_\@:
	TCP_open	a0,d0,#TOS_NORMAL,#TCP_BSIZE
	move		d0,d3
	bmi.s		.open_c_exit_\@
	TCP_info	d3,set_defer_xxPIB(pc)		;switch connection mode
	tst		d0
	bpl.s		.open_c_exit_\@
	cmp		#E_LOCKED,d0
	beq.s		.open_c_exit_\@
	exg		d0,d3
	TCP_close	d0,!,!
	bra.s		.open_c_exit_\@
;-------
.open_UDP_conn_\@:
	UDP_open	a0,#UDP_EXTEND
	move		d0,d3
	bmi.s		.open_c_exit_\@
	UDP_info	d3,set_defer_xxPIB(pc)		;switch connection mode
	tst		d0
	bpl.s		.open_c_exit_\@
	cmp		#E_LOCKED,d0
	beq.s		.open_c_exit_\@
	exg		d0,d3
	UDP_close	d0
.open_c_exit_\@:
	move		d3,d0
	move.l		(sp)+,d3
.open_c_end_\@:
	PUREC_cleanargs	\1,\2
	ENDM
;----------------------------------------------------------------------------
;int16	close_c(int16 conn, int16 proto)
;-------------------------------------
close_c	MACRO		conn,proto
	sub__close_c.\0	close_c,2,5,<\1>,<\2>,<\3>
	ENDM
;-------------------------------------
sub__close_c		MACRO	func,argc,argf,arg1,arg2
	PUREC_args.\0	\3,<\4>,<\5>,<\6>
	cmp		#IPPROTO_TCP,d1
	beq.s		.close_TCP_conn_\@
	cmp		#IPPROTO_UDP,d1
	beq.s		.close_UDP_conn_\@
	moveq		#E_ERROR,d0
	bra.s		.close_c_end_\@
;-------
.close_TCP_conn_\@:
	TCP_close	d0,!,!
	bra.s		.close_c_end_\@
;-------
.close_UDP_conn_\@:
	UDP_close	d0
.close_c_end_\@:
	PUREC_cleanargs	\1,\2
	ENDM
;----------------------------------------------------------------------------
;int16	send_c(int16 conn, char *buf, int16 len, int16 proto)
;-------------------------------------
send_c	MACRO		conn,buf,len,proto
	sub__send_c.\0	send_c,4,$5D,<\1>,<\2>,<\3>,<\4>,<\5>
	ENDM
;-------------------------------------
sub__send_c		MACRO	func,argc,argf,arg1,arg2,arg3,arg4
	PUREC_args.\0	\3,<\4>,<\5>,<\6>,<\7>,<\8>
	cmp		#IPPROTO_TCP,d2
	beq.s		.send_TCP_\@
	cmp		#IPPROTO_UDP,d2
	beq.s		.send_UDP_\@
	moveq		#E_ERROR,d0
	bra.s		.send_c_end_\@
;-------
.send_TCP_\@:
	TCP_send	d0,(a0),d1
	bra.s		.send_c_end_\@
;-------
.send_UDP_\@:
	UDP_send	d0,(a0),d1
.send_c_end_\@:
	PUREC_cleanargs	\1,\2
	ENDM
;----------------------------------------------------------------------------
;int16	recv_c(int16 conn, char *buf, int16 len)
;-------------------------------------
recv_c	MACRO		conn,buf,len
	sub__recv_c.\0	recv_c,3,$1D,<\1>,<\2>,<\3>,<\4>
	ENDM
;-------------------------------------
sub__recv_c		MACRO	func,argc,argf,arg1,arg2,arg3,arg4
	PUREC_args.\0	\3,<\4>,<\5>,<\6>,<\7>
	movem.l		d0-d1/a0,-(sp)		;push work regs
	CNbyte_count	d0
	move		d0,d2
	movem.l		(sp)+,d0-d1/a0		;pull work regs
	exg		d0,d2
	ble.s		.recv_c_end_\@
	cmp		d0,d1
	bls.s		.keep_len_\@
	move		d0,d1
.keep_len_\@:
	CNget_block	d2,(a0),d1
.recv_c_end_\@:
	PUREC_cleanargs	\1,\2
	ENDM
;----------------------------------------------------------------------------
sfd_to_sock_p	MACRO	sfd,sock_p
	move		\1,d0
	sub		#SFD_FIRST,d0
	blt		.exit_E_IC_INVSFD
	cmp		#SFD_MASK,d0
	bhs		.exit_E_IC_INVSFD
	lsl		#2,d0
	lea		sfd_sock_pt(pc),a0
	move.l		(a0,d0),\2		;\2 -> EM_sock struct unless NULL
	move.l		\2,d0
	ble		.exit_E_IC_NOTSOCK
		ENDM
;----------------------------------------------------------------------------
	section	TEXT
;----------------------------------------------------------------------------
text_start:
basepage	=	(text_start-$100)
;----------------------------------------------------------------------------
start:
	bra	start_1
;----------------------------------------------------------------------------
;Start of:	Resident data
;----------------------------------------------------------------------------
my_layer:			;struct	LAYER
	dc.l	layer_name_s	;char_p	LAYER_name	;Name of layer
	dc.l	layer_version_s	;char_p	LAYER_version	;Version as xx.yy
	dc.l	0		;uint32	LAYER_flags	;Private data
	dc.w	((M_YEAR-1980)<<9)|(M_MONTH<<5)|M_DAY	;uint16	LAYER_date
	dc.l	layer_author_s	;char_p	LAYER_author	;Name of programmer
	dc.w	0		;int16	LAYER_stat_dropped	;dropped packets
	dc.l	0		;void_p	LAYER_next	;-> Next layer
basepage_p:
	dc.l	basepage	;void_p	LAYER_basepage	;-> basepage of self
;ND_layer struct end		;d_end	LAYER
;----------------------------------------------------------------------------
layer_name_s:
	M_TITLE
	dc.b	NUL
my_version_s:
layer_version_s:
	M_VERSION
	dc.b	NUL
my_author_s:
layer_author_s:
	M_AUTHOR
	dc.b	NUL
	EVEN
;----------------------------------------------------------------------------
SLIP_cookie_t:
	dc.l	host_IP		;-> host IP variable
	dc.l	main_API_t	;-> main API table
	dc.l	-1		;flags DNS operability
;----------------------------------------------------------------------------
main_API_t:
	dc.l	4		;00 API version, must be >= 3
	DC.L	IC_socket	;04
	dc.l	IC_bind		;08
	dc.l	IC_listen	;0C
	dc.l	IC_accept	;10
	dc.l	IC_connect	;14
	dc.l	IC_swrite	;18
	dc.l	IC_send		;1C
	dc.l	IC_sendto	;20
	dc.l	IC_sread	;24
	dc.l	IC_recv		;28
	dc.l	IC_recvfrom	;2C
	dc.l	IC_select	;30
	dc.l	IC_status	;34
	dc.l	IC_shutdown	;38
	dc.l	IC_sclose	;3C
	dc.l	IC_sfcntl	;40
	dc.l	IC_getsockopt	;44
	dc.l	IC_setsockopt	;48
	dc.l	IC_getsockname	;4C
	dc.l	IC_getpeername	;50
	dc.l	IC_res_init	;54
	dc.l	IC_res_query	;58
	dc.l	IC_res_search	;5C
	dc.l	IC_res_mkquery	;60
	dc.l	IC_res_send	;64
	dc.l	IC_dn_expand	;68
	dc.l	IC_dn_comp	;6C
	dc.l	usis_query	;70
;-------
	ds.l	16		;safety border	
;----------------------------------------------------------------------------
frame_size:		dc.w	6		;patched by init
frame_offset:		dc.w	0		;patched by init
;----------------------------------------------------------------------------
sting_drivers:	dc.l	0	;DRV_LIST	*sting_drivers;
tpl:		dc.l	0	;TPL		*tpl;
stx:		dc.l	0	;STX		*stx;
;----------------------------------------------------------------------------
currbp_p_p:		ds.l	1
kbshift_p:		ds.l	1
line_a_base_p:		ds.l	1
;-------
MiNT_p			ds.l	1
MagX_p			ds.l	1
nAES_p			ds.l	1
Gnva_p			ds.l	1
;----------------------------------------------------------------------------
;Start of:	XBRA linked gemdos dispatcher
;----------------------------------------------------------------------------
	XB_define	IC_gemdos_XB,'_MET'
	btst		#5,(sp)
	beq.s		.user_called
.super_called:
	lea		(sp),a0
	add		frame_size(pc),a0
	bra.s		.have_arg_p
;
.user_called:
	move		usp,a0
.have_arg_p:
	move		(a0),d0				;d0 = gemdos opcode
	move.b		IC_gemdos_func_f(pc,d0.w),d0
	bpl.s		IC_try_GD_func_1
IC_goto_old_gemdos:
	movea.l		IC_gemdos_XB+xb_next(pc),a0
	jmp		(a0)
;-------
IC_try_GD_func_1:
	cmp		#IC_gemdos_func_f_cnt,(a0)
	bhs.s		IC_goto_old_gemdos
	and		#$FE,d0				;d0 = code index
	move		IC_gemdos_func_t(pc,d0),d0	;d0 = code offset
	jmp		IC_gemdos_func_t(pc,d0)		;goto code
;----------------------------------------------------------------------------
;Start of:	IC_gemdos_func_t
;----------------------------------------------------------------------------
IC_gemdos_func_t:
	dc.w	IC_Pterm_xxx-IC_gemdos_func_t
;----------------------------------------------------------------------------
;End of:	IC_gemdos_func_t
;----------------------------------------------------------------------------
;Start of:	IC_gemdos_func_f
;----------------------------------------------------------------------------
IC_gemdos_func_f:
	dc.b	00,-1,-1,-1,-1,-1,-1,-1		;Pterm0
	dc.b	-1,-1,-1,-1,-1,-1,-1,-1
	dc.b	-1,-1,-1,-1,-1,-1,-1,-1
	dc.b	-1,-1,-1,-1,-1,-1,-1,-1
	dc.b	-1,-1,-1,-1,-1,-1,-1,-1
	dc.b	-1,-1,-1,-1,-1,-1,-1,-1
	dc.b	-1,00,-1,-1,-1,-1,-1,-1		;Ptermres
	dc.b	-1,-1,-1,-1,-1,-1,-1,-1
	dc.b	-1,-1,-1,-1,-1,-1,-1,-1
	dc.b	-1,-1,-1,-1,00,-1,-1,-1		;Pterm
	dcb.b	272,-1				;next opcode would be 352
IC_gemdos_func_f_end:
IC_gemdos_func_f_cnt	=	(IC_gemdos_func_f_end-IC_gemdos_func_f)
;----------------------------------------------------------------------------
;End of:	IC_gemdos_func_f
;----------------------------------------------------------------------------
IC_Pterm_xxx:
	movem.l		d1-d3/a1-a2,-(sp)
	move.l		currbp_p_p(pc),a0	;a0 -> p_run OS variable
	move.l		(a0),d3			;d3 -> basepage of APP
.active_sock_loop_1:
	move.l		active_sock_p(pc),d0
	ble.s		.done_active_socks
.active_sock_loop_2:
	move.l		d0,a0
	cmp.l		EMS_owner(a0),d3
	beq.s		.close_active_a0
	move.l		EMS_next(a0),d0
	bne.s		.active_sock_loop_2
	bra.s		.done_active_socks
;-------
.close_active_a0:
	move		EMS_sfd(a0),-(sp)
	pea		(NULL).w
	bsr		IC_sclose
	addq		#6,sp
	bra.s		.active_sock_loop_1
;-------
.done_active_socks:
.listen_sock_loop_1:
	move.l		listen_sock_p(pc),d0
	ble.s		.done_listen_socks
.listen_sock_loop_2:
	move.l		d0,a0
	cmp.l		EMS_owner(a0),d3
	beq.s		.close_listen_a0
	move.l		EMS_next(a0),d0
	bne.s		.listen_sock_loop_2
	bra.s		.done_listen_socks
;-------
.close_listen_a0:
	move		EMS_sfd(a0),-(sp)
	pea		(NULL).w
	bsr		IC_sclose
	addq		#6,sp
	bra.s		.listen_sock_loop_1
;-------
.done_listen_socks:
.exit_to_old_gemdos:
	movem.l		(sp)+,d1-d3/a1-a2
.goto_old_gemdos:
	movea.l		IC_gemdos_XB+xb_next(pc),a0
	jmp		(a0)
;----------------------------------------------------------------------------
;End of:	XBRA linked gemdos dispatcher
;----------------------------------------------------------------------------
;Start of:	my_timer_func called from STinG kernel in system interrupt
;----------------------------------------------------------------------------
my_timer_func:
	move.l		(_hz_200).w,d0
	move.l		d0,d3
	sub.l		last_IC_tic(pc),d3
	bne.s		IC_timer_work
	rts
;-------
IC_timer_work:
	move.l		d0,last_IC_tic
	lv_init		a6
	movem.l		d3/a2/a3,-(sp)
;-------
	lv_var.b	x_tcpib,sizeof_TCPIB
;-------------------------------------	start of:	listener operations
	move.l		listen_sock_p(pc),d0
	beq		.done_listeners
.listener_loop:
	move.l		d0,a3
	btst		#SS1_b_maxlisten,EMS_state1(a3)
	beq.s		.not_maxed_out
	move		EMS_back_cnt(a3),d0
	cmp		EMS_back_max(a3),d0
	bhi		.next_listener
	bclr		#SS1_b_maxlisten,EMS_state1(a3)
.not_maxed_out:
	btst		#SS0_b_opened,EMS_state0(a3)
	beq		.make_new_conn
	move.l		#TCPI_state,TCPIB_request+x_tcpib(a6)
	TCP_info	EMS_sfd(a3),x_tcpib(a6)		;get TCP state
	tst		d0				;network errors ?
	bpl.s		.check_state
	cmp		#E_LOCKED,d0
	beq		.next_listener
	move.l		a3,a0
	TCP_close	EMS_conn(a3),!,!
	bra.s		.make_new_conn
;-------
.check_state:
	move		TCPIB_state+x_tcpib(a6),d0	;d0 = TCP state
	cmp		#TLISTEN,d0
	beq		.next_listener
.make_accept_sock:
	move.l		a3,-(sp)			;push a3 -> listener
	bsr		create_EM_sock
	move.l		a3,a2				;a2 -> new socket
	move.l		(sp)+,a3			;a3 -> listener
	move.l		a3,a1
	move.l		a2,a0
	moveq		#((EMS_listener+3)/4-1),d0
.copy_loop:
	move.l		(a1)+,(a0)+
	dbra		d0,.copy_loop
	move.l		a3,EMS_listener(a2)
	protect_exec	(a2),insert_backed_sock(pc)
	move.b		#SS1_UNACCEPTED,EMS_state1(a2)
.make_new_conn:
	move.w		#SSW_NEWLISTEN,EMS_state_w(a3)
	lea		EMS_CAB(a3),a0
	TCP_open	a0,d0,#TOS_NORMAL,#TCP_BSIZE
	move		d0,d3
	bmi.s		.next_listener
	TCP_info	d3,set_defer_xxPIB(pc)		;switch connection mode
	move		d0,EMS_conn(a3)
	CNgetinfo	EMS_conn(a3)
	move.l		d0,EMS_CIB_p(a3)
	bset		#SS0_b_opened,EMS_state0(a3)
.next_listener:
	move.l		EMS_next(a3),d0
	bgt		.listener_loop
.done_listeners:
;-------------------------------------	end of:		listener operations
;-------------------------------------	start of:	timeout job polling
	move.l		TJ_root(pc),a0
	move.l		a0,d0
	ble.s		.done_tjobs
;-------
	suba.l		a2,a2
.test_tjob_loop:
	move.l		TJ_next(a0),a3
	cmpi.b		#$01,TJ_work_f(a0)
	bne.s		.test_next_tjob
	sub		d3,TJ_count(a0)
	bhi.s		.test_next_tjob
	bsr		exit_t_job
	move.b		#$02,TJ_work_f(a0)
	move.l		a2,TJ_next(a0)
	move.l		a0,a2
.test_next_tjob:
	move.l		a3,a0
	move.l		a0,d0
	bgt.s		.test_tjob_loop
.call_next_tjob:
	move.l		a2,d0
	ble.s		.done_tjobs
	move.l		a2,a0
	move.l		TJ_next(a0),a2
	move.l		TJ_func(a0),d0
	ble.s		.call_next_tjob
	move.l		d0,a1
	move.l		TJ_parm(a0),a0
	jsr		(a1)
	bra.s		.call_next_tjob
;-------
.done_tjobs:
;-------------------------------------	end of:		timeout job polling
	movem.l		(sp)+,d3/a2/a3
	lv_exit		a6
	rts					;return to STinG kernel
;----------------------------------------------------------------------------
;End of:	my_timer_func called from STinG kernel in system interrupt
;----------------------------------------------------------------------------
;Start of:	bitmap routines for socket file descriptors
;----------------------------------------------------------------------------
;void	release_sfd(int16 sfd);
;void	set_bit_in_map(int16 ix, uint32 *map);
;-------------------------------------
release_sfd:
	sub	#SFD_FIRST,d0	;d0 = sfd index
	blt.s	bad_setbit_index
	lea	sfd_map_t(pc),a0
set_bit_in_map:
	cmp	#SFD_MASK,d0
	bhs.s	bad_setbit_index
	move	d0,d1
	and	#$1F,d1
	sub	d1,d0
	lsr	#3,d0
	add	d0,a0
	move.l	(a0),d0		;fetch long
	bset	d1,d0		;set sfd availability bit
	move.l	d0,(a0)		;store long
	rts
;-------
bad_setbit_index:
	moveq	#E_IC_INVSFD,d0
	rts
;----------------------------------------------------------------------------
;allocate_bit		entry:	a0 -> map_base for 256 bits in 8 longs
;allocate_limited	entry:	a0 -> map_base  d1 = dbra_cnt_for_start
;allocate_indexed	entry:	a0 -> map_addr_for_start   a1 -> map_base
;				d1 =  dbra_cnt_for_start
;all cause result:		a0 -> map_addr_at_success  a1 -> map_base
;				d0 = bit_ix/err_code  d1 = dbra_cnt_at_success
;				d2 = dbra_cnt_at_success
;-------------------------------------
allocate_bit:
	move.l	#(SFD_LIM>>5)-1,d1
allocate_limited:
	move.l	a0,a1			;a1 -> map_base
allocate_indexed:
.loop:
	move.l	(a0)+,d0
	dbne	d1,.loop
	beq.s	.fail
	subq	#4,a0			;a0 = map_addr_at_success
	move	d1,d2			;d2 = dbra_cnt_at_success
	tst	d0
	bne.s	.boff_8_0
.boff_24_16:
	swap	d0
	tst.b	d0
	bne.s	.boff_16
.boff_24:
	lsr	#8,d0
	moveq	#24,d1
	bra.s	.calc_sfd_bit
;-------
.boff_16:
	moveq	#16,d1
	bra.s	.calc_sfd_bit
;-------
.boff_8_0:
	tst.b	d0
	bne.s	.boff_0
.boff_8:
	lsr	#8,d0
	moveq	#8,d1
	bra.s	.calc_sfd_bit
;-------
.boff_0:
	moveq	#0,d1
.calc_sfd_bit:
	and	#SFD_MASK,d0
	add.b	.low_bit_num_t(pc,d0),d1
	move.l	(a0),d0			;fetch long
	bclr	d1,d0			;clear sfd availability bit
	move.l	d0,(a0)			;store long
	move.l	a0,d0
	sub.l	a1,d0			;d0 = success_addr-map_base
	lsl	#3,d0			;d0 = number of success_long
	add	d1,d0			;d0 = total index of found bit
	move	d2,d1			;d1 = dbra_cnt at success
	rts
;-------
.fail:
	moveq	#E_IC_MANYSOCKS,d0
	rts
;-------
.low_bit_num_t:
;---------------0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f--------
	dc.b	0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;0x
	dc.b	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;1x
	dc.b	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;2x
	dc.b	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;3x
	dc.b	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;4x
	dc.b	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;5x
	dc.b	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;6x
	dc.b	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;7x
	dc.b	7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	:8x
	dc.b	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;9x
	dc.b	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;ax
	dc.b	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;bx
	dc.b	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;cx
	dc.b	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;dx
	dc.b	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;ex
	dc.b	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0	;fx
;----------------------------------------------------------------------------
sfd_map_t:
	dcb.l	(SFD_LONGS-1),$ffFFffFF
	dc.l	$7fFFffFF
;----------------------------------------------------------------------------
;End of:	bitmap routines for socket file descriptors
;----------------------------------------------------------------------------
;Start of:	Various data for IConnect API
;----------------------------------------------------------------------------
;	pointer table to translate from 'sfd' to corresponding 'EM_sock':
;-------------------------------------
sfd_sock_pt:	ds.l	SFD_LIM
;----------------------------------------------------------------------------
;	variables and structs for resolver:
;-------------------------------------
	struct	ext_hostent
	s_struc	he_hostent,hostent
	struc_p	he_owner
	char_p	he_addrip_p
	uint32	he_addrip_t
	uint32	he_end_mark
	d_end	ext_hostent
;-------------------------------------
etc_invalid_f:	dc.b	-1,NUL
etcdir_s:	ds.b	128
ICNN_EMU_IP_vns:	dc.b	'ICNN_EMU_IP',NUL
ICNN_EMU_ETC_vns:	dc.b	'ICNN_EMU_ETC',NUL
NAMESERVER_vns:		dc.b	'NAMESERVER',NUL
		EVEN
unknown_1:	dc.l	0
unknown_2:	dc.l	0
host_IP:	dc.l	0
dns1_IP:	dc.l	0
dns2_IP:	dc.l	0
hostent_ix:	dc.w	0					;cyclic index
hostent_t:	ds.b	(HOSTENT_LIM*(sizeof_ext_hostent))	;hostent structs
;----------------------------------------------------------------------------
;	Linked list roots:
;-------------------------------------
TJ_root:	dc.l	0
active_sock_p:	dc.l	0
listen_sock_p:	dc.l	0
mallocated_p:	dc.l	0	;each block has a prefix of owner.link (longs)
;----------------------------------------------------------------------------
;	Timing variables
;-------------------------------------
last_IC_tic:	dc.l	0
;----------------------------------------------------------------------------
;	structures for TCP_info and UDP_info
;-------------------------------------
ask_state_TCPIB:	dc.l	TCPI_state
			ds.b	sizeof_TCPIB-4
;-------
set_defer_xxPIB:	dc.l	TCPI_defer
			ds.b	sizeof_TCPIB-4
;----------------------------------------------------------------------------
;End of:	Various data for Iconnect SLIP API
;----------------------------------------------------------------------------
;Start of:	Iconnect SLIP API functions
;----------------------------------------------------------------------------
dummy_sub:
	moveq		#0,d0
	rts
;----------------------------------------------------------------------------
;int16	IC_clr_w_if_neg(int32 fop, int32 unkn1, int16 someword, void *unkn2);
;-------------------------------------
IC_clr_w_if_neg:
	move		12(sp),d0
	bpl.s		.keep_pos
	clr		d0
.keep_pos:
	rts
;----------------------------------------------------------------------------
;int16 IC_socket(int32 fop, int16 domain, int16 type, int16 proto);
;-------------------------------------
;Create a Iconnect socket and return the socket file descriptor
;-------------------------------------
IC_socket:
	lv_init	a6
	movem.l		d2-d3/a2-a3,-(sp)
;-------
	lv_arg.l	x_fop
	lv_arg.w	x_domain
	lv_arg.w	x_type
	lv_arg.w	x_proto
;-------
	lv_var.w	x_fixed_domain
	lv_var.w	x_fixed_type
	lv_var.w	x_fixed_proto
	lv_var.l	x_max_xfer
	lv_var.w	x_max_buff
;-------
.parm_check:
.fix_domain:
	move		x_domain(a6),d0		;also tests for AF_UNSPEC
	bne.s		.keep_domain
	move		#AF_INET,d0
	bra.s		.domain_fix
;-------
.keep_domain:
	cmp		#AF_INET,d0
	bne.s		.exit_E_IC_OPNOTSUPP
.domain_fix:
	move		d0,x_fixed_domain(a6)
.fix_type:
	move		x_type(a6),d0
	bne.s		.keep_type
	move		#SOCK_STREAM,d0
	bra.s		.type_fix
;-------
.keep_type:
	cmp		#SOCK_STREAM,d0
	beq.s		.type_fix
	cmp		#SOCK_DGRAM,d0
	bne.s		.exit_E_IC_OPNOTSUPP
.type_fix:
	move		d0,x_fixed_type(a6)
	move		#TCP_BSIZE/2,d2
	move.l		#$7FffFFff,d1
	cmp		#SOCK_STREAM,d0
	beq.s		.have_max_xfer
	move		#512,d2
	move.l		#512,d1
.have_max_xfer:
	move.l		d1,x_max_xfer(a6)
	move		d2,x_max_buff(a6)
.fix_proto:
	move		x_proto(a6),d0
	bne.s		.keep_proto
	move		x_fixed_type(a6),d1
	moveq		#IPPROTO_TCP,d0
	cmp		#SOCK_STREAM,d1
	beq.s		.proto_fix
	moveq		#IPPROTO_UDP,d0
	cmp		#SOCK_DGRAM,d1
	beq.s		.proto_fix
	bne.s		.exit_E_IC_OPNOTSUPP
;-------
.keep_proto:
	cmp		#IPPROTO_UDP,d0
	beq.s		.proto_fix
	cmp		#IPPROTO_TCP,d0
	beq.s		.proto_fix
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		IC_socket_exit
;-------
.proto_fix:
	move		d0,x_fixed_proto(a6)
.parm_check_done:
	bsr		create_EM_sock
	bmi.s		IC_socket_exit
	move		x_fixed_domain(a6),EMS_domain(a3)
	move		x_fixed_type(a6),EMS_type(a3)
	move		x_fixed_proto(a6),EMS_proto(a3)
	move.l		x_max_xfer(a6),EMS_max_xfer(a3)
	move		x_max_buff(a6),EMS_max_buff(a3)
	move		d3,d1
	sub		#SFD_FIRST,d1			;d1 = socket index
	asl		#2,d1
	lea		sfd_sock_pt(pc),a0
	move.l		a3,(a0,d1)
	protect_exec	(a3),insert_active_sock(pc)
	move		d3,d0
IC_socket_exit:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------------------------------------
;End of:	IC_socket
;----------------------------------------------------------------------------
;int IC_bind(int32 fop, int16 sfd, struct sockaddr *address, int16 len);
;-------------------------------------
IC_bind:
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.l	x_address
	lv_arg.w	x_len
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	move.l		x_address(a6),a1
	move.l		a1,d0
	ble.s		.exit_E_IC_OPNOTSUPP
	cmp		#AF_INET,sa_family(a1)
	bne.s		.exit_E_IC_OPNOTSUPP
	btst		#SS1_b_bound,EMS_state1(a3)
	bne.s		.exit_E_IC_OPNOTSUPP
	lea		EMS_CAB(a3),a2
	move		sin_port(a1),CAB_lport(a2)
	move.l		sin_addr(a1),CAB_lhost(a2)
	beq.s		.exit_E_IC_OPNOTSUPP
	cmp		#IPPROTO_UDP,EMS_type(a3)
	bne.s		.done_bind
	move.l		a3,a0
	bsr		open_EMS_conn
	bmi.s		.exit_d0
.done_bind:
	bset		#SS1_b_bound,EMS_state1(a3)
;-------
.exit_E_OK:
	moveq		#E_OK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
.exit_d0:
IC_bind_exit:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------------------------------------
;End of:	IC_bind
;----------------------------------------------------------------------------
;int16 IC_listen(int32 fop, int16 sfd, int16 backlog);
;-------------------------------------
IC_listen:
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.w	x_backlog
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	cmp		#SOCK_STREAM,EMS_type(a3)
	bne.s		.exit_E_IC_OPNOTSUPP
	cmp		#IPPROTO_TCP,EMS_proto(a3)
	bne.s		.exit_E_IC_OPNOTSUPP
	btst		#SS1_b_listening,EMS_state1(a3)
	bne.s		.exit_E_IC_ALREADY
	btst		#SS1_b_connected,EMS_state1(a3)
	bne.s		.exit_E_IC_ISCONN
	btst		#SS0_b_opened,EMS_state0(a3)
	bne.s		.have_EMS_conn
;-------
	clr.l		EMS_CAB+CAB_lhost(a3)
	move.l		a3,a0
	bsr		open_EMS_conn
	bmi.s		.exit_d0
.have_EMS_conn:
	bset		#SS1_b_listening,EMS_state1(a3)
	move		x_backlog(a6),EMS_back_max(a3)
	clr		EMS_back_cnt(a3)
	clr.l		EMS_backlist(a3)
	protect_exec	(a3),remove_active_sock(pc)
	protect_exec	(a3),insert_listen_sock(pc)
;-------
.exit_E_OK:
	moveq		#E_OK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_ISCONN:
	moveq		#E_IC_ISCONN,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_ALREADY:
	moveq		#E_IC_ALREADY,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
.exit_d0:
IC_listen_exit:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------------------------------------
;End of:	IC_listen
;----------------------------------------------------------------------------
;int16 IC_accept(int32 fop, int16 sfd, struct sockaddr *address, int16 *addrlen);
;-------------------------------------
IC_accept:
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.l	x_sockaddr_p
	lv_arg.l	x_addrlen_p
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
.loop:
	btst		#SS1_b_listening,EMS_state1(a3)
	beq		.exit_E_IC_OPNOTSUPP
	protect_exec	(a3),accept_backed_sock(pc)
	tst.l		d0
	bgt.s		.accept_sock
	btst		#SS0_b_opened,EMS_state0(a3)
	beq.s		.exit_E_IC_NOTCONN
	CNbyte_count	EMS_conn(a3)
	tst		d0
	bpl.s		.not_now
	cmp		#E_LISTEN,d0
	beq.s		.not_now
	cmp		#E_NODATA,d0
	beq.s		.not_now
	cmp		#E_LOCKED,d0
	bne.s		.exit_E_IC_PROTO
.not_now:
	btst		#SS2_b_NONBLOCK,EMS_state2(a3)
	beq.s		.loop
.exit_E_IC_AGAIN:
	moveq		#E_IC_AGAIN,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_PROTO:
	moveq		#E_IC_PROTO,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTCONN:
	moveq		#E_IC_NOTCONN,d0
	bra.s		.exit_d0
;-------
.accept_sock:
	move.l		d0,a3
	move.b		#SS1_ACCEPTED,EMS_state1(a3)
	move.l		EMS_CIB_p(a3),a0
	move.l		CIB_lhost(a0),EMS_CAB+CAB_lhost(a3)
	move		CIB_lport(a0),EMS_CAB+CAB_lport(a3)
	move.l		x_sockaddr_p(a6),a1
	move		#AF_INET,sin_family(a1)
	move.l		CIB_rhost(a0),d0
	move.l		d0,sin_addr(a1)
	move.l		d0,EMS_CAB+CAB_rhost(a3)
	move		CIB_rport(a0),d0
	move		d0,sin_port(a1)
	move		d0,EMS_CAB+CAB_rport(a3)
	clr.l		sin_zero(a1)
	clr.l		sin_zero+4(a1)
	move.l		x_addrlen_p(a6),a1
	move		#sizeof_sockaddr_in,(a1)
	move		EMS_sfd(a3),d0
.exit_d0:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
	bra.s		.exit_d0
;-------------------------------------
;End of:	IC_accept
;----------------------------------------------------------------------------
;int16 IC_connect(int32 fop, int16 sfd, struct sockaddr *remaddr_p, int16 len);
;-------------------------------------
IC_connect:
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
;-------
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.l	x_remaddr_p
	lv_arg.w	x_len
;-------
	lv_var.b	x_tcpib,sizeof_TCPIB
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	btst		#SS1_b_listening,EMS_state1(a3)
	bne		.exit_E_IC_ISCONN
	bset		#SS1_b_connected,EMS_state1(a3)
	beq.s		.new_connect
	cmp		#SOCK_DGRAM,EMS_type(a3)
	bne		.exit_E_IC_ISCONN
	cmp		#IPPROTO_UDP,EMS_proto(a3)
	bne.s		.new_connect
	bclr		#SS0_b_opened,EMS_state0(a3)
	beq.s		.new_connect
	UDP_close	EMS_conn(a3)
	clr		EMS_conn(a3)
.new_connect:
	btst		#SS0_b_opened,EMS_state0(a3)
	bne.s		.exit_E_OK
;-------
	move.l		x_remaddr_p(a6),a1
	cmp		#AF_INET,sa_family(a1)
	bne.s		.exit_E_IC_OPNOTSUPP
	lea		EMS_CAB(a3),a2
	move		sin_port(a1),CAB_rport(a2)
	move.l		sin_addr(a1),CAB_rhost(a2)
;-------
	move		EMS_proto(a3),d0
	cmp		#IPPROTO_UDP,d0
	beq.s		.open_STinG_conn
	cmp		#IPPROTO_TCP,d0
	bne.s		.exit_E_IC_OPNOTSUPP
.open_STinG_conn:
	move.l		a3,a0
	bsr		open_EMS_conn
	bmi.s		.exit_E_IC_PROTO
.open_conn_ok:
;-------
	IFNE		SLOW_CONNECT
;-------
	btst		#SS2_b_NONBLOCK,EMS_state2(a3)
	bne.s		.exit_E_OK
	cmp		#IPPROTO_TCP,EMS_proto(a3)
	bne.s		.exit_E_OK
.await_TESTABLISH:
	move.l		#TCPI_state,TCPIB_request+x_tcpib(a6)
	TCP_info	EMS_conn(a3),x_tcpib(a6)	;get TCP state
	tst		d0				;network errors ?
	bpl.s		.check_state
	cmp		#E_LOCKED,d0
	beq.s		.await_TESTABLISH
	bra.s		.exit_E_IC_PROTO
;-------
.check_state:
	move		TCPIB_state+x_tcpib(a6),d0	;d0 = TCP state
	cmp		#TLISTEN,d0
	beq.s		.exit_E_OK
	cmp		#TESTABLISH,d0
	blo.s		.await_TESTABLISH
;-------
	ENDC		;SLOW_CONNECT
;-------
.exit_E_OK:
	moveq		#E_OK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_AGAIN:
	moveq		#E_IC_AGAIN,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_ISCONN:
	moveq		#E_IC_ISCONN,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_PROTO:
	moveq		#E_IC_PROTO,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
.exit_d0:
IC_connect_exit:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------------------------------------
;End of:	IC_connect
;----------------------------------------------------------------------------
;int32 IC_swrite(int32 fop, int16 sfd, void *buf, int32 len );
;-------------------------------------
IC_swrite:
	moveq		#0,d0		;case 0 == write_socket
	bra.s		IC_send_xxx
;-------------------------------------
;int32 IC_send(int32 fop, int16 sfd, void *buf, int32 len, uint16 flags);
;-------------------------------------
IC_send:
	moveq		#1,d0		;case 1 == send
	bra.s		IC_send_xxx
;-------------------------------------
;int32 IC_sendto(int32 fop, int16 sfd, void *buf, int32 len, uint16 flags, struct sockaddr_in *addr, int16 addr_len);
;-------------------------------------
IC_sendto:
	moveq		#2,d0		;case 2 == sendto
IC_send_xxx:
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.l	x_buf_msg	;diff for IC_sendmsg
	lv_arg.l	x_blen_mflg	;diff for IC_sendmsg
	lv_arg.w	x_normflags	;not for IC_sendmsg or IC_write_socket
;-------
	lv_arg.l	x_to_addr	;only for IC_sendto
	lv_arg.w	x_to_addrlen	;only for IC_sendto
;-------
	lv_var.w	x_send_xxx_mode	;0..3:write_socket,send,sendto,sendmsg
	lv_var.l	x_iov_p		;struct iovec *iov_p
	lv_var.l	x_iov_cnt	;array entries at *iov_p
	lv_var.b	x_loc_iov,sizeof_iovec
	lv_var.w	x_flags		;uint16 flags
	lv_var.l	x_to_ad		;struct sockaddr *to_ad;
	lv_var.w	x_to_adlen	;int16 adlen;
	lv_var.l	x_msg_name	;void_p msg_name
	lv_var.l	x_msg_namelen	;uint32 msg_namelen
	lv_var.l	x_data_sent	;uint32 data_sent
;-------
	move		d0,x_send_xxx_mode(a6)
	add		d0,d0
	move		send_xxx_t(pc,d0),d0
	jmp		send_xxx_t(pc,d0)
;-------
send_xxx_t:
	dc.w		send_xxx_0-send_xxx_t
	dc.w		send_xxx_1-send_xxx_t
	dc.w		send_xxx_2-send_xxx_t
;-------
send_xxx_0:					;for IC_write_socket
	clr		x_flags(a6)
	bra.s		send_xxx_0_1
;
send_xxx_1:					;for IC_send
	move		x_normflags(a6),x_flags(a6)
send_xxx_0_1:
	clr.l		x_to_ad(a6)
	bra.s		send_xxx_0_1_2
;-------
send_xxx_2:					;for IC_sendto
	move.l		x_to_addr(a6),x_to_ad(a6)
	move		x_to_addrlen(a6),x_to_adlen(a6)
send_xxx_0_1_2:
	move.l		x_buf_msg(a6),x_loc_iov+iov_base(a6)
	move.l		x_blen_mflg(a6),x_loc_iov+iov_len(a6)
	lea		x_loc_iov(a6),a0
	move.l		a0,x_iov_p(a6)
	move.l		#1,x_iov_cnt(a6)
	clr.l		x_msg_name(a6)
send_xxx_common:
	clr.l		x_data_sent(a6)
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	btst		#SS1_b_listening,EMS_state1(a3)
	bne		.exit_E_IC_NOTCONN
	btst		#SS1_b_connected,EMS_state1(a3)
	bne.s		.already_connected
.not_connected:
	cmp		#SOCK_STREAM,EMS_type(a3)
	beq		.exit_E_IC_OPNOTSUPP
	cmp		#2,x_send_xxx_mode(a6)	;sendto call ?
	bne		.exit_E_IC_OPNOTSUPP
	move.l		x_to_ad(a6),a0
	move.l		a0,d0
	ble		.exit_E_IC_OPNOTSUPP
	cmp		#AF_INET,sa_family(a0)
	bne		.exit_E_IC_OPNOTSUPP
	cmp.l		#INADDR_ANY,sin_addr(a0)
	beq		.exit_E_IC_OPNOTSUPP
	move		sin_port(a0),EMS_CAB+CAB_rport(a3)
	move.l		sin_addr(a0),EMS_CAB+CAB_rhost(a3)
	move.l		a3,a0
	bsr		open_EMS_conn
	bmi		.exit_E_IC_PROTO
	bra.s		.conn_is_ready
;-------
.already_connected:
	cmp		#SOCK_STREAM,EMS_type(a3)
	beq.s		.conn_is_ready
	cmp		#2,x_send_xxx_mode(a6)	;sendto call ?
	bne.s		.conn_is_ready
.sendto_connected:
	move.l		x_to_ad(a6),a0
	move.l		a0,d0
	bne		.exit_E_IC_ISCONN
.conn_is_ready:
	tst.l		x_iov_cnt(a6)
	bgt		.first_iov		;for normal sending
	blt		.exit_E_IC_OPNOTSUPP	;for sick sendmsg
	bra		.exit_normal		;for empty sendmsg...
;-------
.send_iov:
	move.l		x_iov_p(a6),a0
	move.l		iov_base(a0),a2
	move.l		a2,d0
	ble.s		.send_error
	move.l		iov_len(a0),d3
	ble		.next_iov
	cmp.l		EMS_max_xfer(a3),d3
	bgt.s		.send_error
.send_block:
	clr.l		d2
	move		EMS_max_buff(a3),d2
	cmp.l		d2,d3
	bhs.s		.keep_size_d2
	move		d3,d2
.keep_size_d2:
.try_send:
	move		d2,-(sp)
	move		d2,d1
	send_c		EMS_conn(a3),(a2),d1,EMS_proto(a3)
	move		(sp)+,d2
	tst		d0
	bpl.s		.next_block
	cmp		#E_LOCKED,d0
	bne.s		.store_error
	btst		#SS2_b_NONBLOCK,EMS_state2(a3)
	beq.s		.try_send
.store_error:
	move		d0,EMS_last_err(a3)
.send_error:
	tst.l		x_data_sent(a6)
	bne.s		.exit_normal
	cmp		#E_LOCKED,EMS_last_err(a3)
	bne.s		.exit_E_IC_PROTO
	moveq		#E_IC_AGAIN,d0
	bra.s		.exit_d0
;
.next_block:
	and.l		#$ffff,d0
	add.l		d2,a2
	add.l		d2,x_data_sent(a6)
	sub.l		d2,d3
	bne		.send_block
.next_iov:
	addq.l		#8,x_iov_p(a6)
.first_iov:
	subq.l		#1,x_iov_cnt(a6)
	bpl		.send_iov
;-------
.exit_normal:
	move.l		x_data_sent(a6),d0
	bra.s		.exit_d0
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_PROTO:
	moveq		#E_IC_PROTO,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_ISCONN:
	moveq		#E_IC_ISCONN,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTCONN:
	moveq		#E_IC_NOTCONN,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
.exit_d0:
IC_send_xxx_exit:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;----------------------------------------------------------------------------
;int32 IC_sread(int32 fop, int16 sfd, void *buf, int32 len );
;-------------------------------------
IC_sread:
	moveq		#0,d0		;case 0 = read_socket
	bra.s		IC_recv_xxx
;-------------------------------------
;int32 IC_recv(int32 fop, int16 sfd, void *buf, int32 len, uint16 flags);
;-------------------------------------
IC_recv:
	moveq		#1,d0		;case 1 = recv
	bra.s		IC_recv_xxx
;-------------------------------------
;int32 IC_recvfrom(int32 fop, int16 sfd, void * buf, int32 len, uint16 flags, struct sockaddr_in *addr, int16 *addr_len);
;-------------------------------------
IC_recvfrom:
	moveq		#2,d0		;case 2 = recvfrom
IC_recv_xxx:
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.l	x_buf_msg	;diff for IC_recvmsg
	lv_arg.l	x_blen_mflg	;diff for IC_recvmsg
	lv_arg.w	x_normflags	;not for IC_recvmsg or IC_read_socket
;-------
	lv_arg.l	x_from_addr	;only for IC_recvfrom
	lv_arg.w	x_from_addrlen	;only for IC_recvfrom
;-------
	lv_var.w	x_recv_xxx_mode	;0..3:write_socket,recv,recvfrom,recvmsg
	lv_var.l	x_iov_p		;struct iovec *iov_p
	lv_var.l	x_iov_cnt	;array entries at *iov_p
	lv_var.b	x_loc_iov,sizeof_iovec
	lv_var.w	x_flags		;uint16 flags
	lv_var.l	x_from_ad	;struct sockaddr *to_ad;
	lv_var.w	x_from_adlen	;int16 adlen;
	lv_var.l	x_msg_name	;void_p msg_name
	lv_var.l	x_msg_namelen	;uint32 msg_namelen
	lv_var.l	x_data_recvd	;uint32 data_recvd
;-------
	move		d0,x_recv_xxx_mode(a6)
	add		d0,d0
	move		recv_xxx_t(pc,d0),d0
	jmp		recv_xxx_t(pc,d0)
;-------
recv_xxx_t:
	dc.w		recv_xxx_0-recv_xxx_t
	dc.w		recv_xxx_1-recv_xxx_t
	dc.w		recv_xxx_2-recv_xxx_t
;-------
recv_xxx_0:					;for IC_read_socket
	clr		x_flags(a6)
	bra.s		recv_xxx_0_1
;
recv_xxx_1:					;for IC_recv
	move		x_normflags(a6),x_flags(a6)
recv_xxx_0_1:
	clr.l		x_from_ad(a6)
	bra.s		recv_xxx_0_1_2
;-------
recv_xxx_2:					;for IC_recvfrom
	move.l		x_from_addr(a6),x_from_ad(a6)
	move		x_from_addrlen(a6),x_from_adlen(a6)
recv_xxx_0_1_2:
	move.l		x_buf_msg(a6),x_loc_iov+iov_base(a6)
	move.l		x_blen_mflg(a6),x_loc_iov+iov_len(a6)
	lea		x_loc_iov(a6),a0
	move.l		a0,x_iov_p(a6)
	move.l		#1,x_iov_cnt(a6)
	clr.l		x_msg_name(a6)
recv_xxx_common:
	clr.l		x_data_recvd(a6)
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	btst		#SS1_b_listening,EMS_state1(a3)
	bne		.exit_E_IC_NOTCONN
	btst		#SS1_b_connected,EMS_state1(a3)
	bne.s		.already_connected
.not_connected:
	cmp		#SOCK_STREAM,EMS_type(a3)
	beq		.exit_E_IC_OPNOTSUPP
	cmp		#2,x_recv_xxx_mode(a6)	;recvfrom call ?
	bne		.exit_E_IC_OPNOTSUPP
	move.l		x_from_ad(a6),a0
	move.l		a0,d0
	ble		.exit_E_IC_OPNOTSUPP
	cmp		#AF_INET,sa_family(a0)
	bne		.exit_E_IC_OPNOTSUPP
	cmp.l		#INADDR_ANY,sin_addr(a0)
	beq		.exit_E_IC_OPNOTSUPP
	move		sin_port(a0),EMS_CAB+CAB_rport(a3)
	move.l		sin_addr(a0),EMS_CAB+CAB_rhost(a3)
	move.l		a3,a0
	bsr		open_EMS_conn
	bmi		.exit_E_IC_PROTO
	bra.s		.conn_is_ready
;-------
.already_connected:
	cmp		#SOCK_STREAM,EMS_type(a3)
	beq.s		.STREAM_conn_is_ready
	cmp		#2,x_recv_xxx_mode(a6)	;recvfrom call ?
	bne.s		.conn_is_ready
.recvfrom_connected:
	move.l		x_from_ad(a6),a0
	move.l		a0,d0
	beq.s		.conn_is_ready
	bne		.exit_E_IC_ISCONN
;-------
.STREAM_conn_is_ready:
	btst		#1,x_flags+1(a6)
	beq.s		.conn_is_ready
	move.l		x_iov_p(a6),a0
	move.l		iov_base(a0),a2
	move.l		a2,d0
	bne.s		.conn_is_ready
.query_available:
	move.l		iov_len(a0),d0
	beq		.exit_d0
	move.l		d0,d3
	CNbyte_count	EMS_conn(a3)
	tst.l		d0
	bmi.s		.query_error
	cmp.l		d3,d0
	bls		.exit_d0
	move.l		d3,d0
	bra		.exit_d0
;-------
.query_error:
	moveq		#0,d0
	bra		.exit_d0
;-------
.conn_is_ready:
	tst.l		x_iov_cnt(a6)
	bgt		.first_iov		;for normal recving
	blt		.exit_E_IC_OPNOTSUPP	;for sick recvmsg
	bra		.exit_normal		;for empty recvmsg...
;-------
.recv_iov_loop:
	move.l		x_iov_p(a6),a0
	move.l		iov_base(a0),a2
	move.l		a2,d0
	ble.s		.recv_error
	move.l		iov_len(a0),d3
	ble		.next_iov
	cmp.l		EMS_max_xfer(a3),d3
	bgt.s		.recv_error
.recv_block_loop:
	clr.l		d2
	move		EMS_max_buff(a3),d2
	cmp.l		d2,d3
	bhs.s		.keep_size_d2
	move		d3,d2
.keep_size_d2:
.try_recv:
	recv_c		EMS_conn(a3),(a2),d2
	tst		d0
	bpl.s		.next_block
	cmp		#E_LOCKED,d0
	beq.s		.chk_retry_permit
	cmp		#E_NODATA,d0
	bne.s		.store_error
.chk_retry_permit:
	btst		#SS2_b_NONBLOCK,EMS_state2(a3)
	beq.s		.try_recv
.store_error:
	move		d0,EMS_last_err(a3)
.recv_error:
	tst.l		x_data_recvd(a6)
	bne.s		.exit_normal
	cmp		#E_LOCKED,EMS_last_err(a3)
	bne.s		.exit_E_IC_PROTO
	moveq		#E_IC_AGAIN,d0
	bra.s		.exit_d0
;
.next_block:
	and.l		#$ffff,d0
	add.l		d0,a2
	add.l		d0,x_data_recvd(a6)
	sub.l		d0,d3
	bne		.recv_block_loop
.next_iov:
	addq.l		#8,x_iov_p(a6)
.first_iov:
	subq.l		#1,x_iov_cnt(a6)
	bpl		.recv_iov_loop
.exit_normal:
	move.l		x_data_recvd(a6),d0
	bra.s		.exit_d0
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_ISCONN:
	moveq		#E_IC_ISCONN,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTCONN:
	moveq		#E_IC_NOTCONN,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_PROTO:
	moveq		#E_IC_PROTO,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
.exit_d0:
IC_recv_xxx_exit:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;----------------------------------------------------------------------------
;int16 IC_select(int32 fop, int16 nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
;-------------------------------------
IC_select:
	lv_init		a6
	movem.l		d3-d4/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_nfds
	lv_arg.l	x_readfds_p
	lv_arg.l	x_writefds_p
	lv_arg.l	x_exceptfds_p
	lv_arg.l	x_timeout_p
;-------
	lv_var.w	x_timeout_f
	lv_var.l	x_start_time
	lv_var.l	x_timeout
	lv_var.w	x_max_dbra
	lv_var.w	x_read_dbra
	lv_var.w	x_write_dbra
	lv_var.w	x_except_dbra
	lv_var.l	x_workarray_p
	lv_var.w	x_success_cnt
;-------
	clr.l		x_workarray_p(a6)
	clr		x_success_cnt(a6)
;-------
	move		x_nfds(a6),d0
	sub		#SFD_FIRST,d0
	ble		.exit_E_IC_INVSFD
	cmp		#SFD_MASK,d0
	bhi		.exit_E_IC_INVSFD
	subq		#1,d0			;d0 = last index for select
	lsr		#5,d0			;number of last long to scan
	move		d0,x_max_dbra(a6)	;store as future dbra cnt
;-------
	move.l		x_timeout_p(a6),d0
	sle		x_timeout_f(a6)		;mark timeout on or off
	ble.s		.done_time_1
	move.l		d0,a0
	move.l		tv_sec(a0),d0		;d0 = tv_sec
	move.l		d0,d1			;d1 = tv_sec
	lsl.l		#7,d0			;d0 = tv_sec*128
	sub.l		d1,d0			;d0 = tv_sec*127
	sub.l		d1,d0			;d0 = tv_sec*126
	sub.l		d1,d0			;d0 = tv_sec*125
	lsl.l		#3,d0			;d0 = tv_sec*1000
	move.l		d0,a1			;a1 = whole seconds [ms]
	move.l		tv_usec(a0),d1		;d1 = fraction of second [us]
	beq.s		.done_tv_usec		;save time when tv_usec == 0
	divu		#1000,d1		;d1 = fraction of second [ms]
	add		d1,a1			;a1 = total timeout [ms]
.done_tv_usec:
;-------
	IFNE		SLOW_SELECT
;-------
	move.l		#SLOW_SELECT,d1
	cmp.l		d1,a1
	bhs.s		.have_timeout_a1
	move.l		d1,a1
.have_timeout_a1:
;-------
	ENDC		;SLOW_SELECT
;-------
	move.l		a1,x_timeout(a6)
	TIMER_now
	move.l		d0,x_start_time(a6)
.done_time_1:
	R_alloc		#3*SFD_LIM
	tst.l		d0
	ble		.exit_E_IC_NOBUFS
	move.l		d0,x_workarray_p(a6)
	move.l		d0,a3
;-------
	clr		d3
	move.l		x_readfds_p(a6),d0
	ble.s		.done_read_setup
	move.l		d0,a0
	move		x_max_dbra(a6),d1
	bsr		allocate_limited
	bmi.s		.done_read_setup
.read_setup_loop
	move.b		d0,(a3)+
	addq		#1,d3
	bsr		allocate_indexed
	bpl.s		.read_setup_loop
.done_read_setup:
	subq		#1,d3
	move		d3,x_read_dbra(a6)
;-------
	clr		d3
	move.l		x_writefds_p(a6),d0
	ble.s		.done_write_setup
	move.l		d0,a0
	move		x_max_dbra(a6),d1
	bsr		allocate_limited
	bmi.s		.done_write_setup
.write_setup_loop
	move.b		d0,(a3)+
	addq		#1,d3
	bsr		allocate_indexed
	bpl.s		.write_setup_loop
.done_write_setup:
	subq		#1,d3
	move		d3,x_write_dbra(a6)
;-------
	clr		d3
	move.l		x_exceptfds_p(a6),d0
	ble.s		.done_except_setup
	move.l		d0,a0
	move		x_max_dbra(a6),d1
	bsr		allocate_limited
	bmi.s		.done_except_setup
.except_setup_loop
	move.b		d0,(a3)+
	addq		#1,d3
	bsr		allocate_indexed
	bpl.s		.except_setup_loop
.done_except_setup:
	subq		#1,d3
	move		d3,x_except_dbra(a6)
;-------
	move.l		a3,d0
	sub.l		x_workarray_p(a6),d0
	beq		.exit_d0
;-------
.main_work_loop:
	move.l		x_workarray_p(a6),a3
;-------
	move		x_read_dbra(a6),d4
	blt.s		.done_read_work
.read_work_loop:
	clr		d0
	move.b		(a3)+,d0
	move		d0,d3			;d3 = d0  socket index
	lsl		#2,d0
	lea		sfd_sock_pt(pc),a0
	move.l		(a0,d0),d0		;d0 = NULL or -> EM_sock struct
	ble		.exit_E_IC_NOTSOCK
	move.l		d0,a2			;a2 -> socket
	btst		#SS0_b_opened,EMS_state0(a2)
	beq.s		.read_unopen
	CNbyte_count	EMS_conn(a2)
	tst		d0
	bgt.s		.read_success
	beq.s		.next_reader
	cmp		#E_LISTEN,d0
	beq.s		.next_reader
	cmp		#E_NODATA,d0
	beq.s		.next_reader
	cmp		#E_LOCKED,d0
	beq.s		.next_reader
.read_error:
	bra		.exit_E_IC_PROTO
;-------
.read_unopen:
	cmp		#SOCK_STREAM,EMS_type(a2)
	bne.s		.next_reader
	bra		.exit_E_IC_NOTCONN
;-------
.read_success:
	addq		#1,x_success_cnt(a6)
	move.l		x_readfds_p(a6),a0	;a0 -> map
	move		d3,d0			;d0 = d3  socket index
	and		#$1F,d3			;d3 = bit index in long
	sub		d3,d0			;d0 = bit index for long
	lsr		#3,d0			;d0 = byte offset for long
	add		d0,a0			;a0 -> long
	move.l		(a0),d0			;d0 = long
	bset		d3,d0			;set bit in d0 long
	move.l		d0,(a0)			;store changed long in map
.next_reader:
	dbra		d4,.read_work_loop
.done_read_work:
;-------
	move		x_write_dbra(a6),d4
	blt.s		.done_write_work
.write_work_loop:
	clr		d0
	move.b		(a3)+,d0
	move		d0,d3			;d3 = d0  socket index
	lsl		#2,d0
	lea		sfd_sock_pt(pc),a0
	move.l		(a0,d0),d0		;d0 = NULL or -> EM_sock struct
	ble		.exit_E_IC_NOTSOCK
	move.l		d0,a2			;a2 -> socket
	cmp		#SOCK_STREAM,EMS_type(a2)
	bne.s		.write_success
	btst		#SS0_b_opened,EMS_state0(a2)
	beq		.exit_E_IC_NOTCONN
	TCP_info	d0,ask_state_TCPIB(pc)	;get TCP connection state
	tst		d0			;network errors ?
	bpl.s		.have_state
	cmp		#E_LOCKED,d0
	beq.s		.next_writer
	bra		.exit_E_IC_PROTO
;-------
.have_state:
	move		TCPIB_state+ask_state_TCPIB(pc),d0
	cmp		#TSYN_SENT,d0
	ble.s		.next_writer
	cmp		#TCLOSING,d0
	bge		.exit_E_IC_NOTCONN
.write_success:
	addq		#1,x_success_cnt(a6)
	move.l		x_writefds_p(a6),a0	;a0 -> map
	move		d3,d0			;d0 = d3  socket index
	and		#$1F,d3			;d3 = bit index in long
	sub		d3,d0			;d0 = bit index for long
	lsr		#3,d0			;d0 = byte offset for long
	add		d0,a0			;a0 -> long
	move.l		(a0),d0			;d0 = long
	bset		d3,d0			;set bit in d0 long
	move.l		d0,(a0)			;store changed long in map
.next_writer:
	dbra		d4,.write_work_loop
.done_write_work:
;-------
	move		x_except_dbra(a6),d4
	blt.s		.done_except_work
.except_work_loop:
	clr		d0
	move.b		(a3)+,d0
	move		d0,d3			;d3 = d0  socket index
	lsl		#2,d0
	lea		sfd_sock_pt(pc),a0
	move.l		(a0,d0),d0		;d0 = NULL or -> EM_sock struct
	ble		.exit_E_IC_NOTSOCK
	move.l		d0,a2			;a2 -> socket
	btst		#SS0_b_opened,EMS_state0(a2)
	beq.s		.except_unopen
	CNbyte_count	EMS_conn(a2)
	tst		d0
	bgt.s		.except_success
	beq.s		.next_excepter
	cmp		#E_LISTEN,d0
	beq.s		.next_excepter
	cmp		#E_NODATA,d0
	beq.s		.next_excepter
	cmp		#E_LOCKED,d0
	beq.s		.next_excepter
.except_error:
	bra.s		.exit_E_IC_PROTO
;-------
.except_unopen:
	cmp		#SOCK_STREAM,EMS_type(a2)
	bne.s		.next_excepter
	bra.s		.exit_E_IC_NOTCONN
;-------
.except_success:
	addq		#1,x_success_cnt(a6)
	move.l		x_exceptfds_p(a6),a0	;a0 -> map
	move		d3,d0			;d0 = d3  socket index
	and		#$1F,d3			;d3 = bit index in long
	sub		d3,d0			;d0 = bit index for long
	lsr		#3,d0			;d0 = byte offset for long
	add		d0,a0			;a0 -> long
	move.l		(a0),d0			;d0 = long
	bset		d3,d0			;set bit in d0 long
	move.l		d0,(a0)			;store changed long in map
.next_excepter:
	dbra		d4,.except_work_loop
.done_except_work:
;-------
	move		x_success_cnt(a6),d0
	bne.s		.exit_d0
	tst.b		x_timeout_f(a6)
	bne		.main_work_loop
	TIMER_elapsed	x_start_time(a6)
	cmp.l		x_timeout(a6),d0
	blo		.main_work_loop
	moveq		#0,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTCONN:
	moveq		#E_IC_NOTCONN,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_PROTO:
	moveq		#E_IC_PROTO,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOBUFS:
	moveq		#E_IC_NOBUFS,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_NOBUFS,d0
;-------
.exit_d0:
	move.l		x_workarray_p(a6),d1
	beq.s		IC_select_exit
	move		d0,d3
	R_free.i	d1
	move		d3,d0
IC_select_exit:
	movem.l		(sp)+,d3-d4/a2-a3
	lv_exit		a6
	rts
;-------------------------------------
;End of:	IC_select
;----------------------------------------------------------------------------
;;;
;-------------------------------------
IC_status:
;-------------------------------------
;End of:	IC_status
;----------------------------------------------------------------------------
;int16 IC_shutdown(int32 fop, int16 sfd, int16 how);
;-------------------------------------
IC_shutdown:
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.w	x_how
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	cmp		#2,x_how(a6)
	bne.s		.exit_OK
.full_shutdown:
	move		x_sfd(a6),-(sp)
	pea		(NULL).w
	bsr		IC_sclose
	addq		#6,sp
.exit_OK:
	moveq		#E_OK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTCONN:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
.exit_d0:
IC_shutdown_exit:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------------------------------------
;End of:	IC_shutdown
;----------------------------------------------------------------------------
;int16	IC_sclose(int32 fop, int16 sfd);
;-------------------------------------
IC_sclose:
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
;-------
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	move.l		a3,a0
	bsr		shutdown_DRS
	protect_exec	(a3),remove_active_sock(pc)
	R_free.i	a3
	move		x_sfd(a6),d0
	bsr		release_sfd
.exit_d0:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_INVSFD,d0
	bra.s		.exit_d0
;-------------------------------------
;End of:	IC_sclose
;----------------------------------------------------------------------------
;int32 IC_sfcntl(int32 fop, int16 sfd, int16 cmd, int32 args);
;-------------------------------------
IC_sfcntl:
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.w	x_cmd
	lv_arg.l	x_args
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	move		x_cmd(a3),d0
	cmp		#'S',d0
	beq.s		.set_NONBLOCK
	cmp		#'T',d0
	bne.s		.exit_E_IC_OPNOTSUPP
.tst_NONBLOCK:
	clr.l		d0
	move		EMS_IC_state(a3),d0
	bra.s		.exit_d0
;-------
.set_NONBLOCK:
	move		x_args+2(a6),d0
	and.l		#SO_O_NONBLOCK,d0
	move		d0,EMS_IC_state(a3)
	bra.s		.exit_d0
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
;-------
.exit_d0:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------------------------------------
;End of:	IC_sfcntl
;----------------------------------------------------------------------------
;int16 IC_getsockopt(int32 fop, int16 sfd, int16 level, int16 optname, char *optval, int *optlen);
;-------------------------------------
IC_getsockopt:		;dummy ?
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.w	x_level
	lv_arg.w	x_optname
	lv_arg.l	x_optval_p
	lv_arg.l	x_optlen_p
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	cmp		#-1,x_level(a6)
	bne.s		.exit_E_IC_BADPARAM
	cmp		#'T',x_optname(a6)
	bne.s		.exit_E_IC_BADPARAM
	move.l		x_optval_p(a6),a0
	move.l		x_optlen_p(a6),a1
	cmp		#2,(a1)
	blt.s		.exit_E_IC_BADPARAM
	move.b		EMS_IC_state+0(a3),0(a0)
	move.b		EMS_IC_state+1(a3),1(a0)
	move		#2,(a1)
	moveq		#E_OK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_BADPARAM:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
;-------
.exit_d0:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------------------------------------
;End of:	IC_getsockopt
;----------------------------------------------------------------------------
;int16 IC_setsockopt(int32 fop, int16 sfd, int16 level, int16 optname, char *optval, int16 optlen);
;-------------------------------------
IC_setsockopt:		;dummy ?
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.w	x_level
	lv_arg.w	x_optname
	lv_arg.l	x_optval_p
	lv_arg.w	x_optlen
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	cmp		#-1,x_level(a6)
	bne.s		.exit_E_IC_BADPARAM
	cmp		#'S',x_optname(a6)
	bne.s		.exit_E_IC_BADPARAM
	cmp		#2,x_optlen(a6)
	bne.s		.exit_E_IC_BADPARAM
	move.l		x_optval_p(a6),a0
	move.b		0(a0),EMS_IC_state+0(a3)
	move.b		1(a0),EMS_IC_state+1(a3)
	moveq		#0,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_BADPARAM:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
;-------
.exit_d0:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------------------------------------
;End of:	IC_setsockopt
;----------------------------------------------------------------------------
;int16 IC_getsockname(int32 fop, int16 sfd, struct sockaddr *name, int16 *namelen);
;-------------------------------------
IC_getsockname:
	moveq		#0,d2			;case 0 = getsockname
	bra.s		IC_get_xxx_name
;-------------------------------------
;int16 IC_getpeername(int32 fop, int16 sfd, struct sockaddr *name, int16 *namelen);
;-------------------------------------
IC_getpeername:
	moveq		#0,d2			;case 1 = getpeername
IC_get_xxx_name:
	lv_init		a6
	movem.l		d2-d3/a2-a3,-(sp)
	lv_arg.l	x_fop
	lv_arg.w	x_sfd
	lv_arg.l	x_somead_p
	lv_arg.l	x_somead_len_p
;-------
	lv_var.b	x_sockad,sizeof_sockaddr_in
;-------
	sfd_to_sock_p	x_sfd(a6),a3
;-------
	move.l		x_somead_len_p(a6),a1
	move.l		a1,d0
	ble		.exit_E_IC_OPNOTSUPP
	move		(a1),d1
	move.l		x_somead_p(a6),a1
	move.l		a1,d0
	ble		.exit_E_IC_OPNOTSUPP
;-------
	tst		d2			;getsockname ?
	beq.s		.gethost
.getpeer:
	btst		#SS0_b_opened,EMS_state0(a3)
	beq.s		.exit_E_IC_NOTCONN
	move.l		EMS_CIB_p(a3),a0
	move.l		a0,d0
	ble.s		.exit_E_IC_NOTCONN
	cmp		#INADDR_ANY,CIB_rhost(a0)
	beq.s		.exit_E_IC_NOTCONN
	move		CIB_rport(a0),x_sockad+sin_port(a6)
	move.l		CIB_rhost(a0),x_sockad+sin_addr(a6)
	bra.s		.copy_addr
;-------
.gethost:
	btst		#SS0_b_opened,EMS_state0(a3)
	beq.s		.get_bound
	move.l		EMS_CIB_p(a3),a0
	move.l		a0,d0
	ble.s		.get_bound
	move		CIB_rport(a0),x_sockad+sin_port(a6)
	move.l		CIB_rhost(a0),x_sockad+sin_addr(a6)
	bra.s		.copy_addr
;-------
.get_bound:
	move		EMS_CAB+CAB_lport(a3),x_sockad+sin_port(a6)
	move.l		EMS_CAB+CAB_lhost(a3),x_sockad+sin_addr(a6)
;-------
.copy_addr:
	move		#AF_INET,x_sockad+sin_family(a6)
	clr.l		x_sockad+sin_zero+0(a6)
	clr.l		x_sockad+sin_zero+4(a6)
	moveq		#sizeof_sockaddr_in,d0
	cmp		d0,d1
	blo.s		.keep_d1_count
	move		d0,d1
.keep_d1_count:
	move.l		x_somead_len_p(a6),a0
	move		d1,(a0)
	lea		x_sockad(a6),a0
	bra.s		.loop_entry
;-------
.loop:
	move.b		(a0)+,(a1)+
.loop_entry:
	dbra		d1,.loop
.exit_OK:
	moveq		#E_OK,d0
.exit_E_IC_NOTCONN:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_OPNOTSUPP:
	moveq		#E_IC_OPNOTSUPP,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_NOTSOCK:
	moveq		#E_IC_NOTSOCK,d0
	bra.s		.exit_d0
;-------
.exit_E_IC_INVSFD:
	moveq		#E_IC_INVSFD,d0
.exit_d0:
IC_get_xxx_name_exit:
	movem.l		(sp)+,d2-d3/a2-a3
	lv_exit		a6
	rts
;-------------------------------------
;End of:	IC_getsockname & IC_getpeername
;----------------------------------------------------------------------------
res_init:
res_query:
res_search:
res_mkquery:
res_send:
dn_expand:
dn_comp:
usis_query:
	moveq		#E_IC_OPNOTSUPP,d0
	rts
;----------------------------------------------------------------------------
;End of:	Iconnect SLIP API functions
;----------------------------------------------------------------------------
;Start of:	Resident local subroutines
;----------------------------------------------------------------------------
loc_malloc:
	addq		#8,d0
	move.l		d2,-(sp)
	R_alloc		d0
	move.l		(sp)+,d2
	tst.l		d0
	ble.s		.error
	move.l		currbp_p_p(pc),a1	;a1 -> p_run OS variable
	move.l		(a1),(a0)+		;store -> block owner
	move.l		mallocated_p(pc),(a0)+	;store -> next block in list
	move.l		a0,mallocated_p
	move.l		a0,d0
	rts
;-------
.error:
	clr.l		d0
	rts
;----------------------------------------------------------------------------
loc_mfree:
	lea		mallocated_p(pc),a1
	move.l		(a1),a0
	move.l		a0,d0
	ble.s		.error
.loop:
	cmp.l		d1,a0
	beq.s		.found
	lea		-4(a0),a1
	move.l		(a1),a0
	move.l		a0,d0
	bgt.s		.loop
.error:
	rts
;-------
.found:
	move.l		-(a0),(a1)
	subq		#4,a0
	move.l		d2,-(sp)
	R_free.i	a0
	move.l		(sp)+,d2
	rts
;----------------------------------------------------------------------------
;create_EM_sock returns:	d0 = errcode,  d3 = sfd,  a3 -> EMS_sock
;-------------------------------------
create_EM_sock:
	lea		sfd_map_t(pc),a0
	bsr		allocate_bit
	ble.s		.exit_direct
	add		#SFD_FIRST,d0		;d0 = sfd
	move		d0,d3			;d3 = sfd
	R_alloc		#sizeof_EM_sock
	tst.l		d0
	ble.s		.malloc_fail_exit
	move.l		d0,a0				;a0 -> new EM_sock
	move.l		a0,a3				;a3 = a0  -> new EM_sock
	moveq		#((sizeof_EM_sock)/2-1),d0
.clear_loop:
	clr		(a0)+
	dbra		d0,.clear_loop
	move.l		currbp_p_p(pc),a0	;a0 -> p_run OS variable
	move.l		(a0),EMS_owner(a3)
	move		d3,EMS_sfd(a3)
	moveq		#E_OK,d0
.exit_direct:
	rts
;-------
.malloc_fail_exit:
	move		d3,d0
	bsr		release_sfd
	moveq		#E_IC_NOBUFS,d0
	rts
;----------------------------------------------------------------------------
;uint16	get_hostent_ix(void)
;-------------------------------------
;This routine must be called via protect_exec
;-------------------------------------
get_hostent_ix:
	addq		#1,hostent_ix
	move		hostent_ix(pc),d0
	and		#HOSTENT_MASK,d0
	rts
;----------------------------------------------------------------------------
;hostent *get_new_hostent(void)		;NB: nonstandard results d0/a0
;-------------------------------------
get_new_hostent:
	protect_exec	!,get_hostent_ix(pc)
	move		d0,d1			;d1 = d0 = hostent_ix
	mulu		#sizeof_ext_hostent,d1	;d1 = hostent offset
	lea		hostent_t(pc),a1
	lea		(a1,d1),a0		;a0 -> hostent for caller
;-------
	move.l		currbp_p_p(pc),a1	;a0 -> p_run OS variable
	move.l		(a0),he_owner(a3)
	move.l		h_name(a0),d1		;was h_name used before ?
	beq.s		.old_name_cleared
	movem.l		d0/a0,-(sp)
	KRfree.i	d1
	movem.l		(sp)+,d0/a0
	clr.l		h_name(a0)
.old_name_cleared:
	rts		;at exit d0 = hostent_ix  a0 -> hostent
;----------------------------------------------------------------------------
;void	insert_active_sock(EM_sock *sock_p)
;-------------------------------------
;This routine must be called via protect_exec
;-------------------------------------
insert_active_sock:
	lv_init		sp,args
	lv_arg.l	x_sock_p
;-------
	lea		active_sock_p(pc),a0	;a0 -> root of active sock list
	move.l		x_sock_p(sp),a1		;a1 -> new socket to insert
	move.l		(a0),EMS_next(a1)	;link old list to new sock
	move.l		a1,(a0)			;link new sock to root
	lv_exit		sp,args
	rts
;----------------------------------------------------------------------------
;void	remove_active_sock(EM_sock *sock_p)
;-------------------------------------
;This routine must be called via protect_exec
;-------------------------------------
remove_active_sock:
	lv_init		sp,args
	lv_arg.l	x_sock_p
;-------
	lea		active_sock_p-EMS_next(pc),a0
	move.l		x_sock_p(sp),a1
	bra.s		.test_next
;-------
.loop:
	cmp.l		a1,d0			;is next EM_sock == x_sock_p ?
	beq.s		.found
	move.l		d0,a0			;a0 -> next EM_sock (now current)
.test_next:
	move.l		EMS_next(a0),d0		;d0 -> next EM_sock unless NULL
	bne.s		.loop
.failed:
	bra.s		.exit
;-------
.found:
	move.l		EMS_next(a1),EMS_next(a0)	;unlink found sock
.exit:
	lv_exit		sp,args
	rts
;----------------------------------------------------------------------------
;void	insert_listen_sock(EM_sock *sock_p)
;-------------------------------------
;This routine must be called via protect_exec
;-------------------------------------
insert_listen_sock:
	lv_init		sp,args
	lv_arg.l	x_sock_p
;-------
	lea		listen_sock_p(pc),a0	;a0 -> root of listen sock list
	move.l		x_sock_p(sp),a1		;a1 -> new socket to insert
	move.l		(a0),EMS_next(a1)	;link old list to new sock
	move.l		a1,(a0)			;link new sock to root
	lv_exit		sp,args
	rts
;----------------------------------------------------------------------------
;void	remove_listen_sock(EM_sock *sock_p)
;-------------------------------------
;This routine must be called via protect_exec
;-------------------------------------
remove_listen_sock:
	lv_init		sp,args
	lv_arg.l	x_sock_p
;-------
	lea		listen_sock_p-EMS_next(pc),a0
	move.l		x_sock_p(sp),a1
	bra.s		.test_next
;-------
.loop:
	cmp.l		a1,d0			;is next EM_sock == x_sock_p ?
	beq.s		.found
	move.l		d0,a0			;a0 -> next EM_sock (now current)
.test_next:
	move.l		EMS_next(a0),d0		;d0 -> next EM_sock unless NULL
	bne.s		.loop
.failed:
	bra.s		.exit
;-------
.found:
	move.l		EMS_next(a1),EMS_next(a0)	;unlink found sock
.exit:
	lv_exit		sp,args
	rts
;----------------------------------------------------------------------------
;void	insert_backed_sock(EM_sock *sock_p)
;-------------------------------------
;This routine must be called via protect_exec
;-------------------------------------
insert_backed_sock:
	lv_init		sp,args
	lv_arg.l	x_sock_p
;-------
	move.l		x_sock_p(sp),a1		;a1 -> new socket to insert
	move.l		EMS_listener(a1),a0	;a0 -> listening sock
	addq		#1,EMS_back_cnt(a0)	;increment count
	lea		EMS_backlist(a0),a0	;a0 -> root of backed sock list
	move.l		(a0),EMS_backlist(a1)	;link old list to new sock
	move.l		a1,(a0)			;link new sock to root
	lv_exit		sp,args
	rts
;----------------------------------------------------------------------------
;void	remove_backed_sock(EM_sock *sock_p)
;-------------------------------------
;This routine must be called via protect_exec
;-------------------------------------
remove_backed_sock:
	lv_init		sp,args
	lv_arg.l	x_sock_p
;-------
	move.l		x_sock_p(sp),a1
	move.l		EMS_listener(a1),a0	;a0 -> listening sock
	subq		#1,EMS_back_cnt(a0)	;decrement count
	bra.s		.test_next
;-------
.loop:
	cmp.l		a1,d0			;is next EM_sock == x_sock_p ?
	beq.s		.found
	move.l		d0,a0			;a0 -> next EM_sock (now current)
.test_next:
	move.l		EMS_backlist(a0),d0	;d0 -> next EM_sock unless NULL
	bne.s		.loop
.failed:
	bra.s		.exit
;-------
.found:
	move.l		EMS_backlist(a1),EMS_backlist(a0)	;unlink
.exit:
	lv_exit		sp,args
	rts
;----------------------------------------------------------------------------
;void	accept_backed_sock(EM_sock *sock_p)
;-------------------------------------
;This routine must be called via protect_exec
;-------------------------------------
accept_backed_sock:
	lv_init		sp,args
	lv_arg.l	x_sock_p
;-------
	move.l		x_sock_p(sp),a0		;a0 -> listener
	move.l		(a0),d0
	ble.s		.exit
	move.l		d0,a1
	bra.s		.test_next
;-------
.loop:
	move.l		a1,a0
	move.l		d0,a1
.test_next:
	move.l		EMS_backlist(a1),d0	;d0 -> next EM_sock unless NULL
	bgt.s		.loop
.found:
	clr.l		EMS_backlist(a0)	;unlink accept socket
	subq		#1,EMS_back_cnt(a0)	;decrement count
	move.l		a1,d0			;return accept socket
.exit:
	lv_exit		sp,args
	rts
;----------------------------------------------------------------------------
;int16	open_EMS_conn(EM_sock *sock)
;-------------------------------------
open_EMS_conn:
	move.l		a3,-(sp)
	move.l		a0,a3			;a3 = a1 -> EM_sock
	bclr		#SS0_b_opened,EMS_state0(a3)
	beq.s		.not_open
	close_c		EMS_conn(a3),EMS_proto(a3)
.not_open:
	clr		EMS_last_err(a3)
	open_c		EMS_CAB(a3),EMS_proto(a3)
	tst		d0
	bmi.s		.exit_E_IC_PROTO
	bset		#SS0_b_opened,EMS_state0(a3)
	move		d0,EMS_conn(a3)
	CNgetinfo	EMS_conn(a3)
	move.l		d0,EMS_CIB_p(a3)
	move		EMS_conn(a3),d0
.exit_d0:
	movem.l		(sp)+,a3
	rts
;-------
.exit_E_IC_PROTO:
	move		d0,EMS_last_err(a3)
	moveq		#E_IC_PROTO,d0
	bra.s		.exit_d0
;----------------------------------------------------------------------------
;int16	close_EMS_conn(EM_sock *sock)
;-------------------------------------
close_EMS_conn:
	move.l		a3,-(sp)
	move.l		a0,a3			;a3 = a1 -> EM_sock
	btst		#SS0_b_opened,EMS_state0(a3)
	beq.s		.exit_E_IC_NOTCONN
	close_c		EMS_conn(a3),EMS_proto(a3)
	tst		d0
	bpl.s		.exit_OK
	cmp		#E_LOCKED,d0
	beq.s		.exit_E_IC_AGAIN
	cmp		#E_BADCLOSE,d0
	beq.s		.exit_OK
	cmp		#E_BADHANDLE,d0
	beq.s		.exit_E_IC_NOTCONN
.exit_weird:
	move		d0,EMS_last_err(a3)
.exit_E_IC_AGAIN:
	moveq		#E_IC_AGAIN,d0
	bra.s		.exit_d0
;-------
.exit_OK:
	moveq		#E_OK,d0
.exit_closed_d0:
	bclr		#SS0_b_opened,EMS_state0(a3)
	clr		EMS_last_err(a3)
.exit_d0:
	movem.l		(sp)+,a3
	rts
;-------
.exit_E_IC_NOTCONN:
	moveq		#E_IC_NOTCONN,d0
	bra.s		.exit_d0
;----------------------------------------------------------------------------
;void	shutdown_DRS(EM_sock *sock)
;-------------------------------------
shutdown_DRS:
	movem.l		a2/a3,-(sp)
	move.l		a0,a3
	protect_exec	(a3),remove_listen_sock(pc)
	move.l		a3,a0
	bsr		close_EMS_conn
	bclr		#SS1_b_connected,EMS_state1(a3)
	bclr		#SS1_b_listening,EMS_state1(a3)
	beq.s		.done_unlisten
	protect_exec	(a3),insert_active_sock(pc)
.unlisten_loop:
	move.l		EMS_backlist(a3),d0
	ble.s		.done_unlisten
	move.l		d0,a2
	move.l		EMS_backlist(a2),EMS_backlist(a3)
	move		EMS_sfd(a2),-(sp)
	pea		(NULL).w
	bsr		IC_sclose
	addq		#6,sp
	bra.s		.unlisten_loop
;-------
.done_unlisten:
	movem.l		(sp)+,a2/a3
	rts
;----------------------------------------------------------------------------
init_t_job:
	move.l		a0,d0
	ble.s		.exit
	move		TJ_delay(a0),d1
	beq.s		.exit
	move		d1,TJ_count(a0)
	tst.b		TJ_work_f(a0)
	bne.s		.exit
	move.b		#$01,TJ_work_f(a0)
	clr.l		TJ_prev(a0)
	move.l		TJ_root(pc),TJ_next(a0)
	beq.s		.set_new_root
	move.l		TJ_next(a0),a1
	move.l		a0,TJ_prev(a1)
.set_new_root:
	move.l		a0,TJ_root
.exit:
	rts
;----------------------------------------------------------------------------
exit_t_job:
	move.l		a0,d0
	ble.s		.exit
	cmpi.b		#$01,TJ_work_f(a0)
	bne.s		.done_unlink
	cmp.l		TJ_root(pc),d0
	bne.s		.keep_root
	move.l		TJ_next(a0),TJ_root
.keep_root:
	move.l		TJ_next(a0),d0
	ble.s		.done_patch_next
	move.l		d0,a1
	move.l		TJ_prev(a0),TJ_prev(a1)
.done_patch_next:
	move.l		TJ_prev(a0),d0
	beq.s		.done_patch_prev
	move.l		d0,a1
	move.l		TJ_next(a0),TJ_next(a1)
.done_patch_prev:
.done_unlink:
	clr.b		TJ_work_f(a0)
.exit:
	rts
;----------------------------------------------------------------------------
		ds.b	16		;for safety from 'misbehavers'
ping_buff:
ping_IP:	ds.b	4	;$00	;IP address for pinging
;-------
ping_t_job:
		ds.b	4	;$04	;-> next tjob
		ds.b	4	;$08	;-> prev tjob
ping_delay:	ds.b	2	;$0C	;delay per ping
ping_dlycnt:	ds.b	2	;$0E	;delay counter
ping_TJ_func:	ds.b	4	;$10	;-> time_job handler
		ds.b	4	;$14
		ds.b	1	;$18	;work flag (0,1,2:free,wait,done)
		ds.b	1	;$19
;-------
ping_timing:	ds.b	4	;$1A	;count of seqnum diffs ???
ping_requests:	ds.b	4	;$1E	;count of ping requests sent
ping_replies:	ds.b	4	;$22	;count of ping replies received
ping_seqnum:	ds.b	2	;$26	;sequence number (and timer)
		ds.b	16		;for safety from 'misbehavers'
ping_pkt:	ds.b	8		;only four bytes used  (idfier,seqnum)
;----------------------------------------------------------------------------
ping_sender:
	addq.l		#1,ping_requests	;increment request count
	TIMER_now
	move		d0,ping_seqnum
	move		d0,ping_pkt+2
	ICMP_send	ping_IP(pc),#8,!,ping_pkt(pc),#4
	lea		ping_t_job(pc),a0
	clr.b		TJ_work_f(a0)
	bsr		init_t_job
	rts
;----------------------------------------------------------------------------
;int16	ping_handler(IP_DGRAM *dgram_p)
;-------------------------------------
ping_handler:
	lv_init		a6
	lv_arg.l	x_dgram_p
;-------
	TIMER_now
	clr.l		d1
	move		d0,d1			;d1 = current time & $FFFF
	move.l		x_dgram_p(a6),a0
	move.l		IPDG_hdr+IPHD_ip_src(a0),d0
	cmp.l		ping_IP(pc),d0
	bne.s		.exit_rejected
	move.l		IPDG_pkt_data(a0),a1
	tst.b		(a1)+			;type == echo reply ?
	bne.s		.exit_rejected
	tst.b		(a1)+			;code == normal ?
	bne.s		.exit_rejected
	addq		#2,a1			;skip chksum
	tst		(a1)+			;echo idfier == 0 ?
	bne.s		.exit_rejected
	sub		(a1),d1			;d1 = elapsed millisecs
	add.l		d1,ping_timing		;add diff to triptime sum
	addq.l		#1,ping_replies		;increment reply_count
	ICMP_discard	(a0)			;discard packet
;-------
.exit_accepted:
	moveq		#1,d0
.exit_d0:
	lv_exit		a6
	rts
;-------
.exit_rejected:
	moveq		#0,d0
	bra.s		.exit_d0
;----------------------------------------------------------------------------
;End of:	Resident local functions
;----------------------------------------------------------------------------
;Start of:	Resident library functions
;----------------------------------------------------------------------------
	make		JAR_links
	make		DOMAIN_links
	_uniref		RAM_own
	_uniref		RAM_add
	make		RAM_links
;-------
	include		standard\strcpy.s
	include		standard\strncpy.s
	include		standard\memcpy.s
	include		standard\memset.s
;----------------------------------------------------------------------------
;End of:	Resident library functions
;----------------------------------------------------------------------------
resident_end:
;all beyond that point will be released in going resident
resident_size	=	resident_end-text_start+$100
;----------------------------------------------------------------------------
;Start of:	Non-resident initialization code
;----------------------------------------------------------------------------
start_1:
	move.l		a0,d0
	sne		d7
	bne.s		.have_basepage
	move.l		4(sp),d0
.have_basepage:
	move.l		d0,a5
	lea		mystack(pc),sp
	move.l		a5,basepage_p
	tst.b		d7
	bne		.ACC_launch
	gemdos		Mshrink,#0,(a5),#initial_size
	lea		bp_arglen(a5),a0
	lea		STinG_Load_s(pc),a1
	str_comp	a0,a1
	bne		.bad_launch
;
	gemdos		Super,0.w
	move.l		d0,d4
;
	moveq		#-1,d3				;d3 = flag cookie conflict
	eval_cookie	#DRACONIS_ID			;test for own cookie
	bpl.s		.done_cookies
	clr.l		d3				;d3 = flag STiK cookie error
	eval_cookie	#"STiK"
	bmi.s		.done_cookies
	move.l		d0,d3				;d3 = d0 -> DRV_LIST structure
.done_cookies:
	gemdos		Super|_ind,d4
;
	move.l		d3,sting_drivers		;sting_drivers -> DRV_LIST structure
	blt		.cookie_conflict
	beq		.STiK_not_found
	move.l		d3,a3				;a3 -> DRV_LIST structure
	lea		DRV_LIST_magic(a3),a0
	lea		STiKmagic_s(pc),a1
	moveq		#10-1,d0
.strcmp_loop:					;loop to test STiKmagic of DRV_LIST
	cmpm.b		(a0)+,(a1)+
	dbne		d0,.strcmp_loop
	bne		.STiK_not_valid
;
	move.l		DRV_LIST_get_dftab(a3),a0	;a0 -> get_dftab function
	pea		TRANSPORT_DRIVER_s		;-(sp) = "TRANSPORT_TCPIP"
	jsr		(a0)				;call get_dftab
	addq		#4,sp
	move.l		d0,tpl				;store pointer in 'tpl'
	ble		.driver_not_valid
;
	move.l		DRV_LIST_get_dftab(a3),a0	;a0 -> get_dftab function
	pea		MODULE_DRIVER_s			;-(sp) = "MODULE_LAYER"
	jsr		(a0)				;call get_dftab
	addq		#4,sp
	move.l		d0,stx				;store pointer in 'stx'
	ble		.layer_not_valid
.install:
	link		a6,#-4
	query_chains	0.w,0.w,-4(a6)
	move.l		-4(a6),a4			;a4->layers
	unlk		a6
;
	move.l		a4,d0
	beq		.bad_layer_list
.layer_loop:
	move.l		d0,a4
	move.l		LAYER_next(a4),d0
	bne		.layer_loop
;
;NB: The code above gives a4 a value -> the end of the layer queue.
;    This is used to install my_layer further below.
;
	gemdos		Super,0.w
	move.l		d0,d4
	lea		ICIP_cookie_t(pc),a0
	make_cookie	#DRACONIS_ID,a0
	move.l		d0,d3
	gemdos		Super|_ind,d4
	move.l		d3,d0
	bmi		.cookie_impossible
;
	TIMER_call	my_timer_func(pc),#HNDLR_SET
	tst		d0
	beq		.timer_failure
.final_install:
	xbios		Supexec,OS_check_1(pc)
	gemdos		Super,0.w
;-------
	move.l		d0,d4
	RAM_own		#1		;setup current bp as RAM owner
	RAM_add		#RAM_chunk	;get some RAM
	lea		my_layer(pc),a0
	move.l		a0,LAYER_next(a4)
;-------
	move.l		(ev_gemdos).w,IC_gemdos_XB+xb_next
	move.l		#IC_gemdos_XB+xb_code,(ev_gemdos).w
;-------
	gemdos		Super|_ind,d4
	gemdos		Ptermres,#resident_size,#0
;-------------------------------------
.ACC_launch:
	lea		ACC_launch_s(pc),a0
	bsr.s		report_error
.loop:
	bra		.loop
;-------------------------------------
.bad_launch:
	lea		bad_launch_s(pc),a0
	bra.s		.error_exit
;-------------------------------------
.cookie_conflict:
	lea	cookie_conflict_s(pc),a0
	bra.s	.error_exit
;-------------------------------------
.cookie_impossible:
	lea	cookie_impossible_s(pc),a0
	bra.s	.error_exit
;-------------------------------------
.bad_layer_list:
	lea		bad_layer_list_s(pc),a0
	bra.s		.error_exit
;-------------------------------------
.timer_failure:
	lea		timer_failure_s(pc),a0
	bra.s		.error_exit
;-------------------------------------
.STiK_not_found:
	lea		STiK_not_found_s,a0
	bra.s		.error_exit
;-------------------------------------
.STiK_not_valid:
	lea		STiK_not_valid_s,a0
	bra.s		.error_exit
;-------------------------------------
.driver_not_valid:
	lea		driver_not_valid_s,a0
	bra.s		.error_exit
;-------------------------------------
.layer_not_valid:
	lea		layer_not_valid_s(pc),a0
.error_exit:
	bsr.s		report_error
	gemdos		Pterm,#E_ERROR
;-------------------------------------
report_error:
	move.l		a0,-(sp)
	lea		error_title_s(pc),a0
	bsr.s		Cconws_sub
	move.l		(sp)+,a0
	bsr.s		Cconws_sub
	lea		error_tail_s(pc),a0
Cconws_sub:
	gemdos		Cconws,(a0)
	rts
;----------------------------------------------------------------------------
OS_check_1:
	move		sr,-(sp)
	ori		#$0700,sr
	move.l		(_cookies).w,a0
.cook_loop_1:
	movem.l		(a0)+,d0/d1
	tst.l		d0
	beq.s		.done_cookies
	lea		OS_check_1_t(pc),a1
.cook_loop_2:
	movem.l		(a1)+,d2/a2
	tst.l		d2
	beq.s		.cook_loop_1
	cmp.l		d2,d0
	bne.s		.cook_loop_2
	move.l		d1,(a2)
	bra.s		.cook_loop_1
;-------
.done_cookies:
	move		(sp),sr
	tst.w		(_longframe).w
	beq.s		.frame_known
	move.w		#8,frame_size
	move		#2,frame_offset
.frame_known:
	_a_init
	move.l		d0,line_a_base_p
	move.l		#$602C,currbp_p_p	;Some old TOS had this (but maybe not all)
	xbios		Keytbl,?,?,?
	move.l		d0,a0
	lea		-1(a0),a0		;NB: this assumes Kbshift stored at Keytbl-1
	move.l		a0,kbshift_p		;NB: So all early TOS have Kbshift data at Keytbl-1 !!!
	move.l		(_sysbase).w,a1
	move.l		os_selfbeg_p(a1),a0
	move		os_version(a0),d0
	cmp		#$102,d0
	blo.s		.done_sys_fix
	move.l		os_kbshift_p(a0),kbshift_p
	move.l		os_currbp_p_p(a0),currbp_p_p
.done_sys_fix:
	move		(sp)+,sr
	rts
;-------------------------------------
OS_check_1_t:
	dc.l	'MiNT',MiNT_p
	dc.l	'MagX',MagX_p
	dc.l	'nAES',nAES_p
	dc.l	'Gnva',Gnva_p
	dc.l	NUL
;----------------------------------------------------------------------------
;End of:	Non-resident initialization code
;----------------------------------------------------------------------------
;Start of:	Non-resident library code
;----------------------------------------------------------------------------
	make	JAR_links
	make	DOMAIN_links
;----------------------------------------------------------------------------
;End of:	Non-resident library code
;----------------------------------------------------------------------------
text_limit:
text_size	= text_limit-text_start
	SECTION	DATA
data_start:
;----------------------------------------------------------------------------
STinG_Load_s:
	dc.b	10,'STinG_Load',NUL
STiKmagic_s:
	dc.b	'STiKmagic',NUL
TRANSPORT_DRIVER_s:
	dc.b	'TRANSPORT_TCPIP',NUL
MODULE_DRIVER_s:
	dc.b	'MODULE_LAYER',NUL
;
ACC_launch_s:
	dc.b	'Drac_Emu error:',CR,LF
	dc.b	'This non-ACC, was launched as an ACC,',CR,LF
	dc.b	'so now you must reset the computer !',CR,LF
	dc.b	'I am looping forever to avoid damage',CR,LF
	dc.b	'that could occur if I try to exit !',CR,LF
	dc.b	NUL
;
bad_launch_s:	
	dc.b	'Drac_Emu error:',CR,LF
	dc.b	'This STX should only be launched by',CR,LF
	dc.b	'STinG, or another TCP/IP stack with',CR,LF
	dc.b	'a compatible module interface !',CR,LF
	dc.b	NUL
;
	EVEN
cookie_conflict_s:
	dc.l	DRACONIS_ID
	dc.b	' cookie already exists !',CR,LF
	dc.b	NUL
;
	EVEN
cookie_impossible_s:
	dc.l	DRACONIS_ID
	dc.b	' cookie can not be installed !',CR,LF
	dc.b	NUL
;
bad_layer_list_s:
	dc.b	'The list chain of STinG layers was',CR,LF
	dc.b	'not found...!',CR,LF
	dc.b	NUL
;
timer_failure_s:
	dc.b	'STinG TIMER_call function failed !',CR,LF
	dc.b	NUL
;
STiK_not_found_s:
	dc.b	'There is no STiK cookie in the jar !',CR,LF
	dc.b	NUL
;
STiK_not_valid_s:
	dc.b	'The STiK cookie data is corrupt !',CR,LF
	dc.b	NUL
;
driver_not_valid_s:
	dc.b	'The main STinG driver is not valid !',CR,LF
	dc.b	NUL
;
layer_not_valid_s:
	dc.b	'The STinG module layer is not valid !',CR,LF
	dc.b	NUL
;
error_title_s:
	dc.b	BEL,CR,LF
	dc.b	'------------'
	M_TITLE
	dc.b	' '
	M_VERSION
	dc.b	'------------',CR,LF
	dc.b	NUL
;
	EVEN
error_tail_s:
	dc.l	DRACONIS_ID
	dc.b	'installation aborted.',CR,LF
	dc.b	BEL,CR,LF,NUL
	EVEN
;----------------------------------------------------------------------------
data_limit:
data_size	=	data_limit-data_start
	SECTION	BSS
bss_start:
;----------------------------------------------------------------------------
		ds.l	200		;subroutine stack >= 100 longs
mystack:	ds.l	1		;top of subroutine stack
;----------------------------------------------------------------------------
bss_limit:
bss_size	=	bss_limit-bss_start
;----------------------------------------------------------------------------
initial_size	=	text_size+data_size+bss_size+$100
;----------------------------------------------------------------------------
		END
;----------------------------------------------------------------------------
;End of file:	ICNN_EMU.S
;----------------------------------------------------------------------------
