Solstice X.25 9.2 Developer's Guide

12.7 Advanced Topics

This section includes material on a variety of advanced topics.

12.7.1 Facility Specification and Negotiation

X.25 user facilities are specified on a per-call basis. The X25_SET_FACILITY ioctl is used to set facilities one at a time. The X25_GET_FACILITY ioctl is used to read facilities one at a time. These ioctl commands support all facilities (1980 and 1984 X.25).

Facilities are set in two places: before issuing a connect call, in order to request desired facilities in the Call Request packet; and before issuing a listen call, in order to negotiate the facilities proposed in an Incoming Call packet.

Facilities are usually read in two places: after a call to connect has succeeded, and after a call to accept has succeeded. This is done to determine the values of the facilities in effect for the resulting connection. Facilities can be read at any time, in general, to determine values which were previously set.

12.7.2 X25_SET_FACILITY/X25_GET_FACILITY ioctls


Note -

The sockets-based interface provides access only to those facilities that were supported in SunNet X.25 7.0. These are a subset of the facilities supported in Solstice X.25 9.2.


The X25_SET_FACILITY ioctl command is used to set the following facilities:

reverse charge   (*)   (#)
 fast select   (*)   (#)
 non-default packet size   (*)
 non-default window size   (*)
 non-default throughput   (*)
 minimum throughput class   (#)
 closed user group   (*)   (#)
 RPOA selection   (*)   (#)
 network transit delay   (#)
 end-to-end transit delay
 network user identification   (#)
 charging information request
 expedited data negotiation
 called AEF
 calling AEF   (#)
 non-X.25 facilities

All of the above facilities can be sent in a Call Request packet. The ones that can be used with a 1980 X.25 interface are marked with an (*), although only the basic forms of the closed user group facility and the RPOA selection can be used in this case. The ones that cannot be sent in a Call Accepted packet are marked with a (#). Solstice X.25 does not permit users to set facilities in Clear Request and Clear Confirm packets.

All of the above facilities can be read using the X25_GET_FACILITY ioctl command. In addition, the following can also be read:

charging information, monetary unit
 charging information, segment
 charging information, call duration
 called line address modified notification
 call redirection notification

Sample programs provided with Solstice X.25 illustrate the use of these facilities. Here, we discuss each of the above facilities in more detail and provide code segments to illustrate their use. For convenience, the variables used in the discussion below are declared here. (Chapter 13, Sockets Programming Example" has a listing of the relevant data structures used by the X25_SET_FACILITY and X25_GET_FACILITY ioctl commands.)

FACILITY    f;   /* facility structure */
 int s;           /* socket */
 int    error;    /* ioctl return value */ 

For brevity, the value returned by ioctl calls is not checked for error.

In the discussion that follows, we show how the user can send facilities in the Call Request packet. In order to send a facility in the Call Accepted packet, the listener should either set the facility before invoking listen, or should set it before causing the Call Accepted packet to be sent (that is, the listener should have used the X25_CALL_ACPT_APPROVAL ioctl command, described later, to cause Solstice X.25 to permit call approval by the user).

The exceptions to this are end-to-end transit delay, expedited data negotiation, Called AEF, and non-X.25 facilities. To send these in the Call Accepted packet, the listener must do call approval, and must set these facilities after accept returns, but before the X25_SEND_CALL_ACPT ioctl command is used to send the Call Accepted packet.

12.7.2.1 Reverse Charge

There are two possible values for this facility: 1 indicates reverse charging, and 0 indicates no reverse charging.

This is set as follows:

u_char    reverse_charge;
 reverse_charge = 1;
 f.type = T_REVERSE_CHARGE;
 f.f_reverse_charge = reverse_charge;
 error = ioctl(s, X25_SET_FACILITY, &f); 

This facility is read as follows:

f.type = T_REVERSE_CHARGE;
 error = ioctl(s, X25_GET_FACILITY, &f);
 reverse_charge = f.f_reverse_charge;

Setting this facility before making the connect call causes this facility to be sent in the Call Request. Setting this facility before making the listen call causes Incoming Calls with the reverse charging facility to be accepted. (Calls that are not reverse-charged are always acceptable.) The listener should read the value of the facility after the accept call returns to find out if the call is reverse-charged.


Note -

Reverse charging must be allowed for this ioctl to work. You allow for reverse charging in the x25tool CUG and Facilities window. To access the CUG and Facilities window, from the x25tool Link Editor window, select CUG and Facilities. Click on Incoming Reverse Charging. See Solstice X.25 9.2 Administration Guide for further details.


12.7.2.2 Fast Select

There are three possible values for this facility. FAST_OFF indicates that fast select is not in effect. FAST_CLR_ONLY indicates fast select with restriction on response, and FAST_ACPT_CLR indicates fast select with no restriction on response.

This is set as follows:

u_char fast_select_type;
 fast_select_type = FAST_CLR_ONLY;
 f.type = T_FAST_SELECT_TYPE;
 f.f_fast_select_type = fast_select_type;
 error = ioctl(s, X25_SET_FACILITY, &f); 

This is read as follows:

f.type = T_FAST_SELECT_TYPE;
 error = ioctl(s, X25_GET_FACILITY, &f);
 fast_select_type = f.f_fast_select_type;

If this facility is set before making the connect call, the Call Request packet is sent out with this facility. If this facility is set before making the listen call, the behavior that follows will depend on whether or not restriction on response was indicated, and on whether the Incoming Call has this facility. In order for an Incoming Call bearing the fast select facility to be acceptable, the listener should have specified fast select (with or without restriction). However, an Incoming Call not bearing the fast select facility will still be acceptable to a listener who has specified fast select with no restriction on response. The type of fast select in effect will be either the type of fast select in the Incoming Call, or fast select with restriction on response if either end of the connection has specified fast select with restriction on response. If the Incoming Call does not specify fast select, and is accepted by a listener who has specified fast select with no restriction on response, fast select will not be in effect for the duration of the call.

A listener that has specified fast select (with or without restriction) must use the X25_SEND_CALL_ACPT ioctl to accept the call or use close to clear the call, after successful completion of the accept call, regardless of whether fast select is in effect for the call. If the type of fast select in effect after accept is either FAST_OFF or FAST_ACPT_CLR, the user may either accept or clear the call. If the type of fast select in effect is FAST_CLR_ONLY, the user cannot accept the call (it can only be cleared). The handling of user data in conjunction with fast select is described later.

12.7.2.3 Packet Size

Packet size is set in the Call Request packet as follows:

u_short sendpktsize, recvpktsize;
 /* set sendpktsize, recvpktsize to desired values */
 f.type = T_PACKET_SIZE;
 f.f_sendpktsize = sendpktsize;
 f.f_recvpktsize = recvpktsize;
 error = ioctl(s, X25_SET_FACILITY, &f);

It is read as follows:

f.type = T_PACKET_SIZE;
 error = ioctl(s, X25_GET_FACILITY, &f);
 sendpktsize = f.f_sendpktsize;
 recvpktsize = f.f_recvpktsize; 

Setting packet size in the Call Request causes the values set to be proposed for the call (a zero value indicates the default for the link). Reading the value after the call is set up yields the result of negotiation.

Packet sizes are set and read in bytes, so that, for example, 128, 256, and 512 are legal values.

12.7.2.4 Window Size

Window size is set in the Call Request packet as follows:

u_short   sendwndsize, recvwndsize;
 /* set sendwndsize, recvwndsize to desired values */
 f.type = T_WINDOW_SIZE;
 f.f_sendwndsize = sendwndsize;
 f.f_recvwndsize = recvwndsize;
 error = ioctl(s, X25_SET_FACILITY, &f);

It is read as follows:

f.type = T_WINDOW_SIZE;
 error = ioctl(s, X25_GET_FACILITY, &f);
 sendwndsize = f.f_sendwndsize;
 recvwndsize = f.f_recvwndsize;

Setting the window size in the Call Request causes the values set to be proposed for the call (a zero value indicates the default for the link). Reading the value after the call is set up yields the result of negotiation.

12.7.2.5 Throughput

Throughput is set in the Call Request packet as follows:

u_char      sendthruput, recvthruput;
 /* set sendthruput, recvthruput to desired values */
 f.type = T_THROUGHPUT;
 f.f_sendthruput = sendthruput;
 f.f_recvthruput = recvthruput;
 error = ioctl(s, X25_SET_FACILITY, &f); 

It is read as follows:

f.type = T_THROUGHPUT;
 error = ioctl(s, X25_GET_FACILITY, &f);
 sendthruput = f.f_sendthruput;
 recvthruput = f.f_recvthruput;

When throughput is set in the Call Request, the values set are proposed for the call (a zero value indicates the default for the link). Reading the value after the call is set up yields the result of negotiation.

12.7.2.6 Minimum Throughput Class

Minimum throughput class is set in the Call Request packet as follows:

u_char      min_sendthruput, min_recvthruput;
 /* set min_sendthruput, min_recvthruput to desired values */
 f.type = T_MIN_THRU_CLASS;
 f.f_min_sendthruput = min_sendthruput;
 f.f_min_recvthruput = min_recvthruput;
 error = ioctl(s, X25_SET_FACILITY, &f); 

It is read as follows:

f.type = T_MIN_THRU_CLASS;
 error = ioctl(s, X25_GET_FACILITY, &f);
 min_sendthruput = f.f_min_sendthruput;
 min_recvthruput = f.f_min_recvthruput; 

This facility may only be set in a Call Request packet, and read from an Incoming Call packet. The receiver of the Incoming Call packet should clear the call (with an appropriate diagnostic) if the proposed minimum throughput values cannot be supported.

12.7.2.7 Closed User Group

The user may set one of three types of Closed User Group facility: CUG_REQ (no outgoing access), CUG_REQ_ACS (with outgoing access), and CUG_BI (bilateral CUG). For CUG_REQ and CUG_REQ_ACS, the CUG is a decimal integer in the range 0-9999 (for 1980 X.25 interfaces, the valid range is 0-99). The extended form of the facility is used for CUG indices in the range 100-9999. This facility is set as follows:

u_short      cug_index;
 /* set cug_index to appropriate value */
 f.type = T_CUG;
 f.f_cug_req = CUG_REQ;    /* could be CUG_REQ_ACS or CUG_BI */
 f.f_cug_index = cug_index;
 error = ioctl(s, X25_SET_FACILITY, &f);
 

To read this facility:

f.type = T_CUG;
 error = ioctl(s, X25_GET_FACILITY, &f);
 cug_req = f.f_cug_req;
 cug_index = f.f_cug_index;

12.7.2.8 RPOA Selection

Solstice X.25 supports the setting of up to three (MAX_RPOA) RPOA transit networks (in the extended form). If only one is specified, the non-extended form of the facility is used. An RPOA transit network is specified as a decimal integer in the range 0-9999.

This facility is set as follows:

u_short      rpoa0, rpoa1, rpoa2;
 /* set rpoa0, rpoa1, rpoa2 */
 f.type = T_RPOA;
 f.f_nrpoa = 3;
 f.f_rpoa_index[0] = rpoa0;
 f.f_rpoa_index[1] = rpoa1;
 f.f_rpoa_index[2] = rpoa2;
 error = ioctl(s, X25_SET_FACILITY, &f);

To read this facility:

f.type = T_RPOA;
 error = ioctl(s, X25_GET_FACILITY, &f);
 rpoa0 = f.f_rpoa_index[0];
 rpoa1 = f.f_rpoa_index[1];
 rpoa2 = f.f_rpoa_index[2];

12.7.2.9 Network Transit Delay

The Transit Delay Selection and Indication facility (TDSAI) is set in the Call Request as follows:

u_short    tr_delay;   /* desired transit delay in milliseconds */
 /* set tr_delay */
 f.type = T_TR_DELAY;
 f.f_tr_delay = tr_delay;
 error = ioctl(s, X25_SET_FACILITY, &f);

This is read as follows:

f.type = T_TR_DELAY;
 error = ioctl(s, X25_GET_FACILITY, &f);
 tr_delay = f.f_tr_delay; 

12.7.2.10 End-to-End Transit Delay

This is set in the Call Request as follows:

u_short   req_delay, desired_delay, max_delay;
 /* set the requested, desired, and maximum delays */
 f.type = T_ETE_TR_DELAY;
 f.f_req_delay = req_delay;
 f.f_desired_delay = desired_delay;
 f.f_max_delay = max_delay;
 error = ioctl(s, X25_SET_FACILITY, &f); 

This is read as follows:

f.type = T_ETE_TR_DELAY;
 error = ioctl(s, X25_GET_FACILITY, &f);
 req_delay = f.f_req_delay;
 desired_delay = f.f_desired_delay;
 max_delay = f.f_max_delay; 

If f_desired_delay is set, f_req_delay must be non-zero; if f_max_delay is set, f_desired_delay must be non-zero. Delay is specified in milliseconds.

12.7.2.11 Network User Identification

This is set as follows (in the example below, NUI is an ASCII string):

char   nui_str[] = "sunhost";
 f.type = T_NUI;
 f.f_nui.nui_len = strlen(nui_str);
 bcopy(nui_str, f.f_nui.nui_data, strlen(nui_str));
 error = ioctl(s, X25_SET_FACILITY, &f); 

Solstice X.25 permits a maximum length of 64 (MAX_NUI) for Network User Identification facility.

To read this facility:

f.type = T_NUI;
 error = ioctl(s, X25_GET_FACILITY, &f);
 nui_str = f.f_nui.nui_data;

12.7.2.12 Charging Information Request

This write-only facility is set as follows:

f.type = T_CHARGE_REQ;
 f.f_charge_req = 1;
 error = ioctl(s, X25_SET_FACILITY, &f);

12.7.2.13 Charging Information

By setting f.type to T_CHARGE_REQ as specified above you make available the following read-only facilities. The facility types are T_CHARGE_MU, T_CHARGE_SEG, and T_CHARGE_DUR. For example, the Charging Information (monetary unit) is read as follows:

typedef struct charge_info_s {
    u_char   charge_len;
 #define MAX_CHARGE_INFO   64
    u_char   charge_data[MAX_CHARGE_INFO];
 } CHARGE_INFO;

 CHARGE_INFO charge_mu;
 f.type = T_CHARGE_MU;
 error = ioctl(s, X25_GET_FACILITY, &f);
 charge_mu = f.f_charge_mu; 

The T_CHARGE_SEG and T_CHARGE_DUR facilities are read in a way similar to the T_CHARGE_MU example above; that is, by using T_CHARGE_SEG or T_CHARGE_DUR for the f.type value, and using f_charge_seg or f_charge_dur in place of f_charge_mu.

The maximum length for the charging information facility permitted by Solstice X.25 is 64 (MAX_CHARGE_INFO). This facility should be read after the call is cleared, but before the socket is closed, since it is received in the Clear Request or Clear Confirm packets.

12.7.2.14 Called Line Address Modified Notification

This is a read-only facility received in either the Call Accepted or Clear Indication packets. It is read as follows:

u_char   line_addr_mod;
 f.type = T_LINE_ADDR_MOD;
 error = ioctl(s, X25_GET_FACILITY, &f);
 line_addr_mod = f.f_line_addr_mod;

12.7.2.15 Call Redirection Notification

This is a read-only facility received in either the Call Accepted or Clear Indication packets. It is read as follows:

typedef struct call_redir_s {
    u_char   cr_reason;
    u_char   cr_hostlen;
    u_char   cr_host[(MAXHOSTADR+1)/2];
 } CALL_REDIR;

 CALL_REDIR call_redir;
 f.type = T_CALL_REDIR;
 error = ioctl(s, X25_GET_FACILITY, &f);
 call_redir = f.f_call_redir; 

12.7.2.16 Expedited Data Negotiation

This facility is set as follows:

u_char expedited = 1;/* 0 indicates non-use of expedited data */
 f.type = T_EXPEDITED;
 f.f_expedited = expedited;
 error = ioctl(s, X25_SET_FACILITY, &f);

It is read as follows:

f.type = T_EXPEDITED;
 error = ioctl(s, X25_GET_FACILITY, &f);
 expedited = f.f_expedited;

12.7.2.17 Called/Calling AEF

There are three types of address extensions: OSI NSAP (AEF_NSAP), Partial OSI (AEF_PARTIAL_NSAP), and Non-OSI (AEF_NON_OSI). The Calling AEF may only be present in the Call Request packet.

Solstice X.25 9.2 Administration Guide describes how Solstice X.25 may be set up to automatically supply the Calling AEF (referred to as address extension) in a Call Request packet.

The Called AEF is set as follows:

typedef struct aef_s {
    u_char   aef_type;
 #define AEF_NONE      0
 #define AEF_NSAP      1
 #define AEF_PARTIAL_NSAP   2
 #define AEF_NON_OSI      3
    u_char   aef_len;
 #define MAX_AEF   40
    u_char   aef[(MAX_AEF+1)/2];
 } AEF;

 AEF   aef;
 aef.aef_type = AEF_NON_OSI;
 aef.aef_len = 7;        /* length in nibbles */
 aef.aef[0] = 0x12;
 aef.aef[1] = 0x34;
 aef.aef[2] = 0x56;
 aef.aef[3] = 0x70;      /* Note, unused nibble is zero */
 f.type = T_CALLED_AEF;
 f_called_aef = aef;
 error = ioctl(s, X25_SET_FACILITY, &f); 

The Called AEF is read as follows:

f.type = T_CALLED_AEF;
 error = ioctl(s, X25_GET_FACILITY, &f);
 aef = f_called_aef;

The Calling AEF is set and read similarly (using T_CALLING_AEF in place of T_CALLED_AEF and f_calling_aef in place of f_called_aef).

12.7.2.18 Non-X.25 Facilities

These are for expert use only. Solstice X.25 permits a maximum of 64 (MAX_PRIVATE) bytes of non-X.25 facilities. These are not looked at by Solstice X.25, but just passed through. Non-X.25 facilities consist of a sequence of facility blocks, where each block begins with a facility marker indicating non-X.25 facilities supported by either the local or remote network, or some arbitrary facility marker. This is set as follows:

typedef struct private_fact_s {
    u_char   p_len;   /* total length of facilities*/
 #define MAX_PRIVATE  64
    u_char   p_fact[MAX_PRIVATE];
       /* facilities exactly as they
        * are present in Call Request or
        * Call Accept packets
        */
 } PRIVATE_FACT;

 PRIVATE_FACT  private;
 /* set the p_len and p_fact fields */
 f.type = T_PRIVATE;
 f.f_private = private;
 error = ioctl(s, X25_SET_FACILITY, &f);

It is read as follows:

f.type = T_PRIVATE;
 error = ioctl(s, X25_GET_FACILITY, &f);
 private = f.f_private;

12.7.2.19 Determining Which Facilities are Present

Since facilities can be read only one at a time, the user needs a way to determine which facilities are present. Solstice X.25 provides the following mechanism for doing this.

The user can read a bit mask that has one bit reserved for each of the facilities described above. This is read as:

u_int     fmask;
 f.type = T_FACILITIES;
 error = ioctl(s, X25_GET_FACILITY, &f);
 fmask = f.f_facilities; 

The following mask bits are defined:

F_REVERSE_CHARGE    /* reverse charging */
 F_FAST_SELECT_TYPE  /* fast select */
 F_PACKET_SIZE       /* packet size */
 F_WINDOW_SIZE       /* window size */
 F_THROUGHPUT        /* throughput */
 F_MIN_THRU_CLASS    /* minimum throughput class */
 F_CUG               /* closed user group selection */
 F_RPOA              /* ROPA transit network */
 F_TR_DELAY          /* network transit delay */
 F_ETE_TR_DELAY      /* end to end transit delay */
 F_NUI               /* network user identification */
 F_CHARGE_REQ        /* charging information request */
 F_CHARGE_MU         /* charging information, monetary unit */
 F_CHARGE_SEG        /* charging information, segment */
 F_CHARGE_DUR        /* charging information, call duration */
 F_LINE_ADDR_MOD     /* called line address modified notification */
 F_CALL_REDIR        /* call redirection notification */
 F_EXPEDITED         /* expedited data negotiation */
 F_CALLED_AEF        /* called AEF */
 F_CALLING_AEF       /* calling AEF */
 F_PRIVATE           /* non-X.25 facilities */ 

For example, to determine if the Call Redirection facility has been received, the following segment of code could be used:

if ((fmask & F_CALL_REDIR) != 0) {
 /*
  * Read its value.
  */
 CALL_REDIR call_redir;
 f.type = T_CALL_REDIR;
 error = ioctl(s, X25_GET_FACILITY, &f);
 call_redir = f.f_call_redir;
 } 

12.7.3 Fast Select User Data

The fast select facility is handled in the following way.

12.7.3.1 Calling Side

To send fast select data, fast_select_type must be set to the proper value (with the X25_SET_FACILITY ioctl) before connect is called (see the section "12.7.1 Facility Specification and Negotiation"of this chapter for more information). Using the CONN_DB structure, a calling DTE can specify a user data field up to 102 bytes (including the optional protocol identifier). If 102 bytes of call user data are not enough for the current fast select message, use the X25_WR_USER_DATA ioctl before calling connect to pass the additional user data. The user data specified in connect will precede this additional user data. To write user data:

typedef struct user_data_db_s {
 u_char      datalen;
 u_char       data[MAX_USER_DATA];
 } USER_DATA_DB;
 int s, error;
 USER_DATA_DB user_data;
 error = ioctl(s, X25_WR_USER_DATA, &user_data)

Here, MAX_USER_DATA is 124.

If connect returns -1 and errno is EFASTDATA, the remote side has cleared the call by sending a Clear Indication packet with up to 32 bytes (1980) or 128 bytes (1984) of user data. At this time, the user can read the user data in the Clear Indication packet with calls to the X25_RD_USER_DATA ioctl until the returned datalen in USER_DATA_DB structure is 0 or less than MAX_USER_DATA, then close the socket with close.

To read user data:

USER_DATA_DB user_data;
 int s, error;
 error = ioctl(s, X25_RD_USER_DATA, &user_data);

If connect returns 0, it indicates that the connection has been set up successfully. If the connection is over an interface that supports 1984 X.25, the remote user may have sent user data in the Call Accepted packet. (This will happen only if the initiator of the connection has specified fast select with no restriction on response.) Thus the initiating user must repeatedly read any user data using the X25_RD_USER_DATA ioctl until the returned length in the USER_DATA_DB structure is less than MAX_USER_DATA.

When a call is cleared after being connected, the Clear Indication packet may contain user data if the interface supports 1984 X.25 and fast select is in effect for that call. Either the initiator of the connection or the responder can send user data in the Clear Request packet. Thus when a call with fast select is cleared by the remote user, user data must be read in the same way as for the other cases.

For 1980 X.25 interfaces, if the connection was accepted by the remote user, the Call Accepted and Clear Request packets will not have any user data; the only time that the Clear Request can have user data is when a fast select call is cleared immediately (this is detectable by means of the EFASTDATA error return).

12.7.3.2 Called Side

To receive a fast select incoming call, the called side must specify either FAST_ACPT_CLR or FAST_CLR_ONLY as the value for fast_select_type using the X25_SET_FACILITY ioctl, before issuing the listen call.

If the Incoming Call has the fast select facility, it will be accepted only if the listener has specified fast select. The incoming call will also be accepted if it does not have the fast select facility and the listener has specified FAST_ACPT_CLR.

The call will be rejected if there are more than 16 bytes of user data, and the called side has either not specified the fast select facility at all, or has specified FAST_OFF (which is equivalent to not specifying fast select).

After accept returns, the called side may use the X25_GET_FACILITY ioctl to determine the type of fast select in effect. For example, if the called side has specified FAST_ACPT_CLR and the calling side has specified FAST_CLR_ONLY, after accept returns, the type of fast select in effect will be FAST_CLR_ONLY. If fast select is indicated, the called side can read the user data that was received in the Call Request by looking at the CONN_DB structure returned by accept. If more than 102 bytes of user data were received, the extra bytes can be read with the X25_RD_USER_DATA ioctl.

The X25_WR_USER_DATA ioctl can be used to specify user data to be sent back in the response to the fast select Call Request. To write more than MAX_USER_DATA bytes of user data, a second X25_WR_USER_DATA ioctl can be used to append the additional data after that from the first X25_WR_USER_DATA ioctl (total length of all user data may not exceed 128 bytes).

If the type of fast select in effect is FAST_CLR_ONLY, the called side can only clear the fast select call by closing the socket (which causes the user data specified by X25_WR_USER_DATA to be sent in the Clear Request). If the type of fast select in effect after accept returns is FAST_ACPT_CLR, the called side has the option, after writing the reply message with the X25_WR_USER_DATA ioctl, of either sending a Clear Request packet with close or sending a Call Accepted packet with the X25_SEND_CALL_ACPT ioctl and thereby entering the normal data transfer state.

int news, error;
 error = ioctl(news, X25_SEND_CALL_ACPT);

When the value in effect is FAST_CLR_ONLY, the called side can only close the socket with the close system call after writing the reply message.

FAST_OFF is the type of fast select that will be in effect when the listener has specified FAST_ACPT_CLR and the incoming call does not have the fast select facility. Even in this case, the listener must use the X25_SEND_CALL_ACPT ioctl to put the connection into normal data transfer state.


Note -

In the current release (and not in SunNet X.25 7.0), the listen socket should not be closed until after the incoming fast select call has been either cleared (with close) or accepted (with X25_SEND_CALL_ACPT).


12.7.4 Permanent Virtual Circuits

Since permanent virtual circuits are always in data transfer state, there is no need to issue a connect on the calling side, or bind, listen, and accept on the called side. Instead, use an ioctl call to bind the socket to a logical channel number and to specify other parameters.

typedef struct pvc_db_s {
 u_short lcn; /* lcn of PVC */
 u_short sendpktsize; /* Maximum packet size */
 u_short recvpktsize; /* Maximum packet size */
 u_char sendwndsize;  /* Output flow control window */
 u_char recvwndsize;  /* Input flow control window */
 } X25_PVC_DB;
 X25_PVC_DB pvc_parms;
 int pvc_so;
 pvc_so = socket(AF_X25, SOCK_STREAM, 0);
 error = ioctl(pvc_so, X25_SETUP_PVC, &pvc_parms); 

In the current release, the sendpktsize, recvpktsize, sendwndsize, and recvwndsize parameters are ignored. The default value in the link configuration file is always used. By default, the lowest numbered WAN link is used for the permanent virtual circuit. If you desire some other link for the permanent virtual circuit, you must select the desired link using the X25_SET_LINK ioctl as described earlier, after the socket call, but before the X25_SETUP_PVC ioctl. Permanent virtual circuits are not supported over LAN interfaces.

12.7.5 Call Acceptance by User

Normally Incoming Call packets are examined and responded to by X.25. If the call is accepted, a Call Accepted packet is sent by X.25 directly. In the event a user process wants to have additional checks before sending a Call Accepted packet, an X25_CALL_ACPT_APPROVAL ioctl may be used.

int approved_by_user, s, error;
 error = ioctl(s, X25_CALL_ACPT_APPROVAL, &approved_by_user);

where approved_by_user = 0 means the approval is done by X.25, and approved_by_user = 1 means approval is done by the user process. By default (that is, if this call is not issued), approval is done by X.25. Note that if a user wants to do call approval, the X25_CALL_ACPT_APPROVAL ioctl must be issued before the listen call is issued.

Regardless of the value of approved_by_user, X.25 always performs address matching and facilities negotiation before notifying accept. If a user process assumes the final incoming call approval, accept will return without sending a Call Accepted packet. At this time, the user process should reply as soon as possible to avoid the Call Request timeout on the remote calling side. To accept the call, use:

int news, error;
 error = ioctl(news, X25_SEND_CALL_ACPT);

Here, news is the socket descriptor returned by accept.

The X25_SEND_CALL_ACPT ioctl call is also needed for fast select calls, as described in an earlier section. To reject the call, simply close the socket:

int news;
 close(news); 

where news is the socket descriptor returned by accept.

12.7.6 Accessing the Link (X.25) Address

The X.25 client can set the local link X.121 (X.25) address through an X.25 socket owned by the superuser. (The default value is established in the Interface Configuration window in x25tool, as described in Solstice X.25 9.2 Administration Guide):

typedef struct link_adr_s {
    int      linkid;  /* id of link */
    u_char   hostlen; /* length of BCDs */
    u_char   host[(MAXHOSTADR+1)/2];
 } LINK_ADR;
 LINK_ADR addr;
 int so, error;
 error = ioctl(so, X25_WR_LINKADR, &addr);

Set linkid to the identifier of the desired link.

The local link X.121 address can be read at any time with:

LINK_ADR addr;
 int s;
 error = ioctl(s, X25_RD_LINKADR, &addr);

The returned addr is actually the link address specified in x25tool (for the link specified in the linkid field of the LINK_ADR structure) unless a new address has been assigned to the link.

The X25_WR_LINKADR ioctl can be used to assign new X.25 addresses to a link.

12.7.7 Accessing High Water Marks of Socket

The AF_X25 socket provides a flow control mechanism using high and low water marks on both the send and receive sides of an X.25 virtual circuit. When the amount of queued data goes above the high water mark, additional data is blocked until the queued data falls below the low water mark. Blocking received data is accomplished by not acknowledging receipt of packets until the user reads the data. Blocking send data is accomplished by blocking the user process invoking send or write.

The default high water mark for both sending and receiving is 2048 bytes. The low water mark is always set to half the high water mark. Note that the high water mark is only an approximation of the maximum amount of data allowed to be queued up.

A user process may set or read the high water mark as described below. To read:

typedef struct so_hiwat_db_s {
    short   sendhiwat;
    short   recvhiwat;
 } SO_HIWAT_DB;
 SO_HIWAT_DB hiwater;
 int s, error;
 error = ioctl(s, X25_RD_SBHIWAT, &hiwater);

To write:

error = ioctl(s, X25_WR_SBHIWAT, &hiwater);

12.7.8 Accessing the Diagnostic Code

The user may read the cause or diagnostic code in a Clear Indication or Reset Indication packet received from the remote end. The user may also write the cause or diagnostic code in Clear Request and Reset Request packets to be transmitted to the remote end.

typedef struct x25_cause_diag_s {
 u_char   flags;
 #   define RECV_DIAG    0
 #   define DIAG_TYPE   1
 #   define WAIT_CONFIRMATION 2
 /*  bit 0 (RECV_DIAG)=
  *  0: no cause and diagnostic codes
  *  1: receive cause and diagnostic codes.
  *  bit 1 (DIAG_TYPE)=
  *  0: reset cause and diagnostic codes in data array
  *  1: clear cause and diagnostic codes in data array
  *  bit 2 (WAIT_CONFIRMATION)=
  *  0: no wait after X25_WR_DIAG_CODE ioctl
  *  1: wait returned cause and diagnostic codes after
  *  X25_WR_DIAG_CODE ioctl.
  */
    u_char   datalen; /* byte count of data array */
    u_char   data[64];
 } X25_CAUSE_DIAG;
 X25_CAUSE_DIAG diag;
 int s, error; 

To read:

error = ioctl(s, X25_RD_CAUSE_DIAG, &diag);

To write:

error = ioctl(s, X25_WR_CAUSE_DIAG, &diag);

The data field in X25_CAUSE_DIAG contains the cause and diagnostic code.

Upon receiving a Clear Indication or Reset Indication packet, the X25_RD_CAUSE_DIAG ioctl may be issued to determine the cause and diagnostic associated with the packet. The datalen field contains the length in bytes of the information in data. When reading the diagnostic, if bit RECV_DIAG (that is, bit 0) is set, it indicates that the information in data is valid. If bit DIAG_TYPE (that is, bit 1) is set, it indicates that the diagnostic was received in a Clear Indication; otherwise, it was received in a Reset Indication.

The X25_WR_CAUSE_DIAG ioctl enables the user to send a Clear Request or Reset Request packet with the desired cause and diagnostic codes. If the user supplies only one byte in the data field, X.25 will use the cause code DTE_ORIGINATED, and use the provided byte as the diagnostic.

The X25_WR_CAUSE_DIAG ioctl call will send a Clear Request or Reset Request. To send a Clear Request, set bit DIAG_TYPE (that is, bit 1) in flags:

X25_CAUSE_DIAG diag;
 int s, error;
 diag.flags = 1 << DIAG_TYPE; /* Clear Request */
 diag.datalen = 2;
 diag.data[0] = 0;
 diag.data[1] = 67;
 error = ioctl(s, X25_WR_CAUSE_DIAG, &diag);

To send a Clear Request and wait for confirmation, set bit WAIT_CONFIRMATION (that is, bit 2) in flags:

X25_CAUSE_DIAG diag;
 int s, error;
 diag.flags = (1 << DIAG_TYPE) | (1 << WAIT_CONFIRMATION);
 diag.datalen = 2;
 diag.data[0] = 0;
 diag.data[1] = 67;
 error = ioctl(s, X25_WR_CAUSE_DIAG, &diag);

To send a Reset Request and wait for confirmation:

X25_CAUSE_DIAG diag;
 int s, error;
 diag.flags = 1 << WAIT_CONFIRMATION;
 diag.datalen = 2;
 diag.data[0] = 0;
 diag.data[1] = 0;   /* can be any valid diagnostic */
 error = ioctl(s, X25_WR_CAUSE_DIAG, &diag);

A close is still necessary to free all resources held by this socket and the associated virtual circuit after a Clear Indication or Clear Confirmation packet is received. After the DTE receives a Clear Indication packet, recv will return zero bytes after all unread data has been read. Calling send after the Clear Indication packet is received will not return an error. Note that this behavior is different from that of SunNet X.25 7.0, in which send does return an error.

To be notified when a Clear Indication packet is received, so that you can use the X25_RD_CAUSE_DIAG ioctl, you can use the following mechanism: Enable a third type of out-of-band data (see "12.5.4 Out-of-Band Data ") and receive the SIGURG signal when this type of out-of-band data arrives. To enable the signalling of Clear Indication packets, use the following ioctl:

error = ioctl(s, X25_OOB_ON_CLEAR, 0);

This will enable the reception of the following type of out-of-band data, which can be read with the X25_OOB_TYPE ioctl:

#define VC_CLEARED 31  /* virtual circuit cleared */

See "12.5.4 Out-of-Band Data " for a complete description of how to handle out-of-band data.


Note -

If an X25_WR_CAUSE_DIAG ioctl is not issued before close, X.25 fills an appropriate cause and diagnostic code in any Clear Request packet sent as a result (this will not happen if the connection is inactive at the time the call is issued).