/* Module: X25Drv_Routines. Facility: X25 Interface Driver Abstract: X25_DRIVER provides upper level protocols with access to X25 circuits. This module implements the low-level details and protocol specific elements of the PSI protocol interface. Author: Original author Peter Dewildt Copyright ) 1988, CSIRO Division of Information Technology Modification History: 2.0 14-Aug-1990 Conversion by Bruce R. Miller, CMU NetDev Converted the whole thing to C, changing it into a run-time loadable IP transport in the process. (And you'd never believe what a bitch it was...) 1.0 06-Jul-1988 Initial Version */ #include #include #include #define MIN(a,b) ((a)>(b) ? (a) : (b)) typedef unsigned long ulong; typedef unsigned short ushort; typedef unsigned short uword; typedef unsigned char uchar; #define u_char unsigned char #define u_short unsigned short #define u_long unsigned long #define n_long long #include "CMUIP_SRC:[central.include]netconfig.h" #include "CMUIP_SRC:[central.include]netcommon.h" #include "X25drv.h" extern IPACP_Info_Structure *IPACP_Interface; /* from cmuip_src:[central.include] */ #include #include /* from cmuip_src:[central.include.netinet] */ #include #include /* from sys$library */ #include #include /***************************************************************************/ const #define max_packet_size 128 /* Maximum number of bytes to be */ /* transmitted in one packet */ #define call_data 0xCC /* User data field for IP connects */ #define call_mask 0xFF /* Corresponding mask */ #define timer_id 0x5AB3CD /* Unique 24 bit code to identify timer */ /* requests as belonging to this module.*/ /***************************************************************************/ /**************************************************************************** * * * Only one copy needs to be kept of the following data for the whole driver* * */ char X25_dev_str[20] = "NWA0:"; unsigned long dev_desc[2]; X25_Interface_Structure listener; int catchall_started; nfb_structure nfb; ulong nfb_desc[2]; iosb_psi_type iosb; ulong sts; char ncb[100]; ulong ncb_desc[2]; /****************************************************************************/ DRV$LOG_FAO (s,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) { long unsigned int d[2]; d[0] = strlen(s); d[1] = s; (*IPACP_Interface->ACPI$LOG_FAO)(d,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10); } DRV$ERROR_FAO (s,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) { long unsigned int d[2]; d[0] = strlen(s); d[1] = s; (*IPACP_Interface->ACPI$ERROR_FAO)(d,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10); } DRV$FATAL_FAO (s,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) { long unsigned int d[2]; d[0] = strlen(s); d[1] = s; (*IPACP_Interface->ACPI$FATAL_FAO)(d,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10); } int index (X25_Int) X25_Interface_Structure *X25_Int; { if (X25_Int->X25I$dev_config != NULL) return(X25_Int->X25I$dev_config->dcmib_ifIndex); return(-1); } /***************************************************************************** * * * Start timeout before disconnecting virtual link to remote DTE * * A unique number must be assigned to each timeout request; the number must * * not interfere with any assigned to timers started elsewhere in the whole * * package. * * */ void Timer_AST(); start_timer (X25_Int) X25_Interface_Structure *X25_Int; { int sts,id; return; /* We have to decide on a way to define timeouts before enabling this ID = .X25_Int; Status = $SETIMR ( DAYTIM = X25_Int [ X25I$Timeout ] ASTADR = Timer_AST, REQIDT = .ID ); IF NOT .Status THEN DRV$FATAL_FAO('!%T error starting DECnet timer, status is %X!XL!/', 0,.Status); */ } stop_timer ( X25_Int ) X25_Interface_Structure *X25_Int; { int sts,id; return; /* We have to decide on a way to define timeouts before enabling this ID = .X25_Int; Status = $CANTIM ( REQIDT = .ID ); IF NOT .Status THEN DRV$FATAL_FAO('!%T error stopping DECnet timer, status is %X!XL!/', 0,Status); */ } /****************************************************************************/ swap_bytes (i) int i; { return (i << 8) + i / 256; } dump_ip (buff,buff_size) struct ip *buff; int buff_size; { unsigned char (*i_src)[4],(*i_dst)[4]; int i_paclen, i_id, i_fragoff, i_cksum; unsigned int i_source,i_dest; i_paclen = swap_bytes( buff->ip_hl ); i_id = swap_bytes( buff->ip_id ); i_fragoff = swap_bytes( buff->ip_off ); i_cksum = swap_bytes( buff->ip_sum ); i_source = &buff->ip_src; i_dest = &buff->ip_dst; i_src = &i_source; i_dst = &i_dst; DRV$LOG_FAO(" Vers: !UB Len: !UB SvcTyp: !UB PacLen: !UW ID: !UW!/", buff->ip_v, buff->ip_len, buff->ip_tos, i_paclen, i_id); DRV$LOG_FAO(" FragOff: !UW Tim2Liv: !UB Proto: !UB Cksum: !UW!/", i_fragoff, buff->ip_ttl, buff->ip_p, i_cksum); DRV$LOG_FAO(" Src: !UB.!UB.!UB.!UB Dest: !UB.!UB.!UB.!UB!/", i_src[1], i_src[2], i_src[3], i_src[4], i_dst[1],i_dst[2],i_dst[3],i_dst[4]); } /****************************************************************************/ void item_add_string ( item_string , type_code , param ) uchar *item_string; uword type_code; uchar *param; { int n = 5; uchar *ptr; n += strlen(param); ptr = item_string + item_string[0]; *ptr++ = (n % 256); *ptr++ = (n >> 8); *ptr++ = (type_code % 256); *ptr++ = (type_code >> 8); *ptr++ = strlen(param); strcpy(ptr,param); item_string[0] += n; } void item_add_word ( item_string , type_code , param ) uchar *item_string; uword type_code; uword param; { int n = 6; uchar *ptr; ptr = item_string + item_string[0]; *ptr++ = (n % 256); *ptr++ = (n >> 8); *ptr++ = (type_code % 256); *ptr++ = (type_code >> 8); *ptr++ = (param % 256); *ptr++ = (param >> 8); item_string[0] += n; } void item_add_code ( item_string , type_code ) uchar *item_string; uword type_code; { int n = 4; uchar *ptr; ptr = item_string + item_string[0]; *ptr++ = (n % 256); *ptr++ = (n >> 8); *ptr++ = (type_code % 256); *ptr++ = (type_code >> 8); item_string[0] += n; } /*****************************************************************************/ /* */ /* Extract the remote DTE and subaddress from an incoming call's NCB */ /* */ extract_remdte ( ncb , ncb_len ) uchar *ncb; int ncb_len; { int i; int len; int typ; char dte_buff[256]; char sub_buff[256]; char ret_buff[256]; /* Oh, what a hack... */ uchar *sp; i = 0; sp = ncb; while (i < ncb_len) { len = ncb[i] + 256 * ncb[i+1]; typ = ncb[i+2] + 256 * ncb[i+3]; len -= 4; i += 4; if (typ == psi$c_ncb_remdte) { memcpy(&ncb[i+1],dte_buff,ncb[i]); dte_buff[ncb[i]] = 0; } else if (typ == psi$c_ncb_remsubadr) { memcpy(&ncb[i+1],sub_buff,ncb[i]); dte_buff[ncb[i]] = 0; } i = i + len; } strcpy(ret_buff,dte_buff); strcat(ret_buff,"-"); strcpy(ret_buff,dte_buff); return(ret_buff); } /*****************************************************************************/ /* */ /* Extract reverse charge information from an incoming call's NCB */ /* */ int extract_revchg ( ncb , ncb_len ) uchar *ncb; int ncb_len; { int i = 0; int len; int typ; char dte_buff[256]; char sub_buff[256]; char ret_buff[256]; /* Oh, what a hack... */ uchar *sp; DRV$LOG_FAO(" NCB size is !UL!/",ncb_len); while (i < ncb_len) { len = ncb[i] + 256 * ncb[i+1]; typ = ncb[i+2] + 256 * ncb[i+3]; len -= 4; i += 4; if (typ == psi$c_ncb_revchg) return(TRUE); i += len; } } /***************************************************************************/ dump_ncb (ncb,ncb_len) char *ncb; int ncb_len; { int i,len,typ,tmp; long int desc[2]; DRV$LOG_FAO(" NCB size is !UL!/",ncb_len); i = 1; while (i < ncb_len) { len = ncb[i] + 256*ncb[i+1]; typ = ncb[i+2] + 256*ncb[i+3]; len -= 4; i += 4; tmp = *(int *)&ncb[i]; desc[0] = (int)ncb[i]; /* set up descriptor for counted string */ desc[1] = &(ncb[i+1]); /*!!!HACK!!! the ncb[i]'s in the next few lines are wrong, maybe! */ switch (typ) { case psi$c_ncb_ici : DRV$LOG_FAO(" NCB Incoming Call Id = !UL!/",tmp); case psi$c_ncb_userdata : DRV$LOG_FAO(" NCB User Data = !AS!/",desc); /* case psi$c_ncb_locnet : DRV$LOG_FAO(" NCB local network = !AS!/",desc); */ case psi$c_ncb_pridst : DRV$LOG_FAO(" NCB dest priority = !UB!/",tmp); case psi$c_ncb_incoming_dte : DRV$LOG_FAO(" NCB incoming dte = !AS!/",desc); case psi$c_ncb_locdte : DRV$LOG_FAO(" NCB local dte = !AS!/",desc); case psi$c_ncb_remdte : DRV$LOG_FAO(" NCB remote dte = !AS!/",desc); case psi$c_ncb_locsubadr : DRV$LOG_FAO(" NCB local subaddress = !AS!/",desc); case psi$c_ncb_remsubadr : DRV$LOG_FAO(" NCB remote subaddress = !AS!/",desc); default : DRV$LOG_FAO(" type code = !UL!/",typ); } i += len; } } dump_mbx_message( X25_Int ) X25_Interface_Structure *X25_Int; { int desc[2]; desc[0] = X25_Int->X25I$mbx_message.count1; desc[1] = X25_Int->X25I$mbx_message.name; DRV$LOG_FAO("!%T Mailbox message received on device !SL!/",0, index(X25_Int)); DRV$LOG_FAO("!%T associated DTE is !AD/!AD!/",0, UNDESC(X25_Int->X25I$remote_dte_dsp), UNDESC(X25_Int->X25I$receive_dte_dsp)); DRV$LOG_FAO("!%T message type is !UW!/",0, X25_Int->X25I$mbx_message.msgtype); DRV$LOG_FAO("!%T device to which message applies is !AS!UW!/", 0,&desc,X25_Int->X25I$mbx_message.unit); if (X25_Int->X25I$mbx_message.msgtype == MSG$_CONNECT) dump_ncb(X25_Int->X25I$mbx_message.info, X25_Int->X25I$mbx_message.count2); } /*****************************************************************************/ /* ROUTINE drop_link ( X25_Int : REF X25_Interface_Structure ) : NOVALUE = BEGIN LOCAL Status; Status = $DASSGN ( CHAN = .X25_Int[X25I$net_chan]); IF NOT .Status THEN DRV$ERROR_FAO("!%T Error dropping DECnet link with node !AS, device !AS, status = %X!XL!/", 0, X25_Int[X25I$Node_name], X25_Int[X25I$NCB_desc], .Status) ELSE BEGIN DRV$LOG_FAO( "!%T Successful dropping of DECnet link with node !AS, device !AS!/", 0, X25_Int[X25I$Node_name], X25_Int[X25I$NCB_desc]); IF .X25_Int[X25I$mbx_chan] NEQ 0 THEN $DASSGN(CHAN = .X25_Int[X25I$mbx_chan]); X25_Int[X25I$X25_connected] = 0; stop_timer ( .X25_Int ) END; END; */ drop_link ( X25_Int ) X25_Interface_Structure *X25_Int; { int sts; sts = sys$qiow( 0, X25_Int->X25I$psi_chan, /* chan */ IO$_DEACCESS, /* func */ &X25_Int->X25I$mbx_iosb, /* iosb */ NULL,0, /* astadr,astprm */ 0,0,0,0,0,0); /* p1-p6 */ if (!ERROR(sts)) sts = X25_Int->X25I$mbx_iosb.status; if (ERROR(sts)) DRV$ERROR_FAO("!%T Error dropping link with DTE !AD, device !SL, status = %X!XL!/",0, UNDESC(X25_Int->X25I$receive_dte_dsp), index(X25_Int),sts); else { DRV$LOG_FAO("!%T Successful dropping of link with !AS, device !SL!/",0, UNDESC(X25_Int->X25I$receive_dte_dsp), index(X25_Int)); X25_Int->X25I$connected = FALSE; X25_Int->X25I$receive_ptr = 0; stop_timer(X25_Int); } } /*****************************************************************************/ shut_channels ( X25_Int ) X25_Interface_Structure *X25_Int; { if (X25_Int->X25I$mbx_chan != 0) sys$dassgn(X25_Int->X25I$mbx_chan); if (X25_Int->X25I$psi_chan != 0) sys$dassgn(X25_Int->X25I$psi_chan); X25_Int->X25I$connected = FALSE; X25_Int->X25I$receive_ptr = 0; stop_timer(X25_Int); } /****************************************************************************/ /* */ /* Connection timeout has occured - simply drop the link */ /* Any messages caught at the time will be sorted out by the higher level */ /* protocols. */ /* */ void Timer_AST ( X25_Int ) X25_Interface_Structure *X25_Int; { DRV$LOG_FAO("!%T connection timeout for DECnet device !AS!/",0, X25_Int->X25I$NCB_desc); if (X25_Int->X25I$connected) drop_link(X25_Int); } /*****************************************************************************/ /* */ /* Incoming data is available - read it. /* */ /* This procedure is executed within an AST - so be careful not to use any */ /* data structures that could be in use at the time. */ /* */ void incoming_data( X25_Int ) X25_Interface_Structure *X25_Int; { long sts; stop_timer(X25_Int); /* */ /* Allocate a receive buffer if we don't have one */ /* */ if (X25_Int->X25I$receive_addr == NULL) { X25_Int->X25I$receive_addr = DRV$SEG_GET(DRV$MAX_PHYSICAL_BUFSIZE); X25_Int->X25I$receive_ptr = 0; } /* */ /* Check that there is still room in the receive buffer */ /* */ if (X25_Int->X25I$receive_ptr >= DRV$MAX_PHYSICAL_BUFSIZE) { DRV$ERROR_FAO( "!%T Buffer overflow from DTE !AD, device !SL - data discarded!/", 0, UNDESC(X25_Int->X25I$receive_dte_dsp), index(X25_Int)); X25_Int->X25I$receive_ptr = 0; } /* */ /* Read segment currently in memory into next part of receive buffer */ /* */ /* DRV$LOG_FAO("!%T Start segment read from DTE !AD, device !SL!/",*/ /* 0,UNDESC(X25_Int->X25I$receive_dte_dsp),ndx); */ /* */ sts = sys$qiow (0, /* Event Flag */ X25_Int->X25I$psi_chan, /* chan */ IO$_READVBLK + IO$M_NOW, /* func */ &X25_Int->X25I$mbx_iosb, /* iosb */ NULL,0, /* astadr,astprm */ *X25_Int->X25I$receive_addr + X25_Int->X25I$receive_ptr, DRV$MAX_PHYSICAL_BUFSIZE - X25_Int->X25I$receive_ptr, 0,0,0,0); /* p3-p6 */ if (!ERROR(sts)) sts = X25_Int->X25I$mbx_iosb.status; if (sts == SS$_NODATA) { DRV$ERROR_FAO( "!%T Curious - there is no data to read from DTE !AD, device !SL!/", 0, UNDESC(X25_Int->X25I$receive_dte_dsp), index(X25_Int)); DRV$SEG_FREE(DRV$MAX_PHYSICAL_BUFSIZE,X25_Int->X25I$receive_addr); X25_Int->X25I$receive_addr = NULL; X25_Int->X25I$receive_ptr = NULL; } else if (ERROR(sts)) { DRV$ERROR_FAO( "!%T Error reading from DTE !AS, device !SL, status = %X!XL!/", 0,UNDESC(X25_Int->X25I$receive_dte_dsp), index(X25_Int),sts); DRV$SEG_FREE(DRV$MAX_PHYSICAL_BUFSIZE,X25_Int->X25I$receive_addr); X25_Int->X25I$receive_addr = NULL; X25_Int->X25I$receive_ptr = 0; } else { X25_Int->X25I$receive_ptr = X25_Int->X25I$receive_ptr + X25_Int->X25I$mbx_iosb.count; /* */ /* If all segments have been input, process data */ /* IP_RECEIVE will deallocate buffer */ /* */ if ((X25_Int->X25I$mbx_iosb.sec_status | psi$m_moredata) == 0) { DRV$LOG_FAO("!%T Message of size !UW received:!/", 0,X25_Int->X25I$receive_ptr); dump_ip(X25_Int->X25I$receive_addr,X25_Int->X25I$receive_ptr); DRV$IP_RECEIVE(X25_Int->X25I$receive_addr,DRV$MAX_PHYSICAL_BUFSIZE, X25_Int->X25I$receive_addr, X25_Int->X25I$receive_ptr, index(X25_Int)); X25_Int->X25I$receive_addr = NULL; X25_Int->X25I$receive_ptr = 0; } } start_timer(X25_Int); } /****************************************************************************/ /* */ /* A connection request has been received which we are to reject because */ /* */ /* - it is from a DTE which we do not know about (as it was not specified */ /* in a device parameter string */ /* - it is a reverse charge call and we are not accepting reverse charge */ /* calls */ /* */ reject_connection( X25_Int ) X25_Interface_Structure *X25_Int; { int sts; ulong conn_desc[2]; conn_desc[0] = X25_Int->X25I$mbx_message.count2; /* Use incoming NCB */ conn_desc[1] = X25_Int->X25I$mbx_message.info; sts = sys$qiow (0, /* Event Flag */ X25_Int->X25I$psi_chan, /* chan */ IO$_ACCESS + IO$M_ABORT, /* func */ &X25_Int->X25I$mbx_iosb, /* iosb */ NULL,0, /* astadr,astprm */ 0, /* p1 */ &conn_desc, /* p2 */ 0,0,0,0); /* p3-p6 */ if (!ERROR(sts)) sts = X25_Int->X25I$mbx_iosb.status; if (ERROR(sts)) { int desc[2]; extract_remdte( X25_Int->X25I$mbx_message.info, X25_Int->X25I$mbx_message.count2, desc); DRV$ERROR_FAO( "!%T Error rejecting connection from !AS, status = %X!XL!/", 0,&desc,sts); } } /*****************************************************************************/ /* */ /* Accept a connection request */ /* */ accept_call ( X25_Int ) X25_Interface_Structure *X25_Int; { int sts; ulong conn_desc[2]; conn_desc[0] = X25_Int->X25I$mbx_message.count2; /* Use incoming NCB */ conn_desc[1] = &X25_Int->X25I$mbx_message.info; sts = sys$qiow (0, /* Event Flag */ X25_Int->X25I$psi_chan, /* chan */ IO$_ACCESS + IO$M_ACCEPT, /* func */ &X25_Int->X25I$mbx_iosb, /* iosb */ NULL,0, /* astadr,astprm */ 0, /* p1 */ &conn_desc, /* p2 */ 0,0,0,0); /* p3-p6 */ if (!ERROR(sts)) sts = X25_Int->X25I$mbx_iosb.status; if (ERROR(sts)) { DRV$ERROR_FAO( "!%T Error accepting connection from !AD, device !SL, status = %X!XL!/",0, UNDESC(X25_Int->X25I$receive_dte_dsp), index(X25_Int),sts); } else { DRV$LOG_FAO("!%T Connection from DTE !AD, device !SL accepted!/", 0, UNDESC(X25_Int->X25I$receive_dte_dsp), index(X25_Int)); X25_Int->X25I$connected = TRUE; X25_Int->X25I$host_initiated = FALSE; X25_Int->X25I$receive_ptr = 0; stop_timer(X25_Int); start_timer(X25_Int); } } /*****************************************************************************/ /* */ /* A connection request has been received */ /* - accept the connection */ /* */ /* This procedure is executed within an AST - so be careful not to use any */ /* data structures that could be in use at the time. */ /* */ connect_request( X25_Int ) X25_Interface_Structure *X25_Int; { if (X25_Int == NULL) { int desc[2]; extract_remdte( X25_Int->X25I$mbx_message.info, X25_Int->X25I$mbx_message.count2, desc); DRV$ERROR_FAO( "!%T An IP connection request from unknown DTE !AS received - call rejected!/",0,desc); reject_connection(X25_Int); } else { if (X25_Int->X25I$mbx_message.unit != 0) DRV$LOG_FAO("!%T connection to DTE !AD, device !SL confirmed!/", 0, UNDESC(X25_Int->X25I$remote_dte_dsp), index(X25_Int)); else { if (extract_revchg(X25_Int->X25I$mbx_message.info,X25_Int->X25I$mbx_message.count2)) { if (X25_Int->X25I$receive_revchg) { DRV$LOG_FAO( "!%T Reverse charge connection request received from DTE !AD, device !SL!/", 0,UNDESC(X25_Int->X25I$receive_dte_dsp),index(X25_Int)); accept_call(X25_Int); } else { DRV$ERROR_FAO ("!%T reverse charge connection request rejected from DTE !AD, device !SL!/", 0,UNDESC(X25_Int->X25I$receive_dte_dsp),index(X25_Int)); reject_connection(X25_Int); } } else { DRV$LOG_FAO("!%T connection request received from DTE !AD, device !SL!/", 0,UNDESC(X25_Int->X25I$receive_dte_dsp),index(X25_Int)); accept_call(X25_Int); } } } } void circuit_reset(X25_Int) X25_Interface_Structure *X25_Int; { if (X25_Int->X25I$host_initiated) DRV$ERROR_FAO( "!%T Request to reset link to DTE !AD, device !SL received!/", 0,UNDESC(X25_Int->X25I$remote_dte_dsp),index(X25_Int)); else DRV$ERROR_FAO( "!%T Request to reset link from DTE !AD, device !SL received!/", 0,UNDESC(X25_Int->X25I$remote_dte_dsp),index(X25_Int)); drop_link(X25_Int); } void circuit_disconnect(X25_Int) X25_Interface_Structure *X25_Int; { if (X25_Int->X25I$connected) { if (X25_Int->X25I$host_initiated) DRV$ERROR_FAO( "!%T Request to disconnect link to DTE !AD, device !SL received!/", 0,UNDESC(X25_Int->X25I$remote_dte_dsp),index(X25_Int)); else DRV$ERROR_FAO( "!%T Request to disconnect link from DTE !AD, device !SL received!/", 0,UNDESC(X25_Int->X25I$receive_dte_dsp),index(X25_Int)); drop_link(X25_Int); } else DRV$ERROR_FAO("!%T Unable to connect to DTE !AD, device !SL!/", 0,UNDESC(X25_Int->X25I$remote_dte),index(X25_Int)); } /* */ /* DECnet has been shut down */ /* */ void decnet_shutdown ( X25_Int ) X25_Interface_Structure *X25_Int; { if (X25_Int->X25I$connected) if (X25_Int->X25I$host_initiated) DRV$ERROR_FAO( "!%T DECnet shutting down, breaking link to !AD, device !SL!/", 0,UNDESC(X25_Int->X25I$remote_dte_dsp),index(X25_Int)); else DRV$ERROR_FAO( "!%T DECnet shutting down, breaking link from !AD,device !SL!/", 0,UNDESC(X25_Int->X25I$receive_dte_dsp),index(X25_Int)); shut_channels(X25_Int); } /*****************************************************************************/ void mbx_ast(); /*****************************************************************************/ /* */ /* This procedures starts a new read on the associated mailbox for the PSI */ /* channel. */ /* */ /* This procedure is executed within an AST - so be careful not to use any */ /* data structures that could be in use at the time. */ /* */ /* ROUTINE start_mailbox_read ( X25_Int : REF X25_Interface_Structure ) = BEGIN LOCAL Status; Status = $QIO ( chan = .X25_Int[X25I$mbx_chan], func = IO$_READVBLK, iosb = X25_Int[X25I$mbx_iosb], astadr = mbx_ast, astprm = .X25_Int, p1 = X25_Int[X25I$mbx_message], p2 = mbx_message_blen ); IF NOT .Status THEN DRV$FATAL_FAO( "!%T Error starting mailbox read for DECnet node !AS, device !AS, status = %X!XL!/", 0,X25_Int[X25I$Node_name],X25_Int[X25I$NCB_desc],.Status); .Status END; */ int start_mailbox_read ( X25_Int ) X25_Interface_Structure *X25_Int; { int sts; uword chn; sts = sys$qiow (0, /* Event Flag */ X25_Int->X25I$mbx_chan, /* chan */ IO$_READVBLK, /* func */ &X25_Int->X25I$mbx_iosb, /* iosb */ NULL,0, /* astadr,astprm */ X25_Int->X25I$mbx_message, /* p1 */ sizeof(X25_Int->X25I$mbx_message), /* p2 */ 0,0,0,0); /* p3-p6 */ if (ERROR(sts)) { DRV$FATAL_FAO ( "!%T Error starting mailbox read for DTE !AD/!AD, device !SL, status = %X!XL!/",0, UNDESC(X25_Int->X25I$remote_dte_dsp), UNDESC(X25_Int->X25I$receive_dte_dsp), index(X25_Int),sts); } return (sts); } /****************************************************************************/ /* */ /* This AST routine is called whenever a message has been received on the */ /* associated mailbox for the PSI channel. */ /* */ void mbx_ast (X25_Int) X25_Interface_Structure *X25_Int; { int sts; sts = X25_Int->X25I$mbx_iosb.status; if (ERROR(sts)) { DRV$ERROR_FAO( "!%T X25 Mailbox read error for DTE !AS/!AS, device !SL, status =%X!XL!/",0, UNDESC(X25_Int->X25I$remote_dte_dsp), UNDESC(X25_Int->X25I$receive_dte_dsp), index(X25_Int),sts); } /* dump_mbx_message(ndx); */ switch (X25_Int->X25I$mbx_message.msgtype) { case MSG$_CONNECT: connect_request(X25_Int); case MSG$_RESET: circuit_reset(X25_Int); case MSG$_DISCON: circuit_disconnect(X25_Int); case MSG$_NETSHUT: decnet_shutdown(X25_Int); case MSG$_INCDAT: incoming_data(X25_Int); } start_mailbox_read(X25_Int); } /****************************************************************************/ /* */ /* Attempt to connect to remote DTE */ /* */ void attempt_connection ( X25_Int ) X25_Interface_Structure *X25_Int; { ncb[0] = 0; item_add_string(ncb,psi$c_ncb_userdata, call_data); item_add_string(ncb,psi$c_ncb_remdte, X25_Int->X25I$remote_dte); if (X25_Int->X25I$remote_dte_sub[0] != 0) item_add_string(ncb,psi$c_ncb_remsubadr,X25_Int->X25I$remote_dte_sub); if (X25_Int->X25I$local_dte[0] != 0) item_add_string(ncb,psi$c_ncb_locdte, X25_Int->X25I$local_dte); if (X25_Int->X25I$local_dte_sub[0] != 0) item_add_string(ncb,psi$c_ncb_locsubadr,X25_Int->X25I$local_dte_sub); if (X25_Int->X25I$remote_revchg) item_add_code (ncb,psi$c_ncb_revchg); ncb_desc[0] = ncb[0]; ncb_desc[1] = &ncb[1]; DRV$LOG_FAO("!%T attempting to connect to DTE !AS, device !SL!/",0, UNDESC(X25_Int->X25I$remote_dte_dsp),index(X25_Int)); sts = sys$qiow (0, /* Event Flag */ X25_Int->X25I$psi_chan, /* chan */ IO$_ACCESS, /* func */ &iosb, /* iosb */ NULL,0, /* astadr,astprm */ 0, /* p1 */ &ncb_desc, /* p2 */ 0,0,0,0); /* p3-p6 */ if (!ERROR(sts)) sts = iosb.status; if (ERROR(sts)) { DRV$ERROR_FAO( "!%T unable to connect to remote DTE !AD, device !SL, status = %X!XL!/",0, UNDESC(X25_Int->X25I$remote_dte_dsp), index(X25_Int),sts); } else { DRV$LOG_FAO("!%T connection made to DTE !AS, device !SL!/", 0,UNDESC(X25_Int->X25I$remote_dte_dsp),index(X25_Int)); X25_Int->X25I$connected = TRUE; X25_Int->X25I$host_initiated = TRUE; X25_Int->X25I$receive_ptr = 0; stop_timer(X25_Int); start_timer(X25_Int); } } /****************************************************************************/ /* */ /* Extract the components of the device parameters */ /* */ /* Format is: */ /* */ /* Tnn;S[R]sssssssss-ss;R[R]rrrrrrrrr-rr;Llllllllll-ll: */ /* */ /* where */ /* nn is the time in seconds after which a connection */ /* will be broken if there is no activity (either send */ /* or receive) */ /* */ /* sssssssss-ss is the DTE address and optional subaddress of the */ /* remote node; all connections initiated from this */ /* end specify this address; if SR is specified */ /* instead of just S, then calls will be placed with */ /* reverse charging (i.e. remote DTE pays) */ /* */ /* rrrrrrrrr-rr is the DTE address and optional subaddress */ /* specified in connections received from the remote */ /* node; we will only accept connections with these */ /* values in the sending DTE address fields; if not */ /* specified the first DTE address and subaddress is */ /* used. If RR is specified instead of just R then we */ /* are willing to accept reverse charge calls. */ /* */ /* lllllllll-ll is the DTE address of this node; this address is */ /* inserted in packets that are sent to the remote */ /* nodes. This can be required where the address is */ /* not automatically inserted by the network. */ /* */ /* Note that as the string is always terminated by a colon most code */ /* does not need to check for end of string. */ /* */ int get_timeout(s,timeout) char *s; quadword *timeout; { long unsigned int sts; int dd,hh,mm,ss; int inc; char atime[30]; long int atime_desc[2]; if (isdigit(*s < '0') || (*s > '9')) DRV$FATAL_FAO( "!%T No timeout value in X25 parameter string.!/", 0); inc = sscanf(s,"%d",&ss); sprintf(atime,"%2d %2d:%2d:%2d", ss/(60*60*24), ss/(60*60), ss/60, ss%60); atime_desc[0] = strlen(atime); atime_desc[1] = atime; sts = sys$bintim(&atime_desc,timeout); if (ERROR(sts)) DRV$FATAL_FAO("!%T invalid X25 timeout !AS!/", 0,s); return(inc); } /* */ /* Get a dte address */ /* Format is */ /* Rnnnnnnnnnnnnnn-nn */ /* if R is specified then reverse charg */ get_dte(s,dte,sub,rev) char *s; char *dte; char *sub; uchar *rev; { int i = 0; int ss; char *s2 = s; *dte = 0; *sub = 0; *rev = FALSE; if (*s == 'R') { *rev = TRUE; s++; } if (isdigit(*s)) { s += sscanf(s,"%d",&ss); sprintf(dte,"%d",ss); } if (*s == '-') { s++; if (isdigit(*s)) { s += sscanf(s,"%d",&ss); sprintf(sub,"%d",ss); } } return(s-s2); } get_parameters ( X25_Int , param_string , param_size ) X25_Interface_Structure *X25_Int; char *param_string; uword param_size; { char c; int i,max_i; int dummy; max_i = param_size; /* */ /* Initialize variables */ /* */ X25_Int->X25I$timeout.l.l1 = 0; X25_Int->X25I$timeout.l.l2 = 0; X25_Int->X25I$remote_revchg = FALSE; X25_Int->X25I$receive_revchg = FALSE; X25_Int->X25I$remote_dte[0] = 0; X25_Int->X25I$remote_dte_sub[0] = 0; X25_Int->X25I$receive_dte[0] = 0; X25_Int->X25I$receive_dte_sub[0] = 0; X25_Int->X25I$local_dte[0] = 0; X25_Int->X25I$local_dte_sub[0] = 0; /* */ /* process parameters */ /* */ i = 1; while (i < max_i) { /* < used as last character is always colon */ switch (c = param_string[i++]) { case 'S': i += get_dte(¶m_string[i], X25_Int->X25I$remote_dte, X25_Int->X25I$remote_dte_sub, &X25_Int->X25I$remote_revchg); case 'R': i += get_dte(¶m_string[i], X25_Int->X25I$receive_dte, X25_Int->X25I$receive_dte_sub, &X25_Int->X25I$receive_revchg); case 'L': i += get_dte(¶m_string[i], X25_Int->X25I$local_dte, X25_Int->X25I$local_dte_sub, &dummy); case 'T': i += get_timeout(¶m_string[i], &X25_Int->X25I$timeout); case ';': break; default: DRV$FATAL_FAO("!%T Invalid code [!AD] in X25 parameter string, device !AD !/", 0,0,&c,param_size,param_string); } } /* */ /* Apply default for receiving DTE */ /* */ if (X25_Int->X25I$receive_dte[0] == 0) { strcpy(X25_Int->X25I$receive_dte,&X25_Int->X25I$remote_dte); if (X25_Int->X25I$receive_dte_sub[0] == 0) strcpy(X25_Int->X25I$receive_dte_sub,X25_Int->X25I$remote_dte_sub); } /* */ /* Check that a remote DTE has been specified */ /* */ if (X25_Int->X25I$remote_dte[0] == 0) DRV$FATAL_FAO("!%T X25 Remote DTE address not specified, device !SL!/", 0,index(X25_Int)); /* */ /* Check that a timeout has been specified */ /* */ if ((X25_Int->X25I$timeout.l.l1 == 0) && (X25_Int->X25I$timeout.l.l2 == 0)) DRV$FATAL_FAO("!%T X25 Timeout has not been specified, device !SL!/", 0,index(X25_Int)); /* */ /* Check for 0-0 code used to prevent connections being made or */ /* accepted. */ /* */ if ((X25_Int->X25I$remote_dte[0] == 0) && (X25_Int->X25I$remote_dte_sub[0] == 0)) X25_Int->X25I$outgoing_calls_permitted = FALSE; else X25_Int->X25I$outgoing_calls_permitted = TRUE; if ((X25_Int->X25I$receive_dte[0] == 0) && (X25_Int->X25I$receive_dte_sub[0] == 0)) X25_Int->X25I$incoming_calls_permitted = FALSE; else X25_Int->X25I$incoming_calls_permitted = TRUE; /* */ /* Set up display form of DTE address for messages */ /* */ strcpy(X25_Int->X25I$remote_dte_dsp,X25_Int->X25I$remote_dte); if (X25_Int->X25I$remote_dte_sub[0] != 0) { strcat(X25_Int->X25I$remote_dte_dsp,"-"); strcat(X25_Int->X25I$remote_dte_dsp,X25_Int->X25I$remote_dte_sub); } strcpy(X25_Int->X25I$receive_dte_dsp,X25_Int->X25I$receive_dte); if (X25_Int->X25I$receive_dte_sub[0] != 0) { strcat(X25_Int->X25I$receive_dte_dsp,"-"); strcat(X25_Int->X25I$receive_dte_dsp,X25_Int->X25I$receive_dte_sub); } strcpy(X25_Int->X25I$local_dte_dsp ,X25_Int->X25I$local_dte); if (X25_Int->X25I$local_dte_sub[0] != 0) { strcat(X25_Int->X25I$local_dte_dsp,"-"); strcat(X25_Int->X25I$local_dte_dsp,X25_Int->X25I$local_dte_sub); } } /*****************************************************************************/ /* */ /* Start the Catchall channel. */ /* */ /* The Catchall channel traps calls from unknown DTEs i.e. those that have */ /* not been specified in the 'R' parameter for the device. */ /* Trapping and logging these calls helps in determining the correct value */ /* to supply for the 'R' parameter. */ /* */ void start_catchall () { short c1,c2; ulong sts; /* with dev_config [-1] do */ /* */ /* Assign to catchall PSI channel */ /* */ sts = lib$asn_wth_mbx ( &dev_desc, /* device-name */ sizeof(listener.X25I$mbx_message), /* maximum message size */ sizeof(listener.X25I$mbx_message)*4, /* buffer-quota */ c1, /* device-channel */ c2 /* mailbox-channel */ ); if (ERROR(sts)) { DRV$ERROR_FAO( "!%T Error assigning to catchall PSI channel, status = %X!XL!/", 0,sts); } /* */ /* Declare this to be a network process to receive unknown IP */ /* messages */ /* */ if (!ERROR(sts)) { listener.X25I$psi_chan = c1; listener.X25I$mbx_chan = c2; nfb.acp_function = NFB$C_DECLNAME; nfb.terminator = 0; nfb_desc[0] = sizeof(nfb); nfb_desc[1] = &nfb; ncb[0] = 0; item_add_string(ncb,psi$c_ntd_acclvl, "X25L3"); item_add_string(ncb,psi$c_ntd_usrdata, call_data); item_add_string(ncb,psi$c_ntd_datmsk, call_mask); item_add_word (ncb,psi$c_ntd_priority, 0); ncb_desc[0] = ncb[0]; ncb_desc[1] = &ncb[1]; sts = sys$qiow( 0, listener.X25I$psi_chan, /* chan */ IO$_ACPCONTROL, /* func */ &iosb, /* iosb */ NULL,0, /* astadr,astprm */ &nfb_desc, /* p1 */ &ncb_desc, /* p2 */ 0,0,0,0); /* p3-p6 */ if (!ERROR(sts)) sts = iosb.status; if (ERROR(sts)) { DRV$ERROR_FAO( "!%T Error declaring network process for catchall channel, status = %X!XL!/",0,sts); } /* */ /* Start read on mailbox for connection requests etc */ /* */ if (ERROR(sts)) sts = start_mailbox_read(&listener); } catchall_started = TRUE; } /*****************************************************************************/ void parameter_summary (X25_Int) X25_Interface_Structure *X25_Int; { uword tl; char tm[16]; sys$asctim( &tl, /* timelen */ tm, /* timebuf */ &X25_Int->X25I$timeout, /* timadr */ 0); DRV$LOG_FAO("!%T Initializing X25 link, device !SL!/",0, index(X25_Int)); if (X25_Int->X25I$outgoing_calls_permitted) { DRV$LOG_FAO("!%T - connections to remote DTE !AD allowed!/",0, strlen(X25_Int->X25I$remote_dte_dsp), X25_Int->X25I$remote_dte_dsp); if (X25_Int->X25I$remote_revchg) DRV$LOG_FAO( "!%T - outgoing calls will be made with reverse charge!/",0); else DRV$LOG_FAO( "!%T - outgoing calls will not be made with reverse charge!/" ,0); } else DRV$LOG_FAO("!%T - outgoing calls not permitted!/",0); if (X25_Int->X25I$incoming_calls_permitted) { DRV$LOG_FAO("!%T - connections from DTE !AD accepted!/",0, UNDESC(X25_Int->X25I$receive_dte_dsp)); if (X25_Int->X25I$receive_revchg) DRV$LOG_FAO( "!%T - incoming reverse charge calls will be accepted!/",0); else DRV$LOG_FAO( "!%T - incoming reverse charge calls won't be accepted!/",0); } else DRV$LOG_FAO ("!%T - incoming calls not permitted!/",0); if (X25_Int->X25I$local_dte_dsp[0] == 0) DRV$LOG_FAO("!%T - no local DTE address to be specified!/",0); else DRV$LOG_FAO("!%T - local address to be specified is !AD!/",0, UNDESC(X25_Int->X25I$local_dte_dsp)); DRV$LOG_FAO("!%T - connection timeout is !AD!/", 0,tl,tm); } /*****************************************************************************/ /* */ /* This routine is called at driver initialization */ /* */ /* Inputs: */ /* ndx - device configuration table entry */ /* param_desc - address of descriptor of parameter string */ /* */ int X25_startup ( X25_Int , dev_config ) X25_Interface_Structure *X25_Int; Device_Configuration_Entry *dev_config; { short unsigned int c1,c2; dev_desc[0] = strlen(X25_dev_str); dev_desc[1] = X25_dev_str; if (!catchall_started) start_catchall(); get_parameters(dev_config, dev_config->dc_devname.l.l1, dev_config->dc_devname.l.l2 ); parameter_summary(X25_Int); /* */ /* Assign to PSI channel */ /* */ X25_Int->X25I$psi_chan = 0; X25_Int->X25I$mbx_chan = 0; sts = lib$asn_wth_mbx ( &dev_desc, /* device-name */ sizeof(X25_Int->X25I$mbx_message), /* maximum message size */ sizeof(X25_Int->X25I$mbx_message)*4, /* buffer-quota */ c1, /* device-channel */ c2 /* mailbox-channel */ ); if (ERROR(sts)) { DRV$ERROR_FAO( "!%T Error assigning to PSI channel for DTE !AS/!AS, device !SL, status = %X!XL!/", 0, UNDESC(X25_Int->X25I$remote_dte_dsp), UNDESC(X25_Int->X25I$receive_dte_dsp), dev_config->dcmib_ifIndex,sts); } /* */ /* Declare this to be a network process to receive IP messages */ /* from the specified remote DTE only */ /* */ /* If incoming calls not permitted use the 0-0 address, otherwise */ /* we are not allowed to start mailbox reads until a connection */ /* exists. */ /* */ if (!ERROR(sts)) { X25_Int->X25I$psi_chan = c1; X25_Int->X25I$mbx_chan = c2; nfb.acp_function = NFB$C_DECLNAME; nfb.terminator = 0; nfb_desc[0] = sizeof(nfb); nfb_desc[1] = &nfb; ncb[0] = 0; item_add_string(&ncb,psi$c_ntd_acclvl, "X25L3"); item_add_string(&ncb,psi$c_ntd_usrdata, call_data); item_add_string(&ncb,psi$c_ntd_datmsk, call_mask); item_add_string(&ncb,psi$c_ntd_remdte, X25_Int->X25I$receive_dte); if (!strcmp(X25_Int->X25I$receive_dte_sub,"")) { sscanf(X25_Int->X25I$receive_dte_sub,"%d",&c1); item_add_word(&ncb,psi$c_ntd_salo,c1); item_add_word(&ncb,psi$c_ntd_sahi,c1); } ncb_desc[0] = strlen(&ncb); ncb_desc[1] = &ncb; sts = sys$qiow( 0, X25_Int->X25I$psi_chan, /* chan */ IO$_ACPCONTROL, /* func */ &iosb, /* iosb */ NULL,0, /* astadr,astprm */ &nfb_desc, /* p1 */ &ncb_desc, /* p2 */ 0,0,0,0); /* p1-p6 */ if (!ERROR(sts)) sts = iosb.status; if (ERROR(sts)) { DRV$ERROR_FAO( "!%T Error declaring network process for DTE !AS, device !SL, status = %X!XL!/",0, strlen(X25_Int->X25I$receive_dte_dsp), X25_Int->X25I$receive_dte_dsp, dev_config->dcmib_ifIndex,sts); } } /* */ /* Start read on mailbox for connection requests */ /* */ if (!ERROR(sts)) sts = start_mailbox_read(X25_Int); if (ERROR(sts)) shut_channels(X25_Int); X25_Int->X25I$connected = FALSE; X25_Int->X25I$receive_ptr = 0; stop_timer(X25_Int); return(sts); } /****************************************************************************/ /* */ /* Check the time that it took to make the connection. The time to live */ /* field in the packet should be reduced by this amount. If the time to */ /* live has reduced to zero then the packet should not be transmitted. */ /* */ int check_time_to_live ( start_time , end_time , ip_buff ) short start_time[4]; short end_time[4]; struct ip *ip_buff; { short diff_time[4]; int seconds; int rem; lib$subx(end_time,start_time,diff_time,2); lib$ediv(&10000000,diff_time,&seconds,&rem); DRV$LOG_FAO("!%T connection took !UL seconds to make!/",0,seconds); if (seconds > ip_buff->ip_ttl) return(SS$_TIMEOUT); else { ip_buff->ip_ttl -= seconds; return(SS$_NORMAL); } } /*****************************************************************************/ /* */ /* This routine is called whenever a packet is to be transmitted. */ /* If no connection to the remote DTE has been established then make the */ /* connection first. */ /* */ int X25_SEND ( X25_Int , buff , buff_size ) X25_Interface_Structure *X25_Int; char *buff; int buff_size; { int i; long f; short start_time[4]; short end_time[4]; DRV$LOG_FAO("!%T Device !SL transmitting message of size !UW:!/", 0,index(X25_Int),buff_size); dump_ip(buff,buff_size); sts = SS$_NORMAL; /* */ /* If there is no connection to the remote DTE attempt to make one */ /* */ if (!X25_Int->X25I$connected) if (X25_Int->X25I$outgoing_calls_permitted) { sys$gettim(start_time); attempt_connection(X25_Int); sys$gettim(end_time); sts = check_time_to_live(start_time,end_time,buff); } else DRV$ERROR_FAO( "!%T attempt to transmit with no connection and outgoing calls not permitted, device !SL!/",0,index(X25_Int)); /* */ /* Transmit the packets for the message */ /* All packets except the first will have the MORE flag set. */ /* */ if (X25_Int->X25I$connected && !ERROR(sts)) { stop_timer(X25_Int); i = 1; while (i <= buff_size) { f = IO$_WRITEVBLK; if ((i+max_packet_size) <= buff_size) f = f + IO$M_MORE; sts = sys$qiow (0, /* Event Flag */ X25_Int->X25I$psi_chan, /* chan */ f, /* func */ &iosb, /* iosb */ NULL,0, /* astadr,astprm */ &buff[i], /* p1 */ MIN(buff_size-i+1,max_packet_size), /* p2 */ 0,0,0,0); /* p3-p6 */ if (!ERROR(sts)) sts = iosb.status; if (ERROR(sts)) { DRV$ERROR_FAO( "!%T Error transmitting to DTE !AD, device !SL, status = %X!XL!/" ,0, UNDESC(X25_Int->X25I$remote_dte), index(X25_Int), sts); i = buff_size; /*Don't try to transmit rest of message*/ } i += max_packet_size; } start_timer(X25_Int); } return(sts); }