/*
 * Copyright 11/20/98 Sun Microsystems, Inc. All Rights Reserved
 *
 * This example program shows how to use the DLPI interface
 * to create and establish LLC2 connections using Solstice X.25 product
 * when the X.25 product is already running over LLC2.
 *
 * In that case, the stream architecture has already been constructed by
 * the X.25 software 
 * It is still possible to use LLC2 DLPI interface as a connection initiator
 * It is also be possible to use it as a connection responder, but in
 * that case, it is necessary to use LSAP different from X.25 ones 
 * that are : 0x7e and 0x7f.
 */

#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stropts.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/dlpi.h>
#include <netdlc/uint.h>
#include <netdlc/timer.h>
#include <netdlc/ll_control.h>
#include <netdlc/ll_proto.h>

#ifdef OLD_DLSAP /* USED ONLY for pre X.25-9.2 llc2 driver */
#include <netdlc/llc2.h>
#else
#include <sys/llc2.h>
#endif
/* The main body of this example 
 */
main(int argc, char *argv[])
{
	int llc2_fd;
	struct strbuf ctlbuf;
	union DL_primitives dlprim;
	dl_bind_req_t dlbind;
	dl_attach_req_t dlatt;
	int link_id;
	int flags;
	char conn_struct[100];
	dl_connect_req_t * dlconnreq_p;

#ifdef OLD_DLSAP /* USED ONLY for pre X.25-9.2 llc2 driver */
	struct llc_dladdr * llc_dladdr_p;
#else
	dlsap_t * llc_dladdr_p;
#endif

	link_id = atoi(argv[1]);

	/* Open the llc2 device to get access to the LLC2 DLPI interface */
	llc2_fd = open("/dev/llc2", O_RDWR);
	if (llc2_fd < 0) {
                perror("Cannot open /dev/llc2");
                exit(1);
        }

	/* Now send DL_ATTACH_REQ to specify the ppa (link id) we want to
	 * work on.
	 * This is the same link id that was defined in X.25 product
	 */
	dlatt.dl_primitive = DL_ATTACH_REQ;
	dlatt.dl_ppa = link_id;
	ctlbuf.buf = (caddr_t)&dlatt;
        ctlbuf.len = (int32_t)sizeof(dlatt);
        if (putmsg(llc2_fd, &ctlbuf, (struct strbuf *)0, 0) < 0)
        {
               perror("DL_ATTACH put message failed");
               exit (1);
        }

	/* Wait for the OK_ACK message that should acknowledge ATTACH request
	 *
	 * The generic union structure DL_primitives is used to get
	 * messages from the LLC2 driver because several types of messages
	 * can be returned depending on the success or failure of the 
	 * operation 
	 */
        ctlbuf.buf = (caddr_t)&dlprim;
        ctlbuf.maxlen = (int32_t)sizeof(dlprim);
        flags = 0;
        if (getmsg(llc2_fd, &ctlbuf, (struct strbuf *)0, &flags) < 0)
        {
                perror("DL_ATTACH get message failed");
                return 1;
        }
 
        if (dlprim.dl_primitive == DL_OK_ACK)
                printf("DL_ATTACH : OK \n");
	else
	{
		printf("DL_ATTACH failed\n");
		exit(0);
	}

	/* Now this stream must be bound */
	dlbind.dl_primitive = DL_BIND_REQ;
	dlbind.dl_sap = 0x7e;
	dlbind.dl_max_conind = 0;
	dlbind.dl_service_mode = DL_CODLS;
	dlbind.dl_conn_mgmt = 0;
	dlbind.dl_xidtest_flg = DL_AUTO_XID|DL_AUTO_TEST;
	ctlbuf.buf = (caddr_t)&dlbind;
        ctlbuf.len = (int32_t)sizeof(dlbind);
        if (putmsg(llc2_fd, &ctlbuf, (struct strbuf *)0, 0) < 0)
        {
               perror("DL_BIND put message failed");
               exit (1);
        }

        ctlbuf.buf = (caddr_t)&dlprim;
        ctlbuf.maxlen = (int32_t)sizeof(dlprim);
        flags = 0;
        if (getmsg(llc2_fd, &ctlbuf, (struct strbuf *)0, &flags) != 0)
        {
                perror("DL_BIND get message failed");
                exit(1);
        }
 
        if (dlprim.dl_primitive == DL_BIND_ACK)
                printf("DL_BIND : OK \n");
	else
	{
		printf("DL_BIND failed\n");
		exit(1);
	}
	
	/* Now try to establish connection :
	 * fill a structure with dl_connect_req_t and llc_dladdr structures
	 * concatenated and send it in a single message
	 * the table conn_struct was previously declared to do this
	 */
	dlconnreq_p = (dl_connect_req_t *) conn_struct;
#ifdef OLD_DLSAP /* USED ONLY for pre X.25-9.2 llc2 driver */
	llc_dladdr_p = (struct llc_dladdr *) (&(conn_struct[0]) + sizeof(dl_connect_req_t));
	dlconnreq_p->dl_dest_addr_length = (t_uscalar_t)sizeof(struct llc_dladdr);
#else
	llc_dladdr_p = (dlsap_t *) (&(conn_struct[0]) + sizeof(dl_connect_req_t));
	dlconnreq_p->dl_dest_addr_length = (t_uscalar_t)sizeof(dlsap_t);
#endif

	dlconnreq_p->dl_primitive = DL_CONNECT_REQ;

	/* this is the offset to the llc_dladdr structure from the beginning
	 * of conn_struct
	 */
	dlconnreq_p->dl_dest_addr_offset = (t_uscalar_t)sizeof(dl_connect_req_t);

	/* Now fill the llc_dladdr structure with SAP and MAC address 
	 */
#ifdef OLD_DLSAP /* USED ONLY for pre X.25-9.2 llc2 driver */
	llc_dladdr_p->dl_sap = 0x34;			/* SAP */
	/* MAC address */
	llc_dladdr_p->dl_mac[0] = 0x08;
	llc_dladdr_p->dl_mac[1] = 0x00;
	llc_dladdr_p->dl_mac[2] = 0x20;
	llc_dladdr_p->dl_mac[3] = 0x83;
	llc_dladdr_p->dl_mac[4] = 0x99;
	llc_dladdr_p->dl_mac[5] = 0x52;

	ctlbuf.len = (int32_t)(sizeof(dl_connect_req_t)+sizeof(struct llc_dladdr));
#else
	llc_dladdr_p->llc.dl_sap = 0x34;			/* SAP */
	/* MAC address */
	llc_dladdr_p->llc.dl_nodeaddr[0] = 0x08;
	llc_dladdr_p->llc.dl_nodeaddr[1] = 0x00;
	llc_dladdr_p->llc.dl_nodeaddr[2] = 0x20;
	llc_dladdr_p->llc.dl_nodeaddr[3] = 0x83;
	llc_dladdr_p->llc.dl_nodeaddr[4] = 0x99;
	llc_dladdr_p->llc.dl_nodeaddr[5] = 0x52;

	ctlbuf.len = (int32_t)(sizeof(dl_connect_req_t)+sizeof(dlsap_t));
#endif

        ctlbuf.buf = (caddr_t)&(conn_struct[0]);

        if (putmsg(llc2_fd, &ctlbuf, (struct strbuf *)0, 0) != 0)
        {
                perror("DL_CONNECT_REQ put message failed");
                exit(1);
        }

        ctlbuf.buf = (caddr_t)&dlprim;
        ctlbuf.maxlen = (int32_t)sizeof(dlprim);
        flags = 0;
        if (getmsg(llc2_fd, &ctlbuf, (struct strbuf *)0, &flags)<0)
        {
                perror("DL_CONNECT get message failed");
                exit(1);
        }
 
        if (dlprim.dl_primitive == DL_CONNECT_CON)
                printf("DL_CONNECT_CON received OK\n");
	else
	{
		printf("DL_CONNECT failed\n");
		if (dlprim.dl_primitive == DL_ERROR_ACK)
		{
			printf("DL_ERROR_ACK was received %d\n");
			printf("     with errno : %d\n",
					 dlprim.error_ack.dl_errno);
		}
		if (dlprim.dl_primitive == DL_DISCONNECT_IND)
		{
			printf("DL_DISCONNECT_IND was received\n");
			printf("     with reason : %d\n",
					 dlprim.disconnect_ind.dl_reason);
		}
		exit (1);
	}

	/* Now the connection is establish and can be used to 
	 * perform data transfer by using M_DATA message
	 * when finished, DL_DISCONNECT and DL_UNBIND can be used
	 * to stop the connection or the stream can be closed
	 *
	 * in this example just sleep forever...
	 */
	for(;;) sleep(10);
}
