386BSD 0.1 development
[unix-history] / usr / othersrc / contrib / isode / tsap / tsapinitiate.c
/* tsapinitiate.c - TPM: initiator */
#ifndef lint
static char *rcsid = "$Header: /f/osi/tsap/RCS/tsapinitiate.c,v 7.4 91/02/22 09:47:27 mrose Interim $";
#endif
/*
* $Header: /f/osi/tsap/RCS/tsapinitiate.c,v 7.4 91/02/22 09:47:27 mrose Interim $
*
*
* $Log: tsapinitiate.c,v $
* Revision 7.4 91/02/22 09:47:27 mrose
* Interim 6.8
*
* Revision 7.3 90/08/08 14:03:13 mrose
* stuff
*
* Revision 7.2 90/07/09 14:51:26 mrose
* sync
*
* Revision 7.1 90/03/23 17:31:34 mrose
* 8
*
* Revision 7.0 89/11/23 22:30:44 mrose
* Release 6.0
*
*/
/*
* NOTICE
*
* Acquisition, use, and distribution of this module and related
* materials are subject to the restrictions of a license agreement.
* Consult the Preface in the User's Manual for the full terms of
* this agreement.
*
*/
/* LINTLIBRARY */
#include <stdio.h>
#include <signal.h>
#include "tpkt.h"
#include "mpkt.h"
#include "isoservent.h"
#include "tailor.h"
static struct nsapent {
int ns_type;
int ns_stack;
IFP ns_open;
} nsaps[] = {
#ifdef TCP
NA_TCP, TS_TCP, tcpopen,
#endif
#ifdef X25
NA_X25, TS_X25, x25open,
#endif
#ifdef BRIDGE_X25
NA_BRG, TS_BRG, bridgeopen,
#endif
#ifdef TP4
NA_NSAP, TS_TP4, tp4open,
#endif
NOTOK, TS_NONE, NULL
};
struct TSAPaddr *newtaddr (), *ta2norm (), *maketsbaddr ();
/* \f T-(ASYN-)CONNECT.REQUEST */
int TAsynConnRequest (calling, called, expedited, data, cc, qos,
tc, td, async)
struct TSAPaddr *calling,
*called;
int expedited,
cc,
async;
char *data;
struct QOStype *qos;
struct TSAPconnect *tc;
struct TSAPdisconnect *td;
{
register int n;
SBV smask;
int result;
isodetailor (NULLCP, 0);
#ifdef notdef
missingP (calling);
#endif
missingP (called);
if ((n = called -> ta_naddr) <= 0)
return tsaplose (td, DR_PARAMETER, NULLCP,
"no NSAP addresses in called parameter");
if (n > NTADDR)
return tsaplose (td, DR_PARAMETER, NULLCP,
"too many NSAP addresses in called parameter");
if ((called = ta2norm (called)) == NULLTA)
return tsaplose (td, DR_PARAMETER, "invalid called parameter");
toomuchP (data, cc, TS_SIZE, "initial");
#ifdef notdef
missingP (qos);
#endif
missingP (td);
smask = sigioblock ();
result = TConnRequestAux (calling, called, expedited, data, cc, qos,
tc, td, async);
(void) sigiomask (smask);
return result;
}
/* \f */
static int TConnRequestAux (calling, called, expedited, data, cc, qos,
tc, td, async)
struct TSAPaddr *calling,
*called;
char *data;
int expedited,
cc,
async;
struct QOStype *qos;
register struct TSAPconnect *tc;
register struct TSAPdisconnect *td;
{
int result;
register struct tsapblk *tb;
if ((tb = newtblk ()) == NULL)
return tsaplose (td, DR_CONGEST, NULLCP, "out of memory");
if (calling == NULLTA) {
static struct TSAPaddr tas;
calling = &tas;
bzero ((char *) calling, sizeof *calling);
}
#ifdef notdef
if (called -> ta_selectlen > 0 && calling -> ta_selectlen == 0) {
calling -> ta_port = htons ((u_short) (0x8000 | (getpid () & 0x7fff)));
calling -> ta_selectlen = sizeof calling -> ta_port;
}
#endif
if (qos)
tb -> tb_qos = *qos; /* struct copy */
if ((tb -> tb_calling = (struct TSAPaddr *)
calloc (1, sizeof *tb -> tb_calling)) == NULL)
goto no_mem;
*tb -> tb_calling = *calling; /* struct copy */
bcopy (calling -> ta_selector, tb -> tb_initiating.ta_selector,
tb -> tb_initiating.ta_selectlen = calling -> ta_selectlen);
if ((tb -> tb_called = (struct TSAPaddr *)
calloc (1, sizeof *tb -> tb_called)) == NULL)
goto no_mem;
*tb -> tb_called = *called; /* struct copy */
if ((tb -> tb_cc = cc) > 0) {
if ((tb -> tb_data = malloc ((unsigned) cc)) == NULLCP) {
no_mem: ;
(void) tsaplose (td, DR_CONGEST, NULLCP, "out of memory");
goto out;
}
bcopy (data, tb -> tb_data, cc);
}
tb -> tb_expedited = expedited;
if ((result = TConnAttempt (tb, td, async)) == NOTOK) {
#ifdef MGMT
if (tb -> tb_manfnx)
(*tb -> tb_manfnx) (OPREQOUTBAD, tb);
#endif
goto out;
}
if (async) {
tc -> tc_sd = tb -> tb_fd;
switch (result) {
case CONNECTING_1:
case CONNECTING_2:
return result;
}
}
if ((result = (*tb -> tb_retryPfnx) (tb, async, tc, td)) == DONE && !async)
result = OK;
return result;
out: ;
freetblk (tb);
return NOTOK;
}
/* \f */
static int TConnAttempt (tb, td, async)
struct tsapblk *tb;
struct TSAPdisconnect *td;
int async;
{
register int n;
int didone,
l,
result;
register struct TSAPaddr *called, *calling;
struct TSAPaddr *realcalled;
register struct NSAPaddr *na, *la;
struct NSAPaddr *realna;
register struct TSAPdisconnect *te = td;
struct TSAPdisconnect tds;
calling = tb -> tb_calling;
called = tb -> tb_called;
didone = 0;
for (na = called -> ta_addrs, n = called -> ta_naddr - 1;
n >= 0;
na++, n--) {
register int *ip;
register char **ap;
register struct nsapent *ns;
realcalled = called;
realna = na;
for (ip = ts_communities; *ip; ip++)
if (*ip == na -> na_community)
break;
if (!*ip)
continue;
for (ip = tsb_communities, ap = tsb_addresses; *ip; ip++, ap++)
if (*ip == na -> na_community) {
if ((realcalled = maketsbaddr (*ap, na, called)) == NULLTA)
continue;
realna = realcalled -> ta_addrs;
break;
}
for (la = calling -> ta_addrs, l = calling -> ta_naddr - 1;
l >= 0;
la++, l--)
if (la -> na_community == na -> na_community)
break;
if (l < 0)
la = NULLNA;
for (ns = nsaps; ns -> ns_open; ns++)
if (ns -> ns_type == realna -> na_stack
&& (ns -> ns_stack & ts_stacks))
break;
if (!ns -> ns_open)
continue;
didone = 1;
switch (ns -> ns_type) {
case NA_NSAP:
if ((result = (*ns -> ns_open) (tb, calling, la,
realcalled, realna,
te, async)) == NOTOK) {
te = &tds;
continue;
}
break;
default:
if ((result = (*ns -> ns_open) (tb, la, realna, te, async))
== NOTOK) {
te = &tds;
continue;
}
break;
}
break;
}
if (tb -> tb_fd == NOTOK) {
if (!didone)
return tsaplose (td, DR_PARAMETER, NULLCP,
"no supported NSAP addresses in, nor known TSBridges for, called parameter");
return NOTOK;
}
if (la) {
tb -> tb_initiating.ta_present = 1;
tb -> tb_initiating.ta_addr = *la; /* struct copy */
}
if (la && la != calling -> ta_addrs) {
struct NSAPaddr ns;
ns = calling -> ta_addrs[0]; /* struct copy */
calling -> ta_addrs[0] = *la; /* .. */
*la = ns; /* .. */
la = calling -> ta_addrs; /* .. */
}
bcopy (realcalled -> ta_selector, tb -> tb_responding.ta_selector,
tb -> tb_responding.ta_selectlen = realcalled -> ta_selectlen);
tb -> tb_responding.ta_present = 1;
tb -> tb_responding.ta_addr = *realna; /* struct copy */
if ((result = (*tb -> tb_connPfnx) (tb, tb -> tb_expedited, tb -> tb_data,
tb -> tb_cc, td)) == NOTOK)
return NOTOK;
if (result == OK)
result = CONNECTING_1;
return result;
}
/* \f T-ASYN-RETRY.REQUEST (pseudo) */
int TAsynRetryRequest (sd, tc, td)
int sd;
struct TSAPconnect *tc;
struct TSAPdisconnect *td;
{
SBV smask;
int result;
register struct tsapblk *tb;
struct TSAPaddr *ta;
missingP (tc);
missingP (td);
smask = sigioblock ();
if ((tb = findtblk (sd)) == NULL) {
(void) sigiomask (smask);
return tsaplose (td, DR_PARAMETER, NULLCP,
"invalid transport descriptor");
}
if (tb -> tb_flags & TB_CONN) {
(void) sigiomask (smask);
return tsaplose (td, DR_OPERATION, NULLCP,
"transport descriptor connected");
}
ta = tb -> tb_called;
switch (result = (*tb -> tb_retryPfnx) (tb, 1, tc, td)) {
case NOTOK: /* try next nsap in list */
if (ta -> ta_naddr <= 1) {
freetblk (tb);
break;
}
*tb -> tb_called = *newtaddr (ta, &ta -> ta_addrs[1],
ta -> ta_naddr - 1); /* struct copy */
switch (result = TConnAttempt (tb, td, 1)) {
case DONE:
result = OK;
/* and fall... */
case CONNECTING_1:
case CONNECTING_2:
if (tb -> tb_fd != sd) {
(void) dup2 (tb -> tb_fd, sd);
(void) close (tb -> tb_fd);
tb -> tb_fd = sd;
}
break;
case NOTOK:
freetblk (tb);
break;
}
break;
case DONE:
if (tb -> tb_data) {
free (tb -> tb_data);
tb -> tb_data = NULLCP;
}
tb -> tb_cc = 0;
tb -> tb_expedited = 0;
break;
case CONNECTING_1:
case CONNECTING_2:
default:
break;
}
(void) sigiomask (smask);
return result;
}
/* \f T-ASYN-NEXT.REQUEST (pseudo) */
int TAsynNextRequest (sd, tc, td)
int sd;
struct TSAPconnect *tc;
struct TSAPdisconnect *td;
{
SBV smask;
int result;
register struct tsapblk *tb;
struct TSAPaddr *ta;
missingP (tc);
missingP (td);
smask = sigioblock ();
if ((tb = findtblk (sd)) == NULL) {
(void) sigiomask (smask);
return tsaplose (td, DR_PARAMETER, NULLCP,
"invalid transport descriptor");
}
if (tb -> tb_flags & TB_CONN) {
(void) sigiomask (smask);
return tsaplose (td, DR_OPERATION, NULLCP,
"transport descriptor connected");
}
ta = tb -> tb_called;
/* close previous connection attempt */
if (tb -> tb_fd != NOTOK)
(void) (*tb -> tb_closefnx) (tb -> tb_fd);
tb -> tb_fd = NOTOK;
if (ta -> ta_naddr <= 1) {
freetblk (tb);
(void) sigiomask (smask);
return tsaplose (td, DR_PARAMETER, NULLCP, "no more NSAPs to try");
}
*tb -> tb_called = *newtaddr (ta, &ta -> ta_addrs[1],
ta -> ta_naddr - 1); /* struct copy */
switch (result = TConnAttempt (tb, td, 1)) {
case DONE:
result = OK;
/* and fall... */
case CONNECTING_1:
case CONNECTING_2:
if (tb -> tb_fd != sd) {
(void) dup2 (tb -> tb_fd, sd);
(void) close (tb -> tb_fd);
tb -> tb_fd = sd;
}
break;
case NOTOK:
freetblk (tb);
break;
}
(void) sigiomask (smask);
return result;
}
/* \f */
static struct TSAPaddr *newtaddr (ta, na, n)
register struct TSAPaddr *ta;
register struct NSAPaddr *na;
int n;
{
static struct TSAPaddr tzs;
register struct TSAPaddr *tz = &tzs;
register struct NSAPaddr *nz = tz -> ta_addrs;
bzero ((char *) tz, sizeof *tz);
if (tz -> ta_selectlen = ta -> ta_selectlen)
bcopy (ta -> ta_selector, tz -> ta_selector, ta -> ta_selectlen);
if (na)
for (tz -> ta_naddr = n; n > 0; n--)
*nz++ = *na++; /* struct copy */
return tz;
}
/* \f */
struct TSAPaddr *ta2norm (ta)
register struct TSAPaddr *ta;
{
register int n,
*ip;
static struct TSAPaddr tzs;
register struct TSAPaddr *tz = &tzs;
register struct NSAPaddr *na,
*ca;
SLOG (addr_log, LLOG_TRACE, NULLCP,
("ta2norm %s", taddr2str (ta)));
for (na = ta -> ta_addrs, n = ta -> ta_naddr - 1; n >= 0; na++, n--)
if (na -> na_community == 0) {
SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
("ta2norm: empty subnet in NSAP address at offset %d",
na - ta -> ta_addrs));
return NULLTA;
}
bzero ((char *) tz, sizeof *tz);
bcopy (ta -> ta_selector, tz -> ta_selector,
tz -> ta_selectlen = ta -> ta_selectlen);
ca = tz -> ta_addrs;
for (ip = ts_communities; *ip; ip++)
for (na = ta -> ta_addrs, n = ta -> ta_naddr - 1;
n >= 0;
na++, n--)
if (*ip == na -> na_community) {
*ca++ = *na; /* struct copy */
tz -> ta_naddr++;
}
for (na = ta -> ta_addrs, n = ta -> ta_naddr - 1; n >= 0; na++, n--) {
for (ip = ts_communities; *ip; ip++)
if (*ip == na -> na_community)
break;
if (!*ip) {
*ca++ = *na; /* struct copy */
tz -> ta_naddr++;
}
}
SLOG (addr_log, LLOG_TRACE, NULLCP,
("ta2norm returns %s", taddr2str (tz)));
return tz;
}
/* \f */
static struct TSAPaddr *maketsbaddr (cp, na, ta)
char *cp;
struct NSAPaddr *na;
struct TSAPaddr *ta;
{
static struct TSAPaddr newta;
register struct TSAPaddr *nta = &newta;
struct TSAPaddr *taz;
struct NSAPaddr *nna;
if ((taz = str2taddr (cp)) == NULLTA)
return taz;
*nta = *taz; /* struct copy */
if ((nna = na2norm (na)) == NULLNA)
return NULLTA;
if ((nta -> ta_selectlen = 2 + nna -> na_addrlen + ta -> ta_selectlen)
>= TSSIZE)
return NULLTA;
bcopy (nna -> na_address, &nta -> ta_selector[2], nna -> na_addrlen);
bcopy (ta -> ta_selector, &nta -> ta_selector[2 + nna -> na_addrlen],
ta -> ta_selectlen);
nta -> ta_selector[0] = nta -> ta_selector[1] = nna -> na_addrlen;
return nta;
}