Solstice X.25 9.2 Developer's Guide

3.3 Additional Call Information

The example in "3.1 Making a Single Call", is of a relatively straightforward call. Procedures for making a call using OSI CONS, for receiving expedited data, for dealing with resets and for receiving remotely initiated disconnects are given in the following sections. These can be integrated into the example above, as required.

3.3.1 Opening connections for OSI CONS Calls

The following example opens a connection for an OSI CONS call:

#define FALSE	0
 #define TRUE	1
 #define CUDFLEN 4
 #define EXPLEN 4
 #include <memory.h>
 #include <netx25/x25_proto.h>
 struct xaddrf called = { 0, 0, {14, { 0x23, 0x42, 0x31, 0x56, 
 0x56, 0x56, 0x56 }}, 0};
 /* Subnetwork "A" (filled in later), no flags, 
   * DTE = "23423156565656", null NSAP  */
 struct xcallf conreq;
 struct strbuf, ctlblk, datblk;
 struct xedataf exp; 

 main ()
 {
    .
    .
    .
    called.link_id = 0;
    /*
     * snidtox25 only fails if a 
     * NULL string is passed to it 
     */
    conreq.xl_type = XL_CTL;
    conreq.xl_command = N_CI;
    conreq.CONS_call = TRUE;
    /* This is a CONS call */
    conreq.negotiate_qos = TRUE;
    /* Negotiate requested */
    memset(&conreq.qos, 0, sizeof (struct qosformat));
    conreq.qos.reqexpedited = TRUE;  /* Expedited requested */
    conreq.qos.xtras.locpacket = 8;  /* 256 bytes */
    conreq.qos.xtras.rempacket = 8;  /* 256 bytes */
    memcpy(&conreq.calledaddr, &called, sizeof(struct xaddrf));
    memset(&conreq.callingaddr, 0, sizeof(struct xaddrf));
    .
    .
    .
 }

Note -

When negotiate_qos is true (non-zero), setting the QOS fields to zero means that the connection uses defaults for QOS and Facilities. If required, these can be set to different values but it is recommended that the entire QOS structure be zeroed first as shown. This is preferable to setting each field individually, as it allows for any future additions to this structure. Setting the calling address to null leaves the network to fill this value in.


The message is sent on the stream using the putmsg system call, with any call user data being passed in the data part of the message:

char cudf[CUDFLEN] = { 1, 0, 0, 0 };
 ctlblk.len = sizeof(struct xcallf);
 ctlblk.buf = (char *) &conreq;
 datblk.len = CUDFLEN;
 datblk.buf = cudf;
 if (putmsg(x25_fd, &ctlblk, &datblk, 0) < 0 ) {
 	perror("Call putmsg");
 	exit(1);
 	}

At this stage, the application should wait for a response to the Call Request. The response may be either a Connect Confirmation or a Disconnect (rejection) message.

3.3.2 Receiving Expedited Data

The preceding example allows for the possibility of receiving expedited data messages, which are carried in X.25 interrupt packets. These must be dealt with appropriately. Since only one expedited data packet can be outstanding in the connection at any time, its sender is prevented from sending any further such messages until the receiver has acknowledged it. The receiver does this by sending an Expedited Acknowledgment (EAck) message. The EAck is sent in the same way as an ordinary data packet, but with no data part.

If an application does not need to use the expedited data capability, then it responds to receiving an EData by resetting or closing the connection.

When sending expedited data, the application must wait for an acknowledgment before requesting further expedited transmissions.

char expdata[]= {1, 2, 3, 4};
 exp.xl_type= XL_CTL;
 exp.xl_command= N_Edata;
 ctlblk.len= sizeof (struct xedataf);
 ctlblk.buf= (char *) &exp;
 datblk.len= EXPLEN;
 datblk.buf= expdata;
 if (putmsg(x25_fd, &ctlblk, &datblk, 0) < 0) {
 	error("Exp putmsg");
 	exit(1);
 	}
 for (;;) {
 	if (getmsg(x25_fd, &ctlblk, &datblk, &getflags) < 0) {
 	perror("Getmsg fail");
 	exit(1);
 	}
 hdrptr = (S_X25_HDR *) ctlbuf;
 if (hdrptr->xl_type == XL_CTL) {
 /* Deal with protocol message as required */
 	}
 if (hdrptr->xl_type == XL_DAT) {
 	dat_msg = (struct xdataf *) ctlbuf;
 	switch (dat_msg->xl_command) {
 		case N_Data:
 /* process more data */
 			break;
 		case N_EData:
 			printf("***Expedited data received \n");
 /* Must deal with */
 .... send N_EAck ....
 			break;
 		case N_EAck:  /* Expedited data received */
 /* Further N_Edata can now be sent */
 			break;
 		default:
 			break;
 		}
 	}

3.3.3 Dealing with Resets and Interrupts

Resets and Interrupts are dealt with in a similar way, except that there is no data passed with a Reset Request. When a Reset Request or Interrupt is issued, the application must wait for the acknowledgment, as for an expedited request. However, until this is received, the only action that can be taken is to issue a Disconnect Request.

The diagnostic field in a Reset Request or Interrupt contains the reason for issuing the reset. Standard values for this are defined in the include file <netx25/x25_proto.h>, although the application can set any value. See Chapter 9, Error Codes for more details.

When a Reset Indication is received, there are only two valid actions that may be taken:

In either case, pending data is flushed from the queue.

Reset Indications can be dealt with as part of the general processing of incoming messages, as shown in the following disconnect handling example.

#include<netx25/x25_proto.h>
 struct xrstf rst;
 S_X25_HDR *hdrptr;
 rst.xl_type= XL_CTL;
 rst.xl_command= N_RI;
 rst.cause= 0;
 rst.diag= NU_RESYNC;
 ctlblk.len= sizeof (struct rstf);
 ctlblk.buf= (char *) &rst;
 if (putmsg(x25_fd, &ctlblk, 0, 0) < 0) {
 	perror(" putnmsg");
 	exit(1);
 	}
 	for (;;) {
 		if (getmsg(x25_fd, &ctlblk, &datblk, &getflags) < 0) {
 			perror("Getmsg fail");
 			exit(1);
 			}
 		hdrptr = (S_X25_HDR *) ctlbuf;
 		if (hdrptr->xl_type == XL_CTL) {
 			continue;
 			}
 		switch (hdrptr->xl_command) {
 			case N_RC:  /* Reset complete */
 /* Enter data transfer */
 				break;
 			default:
 				break;
 			}  /* end switch */
 		} /* end for */

Control messages, like resets and interrupts, take higher priority than normal data messages, both internally in the PLP driver, and across the network.

3.3.3.1 Receiving a Remote Disconnect

If the remote end initiates a Disconnect, then a Disconnect Indication (N_DI) message (or possibly an N_Abort message, see "6.4.1 N_Abort--Abort Indication") is received at the NLI. The application need not acknowledge this message since, after sending a Disconnect, the X.25 driver silently discards all messages received except for connect and accept messages. These are the only meaningful X.25 messages on the stream after disconnection.

The receiver of a Disconnect Indication should ensure that enough room is available in the getmsg call to receive all parameters and, when present, up to 128 bytes of Clear User Data. Handling such a Disconnect event would normally be part of the general processing of incoming messages.

The following example could be combined with the code from the data transfer example in the previous section.

struct xdiscf *dis_msg;
 if (hdrptr->xl_type == XL_CTL) {
 	switch (hdrptr->xl_command) {
 /* Other events/indications dealt with 
   * here - e.g. Reset Indication (N_RI)
   */
 		case N_DI: 
 			dis_msg = (struct xdiscf *) hdrptr;
 			printf("Remote disconnect, cause = %x, diagnostic = %x \n",
 			dis_msg->cause, dis_msg->diag);
 /* Any other processing needed here - 
   * e.g. change connection state
   */
 			return;
 		case N_Abort:
 			printf("***Connection Aborted \n");  /* etc.  */
 			return;
 		default:
 			break;
 		}
 	} 

Note -

It is guaranteed that no X.25 interface messages are sent to the application once a disconnect message has been passed up to it, wherever the message came from.


Although at this stage the stream is idle, it is in an open state and remains so until some user action. This could be to close the stream, or to initiate a new Listen or Connect request on it.