386BSD 0.1 development
[unix-history] / usr / othersrc / contrib / isode / ssap / ssapinitiate.c
CommitLineData
a0be6343
WJ
1/* ssapinitiate.c - SPM: initiator */
2
3#ifndef lint
4static char *rcsid = "$Header: /f/osi/ssap/RCS/ssapinitiate.c,v 7.3 91/02/22 09:45:48 mrose Interim $";
5#endif
6
7/*
8 * $Header: /f/osi/ssap/RCS/ssapinitiate.c,v 7.3 91/02/22 09:45:48 mrose Interim $
9 *
10 *
11 * $Log: ssapinitiate.c,v $
12 * Revision 7.3 91/02/22 09:45:48 mrose
13 * Interim 6.8
14 *
15 * Revision 7.2 90/01/27 10:27:27 mrose
16 * touch-up
17 *
18 * Revision 7.1 89/11/27 10:30:40 mrose
19 * sync
20 *
21 * Revision 7.0 89/11/23 22:25:27 mrose
22 * Release 6.0
23 *
24 */
25
26/*
27 * NOTICE
28 *
29 * Acquisition, use, and distribution of this module and related
30 * materials are subject to the restrictions of a license agreement.
31 * Consult the Preface in the User's Manual for the full terms of
32 * this agreement.
33 *
34 */
35
36
37/* LINTLIBRARY */
38
39#include <stdio.h>
40#include <signal.h>
41#include "spkt.h"
42#include "tailor.h"
43
44/* \f S-(ASYN-)CONNECT.REQUEST */
45
46#define dotoken(requires,shift,bit,type) \
47{ \
48 if (requirements & requires) \
49 switch (settings & (ST_MASK << shift)) { \
50 case ST_INIT_VALUE << shift: \
51 case ST_RESP_VALUE << shift: \
52 case ST_CALL_VALUE << shift: \
53 break; \
54 \
55 default: \
56 return ssaplose (si, SC_PARAMETER, NULLCP, \
57 "improper choice of %s token setting", type); \
58 } \
59}
60
61/* \f */
62
63int SAsynConnRequest (ref, calling, called, requirements, settings, isn,
64 data, cc, qos, sc, si, async)
65struct SSAPref *ref;
66struct SSAPaddr *calling,
67 *called;
68int requirements,
69 settings,
70 cc,
71 async;
72long isn;
73char *data;
74struct QOStype *qos;
75struct SSAPconnect *sc;
76struct SSAPindication *si;
77{
78 SBV smask;
79 int result;
80
81 isodetailor (NULLCP, 0);
82
83 missingP (ref);
84 refmuchP (ref);
85 if (ref -> sr_vlen)
86 return ssaplose (si, SC_PARAMETER, NULLCP, "bad format for reference");
87#ifdef notdef
88 missingP (calling);
89#endif
90 missingP (called);
91
92 if (requirements & ~SR_MYREQUIRE)
93 return ssaplose (si, SC_PARAMETER, NULLCP,
94 "requirements settings not supported");
95 if ((requirements & SR_EXCEPTIONS)
96 && !(requirements & SR_HALFDUPLEX))
97 return ssaplose (si, SC_PARAMETER, NULLCP,
98 "exception service requires half-duplex service");
99
100 dotokens ();
101
102 if (requirements & (SR_MINORSYNC | SR_MAJORSYNC | SR_RESYNC)) {
103 if (!(requirements & SR_ACTIVITY) || isn != SERIAL_NONE)
104 if (SERIAL_MIN > isn || isn > SERIAL_MAX + 1)
105 return ssaplose (si, SC_PARAMETER, NULLCP,
106 "bad choice for initial serial number");
107 }
108 else
109 if (isn != SERIAL_NONE)
110 return ssaplose (si, SC_PARAMETER, NULLCP,
111 "initial serial number invalid given requirements");
112
113 if (data == NULL)
114 cc = 0;
115 else
116 if (cc > CONNECT_MAX)
117 return ssaplose (si, SC_PARAMETER, NULLCP,
118 "too much initial user data, %d octets", cc);
119
120#ifdef notdef
121 missingP (qos);
122#endif
123 missingP (sc);
124 missingP (si);
125
126 smask = sigioblock ();
127
128 result = SConnRequestAux (ref, calling, called, requirements, settings,
129 isn, data, cc, qos, sc, si, async);
130
131 (void) sigiomask (smask);
132
133 return result;
134}
135
136#undef dotoken
137
138/* \f */
139
140static int SConnRequestAux (ref, calling, called, requirements, settings, isn,
141 data, cc, qos, sc, si, async)
142struct SSAPref *ref;
143struct SSAPaddr *calling,
144 *called;
145int requirements,
146 settings,
147 cc,
148 async;
149long isn;
150char *data;
151struct QOStype *qos;
152struct SSAPconnect *sc;
153struct SSAPindication *si;
154{
155 int result;
156 register struct ssapkt *s;
157 register struct ssapblk *sb;
158 struct TSAPconnect tcs;
159 register struct TSAPconnect *tc = &tcs;
160 struct TSAPdisconnect tds;
161 register struct TSAPdisconnect *td = &tds;
162
163 if ((sb = newsblk ()) == NULL)
164 return ssaplose (si, SC_CONGEST, NULLCP, "out of memory");
165 if (!async || qos == NULLQOS || qos -> qos_maxtime <= 0)
166 sb -> sb_maxtime = NOTOK;
167 else
168 sb -> sb_maxtime = qos -> qos_maxtime;
169
170 if ((s = newspkt (SPDU_CN)) == NULL) {
171 (void) ssaplose (si, SC_CONGEST, NULLCP, "out of memory");
172 goto out1;
173 }
174
175#ifdef notdef
176 if (called -> sa_selectlen > 0) {
177 if (calling == NULLSA) {
178 static struct SSAPaddr sas;
179
180 calling = &sas;
181 bzero ((char *) calling, sizeof *calling);
182 }
183
184 if (calling -> sa_selectlen == 0) {
185 calling -> sa_port =
186 htons ((u_short) (0x8000 | (getpid () & 0x7fff)));
187 calling -> sa_selectlen = sizeof calling -> sa_port;
188 }
189 }
190#endif
191
192 if (calling) {
193 if (calling -> sa_selectlen > 0) {
194 s -> s_mask |= SMASK_CN_CALLING;
195 bcopy (calling -> sa_selector, s -> s_calling,
196 s -> s_callinglen = calling -> sa_selectlen);
197 }
198 sb -> sb_initiating = *calling; /* struct copy */
199 }
200
201 if (called -> sa_selectlen > 0) {
202 s -> s_mask |= SMASK_CN_CALLED;
203 bcopy (called -> sa_selector, s -> s_called,
204 s -> s_calledlen = called -> sa_selectlen);
205 }
206 sb -> sb_responding = *called; /* struct copy */
207
208 sb -> sb_requirements = requirements;
209 sb -> sb_settings = settings;
210
211 if ((result = TAsynConnRequest (calling ? &calling -> sa_addr : NULLTA,
212 &called -> sa_addr,
213 (qos ? qos -> qos_extended : 0)
214 || ((requirements & SR_EXPEDITED) ? 1 : 0),
215 NULLCP, 0, qos, tc, td, async)) == NOTOK) {
216 (void) ts2sslose (si, "TAsynConnRequest", td);
217
218 bzero ((char *) sc, sizeof *sc);
219 sc -> sc_sd = NOTOK;
220 sc -> sc_result = si -> si_abort.sa_reason;
221
222 result = DONE;
223 goto out2;
224 }
225
226 sb -> sb_fd = tc -> tc_sd;
227 if (qos && qos -> qos_sversion < 0) {
228 sb -> sb_version = SB_VRSN1;
229 sb -> sb_vrsnmask = SB_ALLVRSNS;
230 }
231 else
232 sb -> sb_vrsnmask = 1 << (sb -> sb_version =
233 (cc > SS_SIZE
234 || (qos && qos -> qos_sversion > 1))
235 ? SB_VRSN2 : SB_VRSN1);
236
237 s -> s_mask |= SMASK_CN_REF | SMASK_CN_OPT | SMASK_CN_VRSN;
238 s -> s_cn_reference = *ref; /* struct copy */
239 s -> s_options = CR_OPT_NULL;
240 s -> s_cn_version = sb -> sb_vrsnmask;
241
242 if (isn != SERIAL_NONE) {
243 s -> s_mask |= SMASK_CN_ISN;
244 s -> s_isn = isn;
245 }
246
247 if (cc > 0) { /* XXX: user musn't touch! */
248 s -> s_mask |= SMASK_UDATA_PGI;
249 s -> s_udata = data, s -> s_ulen = cc;
250 }
251 else
252 s -> s_udata = NULL, s -> s_ulen = 0;
253
254 sb -> sb_retry = s;
255 if (async) {
256 switch (result) {
257 case CONNECTING_1:
258 case CONNECTING_2:
259 sc -> sc_sd = sb -> sb_fd;
260 return result;
261 }
262 }
263 if ((result = SAsynRetryAux (sb, tc, sc, si)) == DONE && !async)
264 result = OK;
265 return result;
266
267out2: ;
268 freespkt (s);
269out1: ;
270 freesblk (sb);
271
272 return result;
273}
274
275/* \f S-ASYN-RETRY.REQUEST (pseudo) */
276
277int SAsynRetryRequest (sd, sc, si)
278int sd;
279struct SSAPconnect *sc;
280struct SSAPindication *si;
281{
282 SBV smask;
283 int result;
284 register struct ssapblk *sb;
285 struct TSAPconnect tcs;
286 register struct TSAPconnect *tc = &tcs;
287 struct TSAPdisconnect tds;
288 register struct TSAPdisconnect *td = &tds;
289
290 missingP (sc);
291 missingP (si);
292
293 smask = sigioblock ();
294
295 if ((sb = findsblk (sd)) == NULL) {
296 (void) sigiomask (smask);
297 return ssaplose (si, SC_PARAMETER, NULLCP,
298 "invalid session descriptor");
299 }
300 if (sb -> sb_flags & SB_CONN) {
301 (void) sigiomask (smask);
302 return ssaplose (si, SC_OPERATION, NULLCP,
303 "session descriptor connected");
304 }
305
306 switch (result = TAsynRetryRequest (sb -> sb_fd, tc, td)) {
307 case NOTOK:
308 (void) ts2sslose (si, "TAsynRetryRequest", td);
309 sb -> sb_fd = NOTOK;
310
311 bzero ((char *) sc, sizeof *sc);
312 sc -> sc_sd = NOTOK;
313 sc -> sc_result = si -> si_abort.sa_reason;
314
315 result = DONE;
316 freesblk (sb);
317 break;
318
319 case CONNECTING_1:
320 case CONNECTING_2:
321 break;
322
323 case DONE:
324 result = SAsynRetryAux (sb, tc, sc, si);
325 break;
326 }
327
328 (void) sigiomask (smask);
329
330 return result;
331}
332
333/* \f S-ASYN-NEXT.REQUEST (pseudo) */
334
335int SAsynNextRequest (sd, sc, si)
336int sd;
337struct SSAPconnect *sc;
338struct SSAPindication *si;
339{
340 SBV smask;
341 int result;
342 register struct ssapblk *sb;
343 struct TSAPconnect tcs;
344 register struct TSAPconnect *tc = &tcs;
345 struct TSAPdisconnect tds;
346 register struct TSAPdisconnect *td = &tds;
347
348 missingP (sc);
349 missingP (si);
350
351 smask = sigioblock ();
352
353 if ((sb = findsblk (sd)) == NULL) {
354 (void) sigiomask (smask);
355 return ssaplose (si, SC_PARAMETER, NULLCP,
356 "invalid session descriptor");
357 }
358 if (sb -> sb_flags & SB_CONN) {
359 (void) sigiomask (smask);
360 return ssaplose (si, SC_OPERATION, NULLCP,
361 "session descriptor connected");
362 }
363
364 switch (result = TAsynNextRequest (sb -> sb_fd, tc, td)) {
365 case NOTOK:
366 (void) ts2sslose (si, "TAsynRetryRequest", td);
367 sb -> sb_fd = NOTOK;
368
369 bzero ((char *) sc, sizeof *sc);
370 sc -> sc_sd = NOTOK;
371 sc -> sc_result = si -> si_abort.sa_reason;
372
373 result = DONE;
374 freesblk (sb);
375 break;
376
377 case CONNECTING_1:
378 case CONNECTING_2:
379 break;
380
381 case DONE:
382 result = SAsynRetryAux (sb, tc, sc, si);
383 break;
384 }
385
386 (void) sigiomask (smask);
387
388 return result;
389}
390
391/* \f */
392
393#define dotoken(requires,shift,bit,type) \
394{ \
395 if (sb -> sb_requirements & requires) { \
396 switch (sb -> sb_settings & (ST_MASK << shift)) { \
397 case ST_CALL_VALUE << shift: \
398 if (!(s -> s_mask & SMASK_CN_SET)) \
399 s -> s_settings = ST_INIT_VALUE << shift; \
400 switch (s -> s_settings & (ST_MASK << shift)) { \
401 case ST_INIT_VALUE << shift: \
402 default: \
403 sb -> sb_owned |= bit; \
404 sc -> sc_settings |= ST_INIT_VALUE << shift; \
405 break; \
406 \
407 case ST_RESP_VALUE << shift: \
408 sc -> sc_settings |= ST_RESP_VALUE << shift; \
409 break; \
410 } \
411 break; \
412 \
413 case ST_INIT_VALUE << shift: \
414 sb -> sb_owned |= bit; \
415 sc -> sc_settings |= ST_INIT_VALUE << shift; \
416 break; \
417 \
418 case ST_RESP_VALUE << shift: \
419 sc -> sc_settings |= ST_RESP_VALUE << shift; \
420 break; \
421 } \
422 \
423 if ((s -> s_mask & SMASK_AC_TOKEN) && (s -> s_ac_token & bit)) \
424 sc -> sc_please |= bit; \
425 } \
426}
427
428/* \f */
429
430static int SAsynRetryAux (sb, tc, sc, si)
431register struct ssapblk *sb;
432struct TSAPconnect *tc;
433struct SSAPconnect *sc;
434struct SSAPindication *si;
435{
436 int len,
437 result;
438 register struct ssapkt *s;
439
440 s = sb -> sb_retry;
441 sb -> sb_retry = NULL;
442
443 sb -> sb_responding.sa_addr = tc -> tc_responding; /* struct copy */
444 if (tc -> tc_expedited)
445 sb -> sb_flags |= SB_EXPD;
446 else
447 sb -> sb_requirements &= ~SR_EXPEDITED;
448 if (sb -> sb_version < SB_VRSN2) /* XXX */
449 sb -> sb_tsdu_us = sb -> sb_tsdu_them =
450 GET_TSDU_SIZE (tc -> tc_tsdusize);
451
452 if (sb -> sb_tsdu_us || sb -> sb_tsdu_them) {
453 s -> s_mask |= SMASK_CN_TSDU;
454 s -> s_tsdu_resp = GET_TSDU_SIZE (sb -> sb_tsdu_us);
455 s -> s_tsdu_init = GET_TSDU_SIZE (sb -> sb_tsdu_them);
456 }
457
458 s -> s_mask |= SMASK_CN_REQ;
459 if ((s -> s_cn_require = sb -> sb_requirements) & SR_TOKENS) {
460 s -> s_mask |= SMASK_CN_SET;
461 s -> s_settings = sb -> sb_settings;
462 }
463
464 result = spkt2sd (s, sb -> sb_fd, 0, si);
465 s -> s_mask &= ~SMASK_UDATA_PGI;
466 s -> s_udata = NULL, s -> s_ulen = 0;
467
468 freespkt (s);
469 if (result == NOTOK)
470 goto out1;
471
472 if ((s = sb2spkt (sb, si, sb -> sb_maxtime, NULLTX)) == NULL) {
473 if (si -> si_abort.sa_reason == SC_TIMER)
474 (void) ssaplose (si, SC_CONGEST, NULLCP, "remote SPM timed-out");
475 result = NOTOK;
476 goto out2;
477 }
478
479 bzero ((char *) sc, sizeof *sc);
480 switch (s -> s_code) {
481 case SPDU_AC:
482 sc -> sc_sd = sb -> sb_fd;
483 sc -> sc_result = SC_ACCEPT;
484 if (s -> s_mask & SMASK_CN_REF)
485 sc -> sc_connect = s -> s_cn_reference; /* struct copy */
486 if (s -> s_mask & SMASK_CN_OPT)
487 sb -> sb_options = s -> s_options;
488 if (!(s -> s_mask & SMASK_CN_TSDU))
489 s -> s_tsdu_init = s -> s_tsdu_resp = 0;
490 if (s -> s_tsdu_init < sb -> sb_tsdu_us)
491 sb -> sb_tsdu_us = s -> s_tsdu_init;
492 if (s -> s_tsdu_resp < sb -> sb_tsdu_them)
493 sb -> sb_tsdu_them = s -> s_tsdu_resp;
494 if (BAD_TSDU_SIZE (sb -> sb_tsdu_us)) {
495 result = spktlose (sb -> sb_fd, si, SC_PROTOCOL, NULLCP,
496 "perposterous TSDU size (%d) for initiator",
497 sb -> sb_tsdu_us);
498 goto out2;
499 }
500 if (BAD_TSDU_SIZE (sb -> sb_tsdu_them)) {
501 result = spktlose (sb -> sb_fd, si, SC_PROTOCOL, NULLCP,
502 "perposterous TSDU size (%d) for responder",
503 sb -> sb_tsdu_them);
504 goto out2;
505 }
506 if (s -> s_mask & SMASK_CN_VRSN) {
507 if (!(s -> s_cn_version & sb -> sb_vrsnmask)) {
508 /* not SC_VERSION */
509 result = spktlose (sb -> sb_fd, si, SC_PROTOCOL, NULLCP,
510 "version mismatch: expecting something in 0x%x, got 0x%x",
511 sb -> sb_vrsnmask, s -> s_cn_version);
512 goto out2;
513 }
514 sb -> sb_vrsnmask &= s -> s_cn_version;
515 }
516 sb -> sb_version = (sb -> sb_vrsnmask & (1 << SB_VRSN2))
517 ? SB_VRSN2 : SB_VRSN1;
518 if (s -> s_mask & SMASK_CN_ISN)
519 sc -> sc_isn = sb -> sb_V_A = sb -> sb_V_M = s -> s_isn;
520 else
521 sc -> sc_isn = SERIAL_NONE;
522 if (!(s -> s_mask & SMASK_CN_REQ)) {
523 s -> s_mask |= SMASK_CN_REQ;
524 s -> s_cn_require = SR_DEFAULT;
525 }
526 switch (sb -> sb_requirements & (SR_HALFDUPLEX | SR_DUPLEX)) {
527 case SR_HALFDUPLEX:
528 if (s -> s_cn_require & SR_HALFDUPLEX)
529 break;
530 result = spktlose (sb -> sb_fd, si, SC_PROTOCOL, NULLCP,
531 "half-duplex negotiation failed");
532 goto out2;
533
534 case SR_DUPLEX:
535 if (s -> s_cn_require & SR_DUPLEX)
536 break;
537 result = spktlose (sb -> sb_fd, si, SC_PROTOCOL, NULLCP,
538 "full-duplex negotiation failed");
539 goto out2;
540
541 default:
542 break;
543 }
544#ifdef notdef /* screwy session protocol... */
545 if (s -> s_cn_require & ~sb -> sb_requirements) {
546 result = spktlose (sb -> sb_fd, si, SC_PROTOCOL, NULLCP,
547 "requirements negotiation failed");
548 goto out2;
549 }
550#endif
551 sb -> sb_requirements &= s -> s_cn_require;
552 switch (sb -> sb_requirements & (SR_HALFDUPLEX | SR_DUPLEX)) {
553 case SR_HALFDUPLEX:
554 case SR_DUPLEX:
555 break;
556
557 default:
558 result = spktlose (sb -> sb_fd, si, SC_PROTOCOL, NULLCP,
559 "half/full-duplex negotiation failed");
560 goto out2;
561 }
562 if ((sb -> sb_requirements & SR_EXCEPTIONS)
563 && !(sb -> sb_requirements & SR_HALFDUPLEX)) {
564 result = spktlose (sb -> sb_fd, si, SC_PROTOCOL, NULLCP,
565 "exception service requires half-duplex service");
566 goto out2;
567 }
568 sc -> sc_requirements = sb -> sb_requirements;
569 sc -> sc_settings = sc -> sc_please = 0;
570 dotokens ();
571 if (s -> s_mask & SMASK_CN_CALLED) {
572 if ((len = s -> s_calledlen)
573 > sizeof sb -> sb_responding.sa_selector)
574 len = sizeof sb -> sb_responding.sa_selector;
575 bcopy (s -> s_called, sb -> sb_responding.sa_selector,
576 sb -> sb_responding.sa_selectlen = len);
577 }
578 sc -> sc_responding = sb -> sb_responding; /* struct copy */
579 if ((sc -> sc_ssdusize = sb -> sb_tsdu_us - SSDU_MAGIC) < 0)
580 sc -> sc_ssdusize = tc -> tc_tsdusize - SSDU_MAGIC;
581 sc -> sc_qos = tc -> tc_qos; /* struct copy */
582 sc -> sc_qos.qos_sversion = sb -> sb_version + 1;
583 sc -> sc_qos.qos_extended = (sb -> sb_flags & SB_EXPD) ? 1 : 0;
584 copySPKTdata (s, sc);
585
586 freespkt (s);
587 sb -> sb_flags |= SB_CONN | SB_INIT;
588
589 return DONE;
590
591 case SPDU_RF: /* ignore s -> s_rf_disconnect */
592 sc -> sc_sd = NOTOK;
593 sc -> sc_result = s -> s_rlen > 0 ? *s -> s_rdata
594 : SC_NOTSPECIFIED;
595 if (s -> s_mask & SMASK_RF_REF)
596 sc -> sc_connect = s -> s_rf_reference; /* struct copy */
597 if ((sc -> sc_result == SC_REJECTED)
598 && (s -> s_mask & SMASK_RF_REQ))
599 sc -> sc_requirements = s -> s_rf_require;
600 if ((s -> s_mask & SMASK_CN_CALLED)
601 && (sc -> sc_result & SC_BASE)) {
602 if ((len = s -> s_calledlen)
603 > sizeof sb -> sb_responding.sa_selector)
604 len = sizeof sb -> sb_responding.sa_selector;
605 bcopy (s -> s_called, sb -> sb_responding.sa_selector,
606 sb -> sb_responding.sa_selectlen = len);
607 }
608 sc -> sc_responding = sb -> sb_responding; /* struct copy */
609 sc -> sc_data = s -> s_rdata + 1, sc -> sc_cc = s -> s_rlen - 1;
610 sc -> sc_realdata = s -> s_rdata, s -> s_rdata = NULL;
611 si -> si_type = SI_ABORT;
612 {
613 register struct SSAPabort *sa = &si -> si_abort;
614
615 sa -> sa_peer = 0;
616 sa -> sa_reason = sc -> sc_result;
617 sa -> sa_info = sc -> sc_data, sa -> sa_cc = sc -> sc_cc;
618 sa -> sa_realinfo = NULL;
619 }
620 result = DONE;
621 break;
622
623 case SPDU_AB:
624 sc -> sc_sd = NOTOK;
625 sc -> sc_result = SC_ABORT;
626 si -> si_type = SI_ABORT;
627 {
628 register struct SSAPabort *sa = &si -> si_abort;
629
630 if (!(sa -> sa_peer = (s -> s_ab_disconnect & AB_DISC_USER)
631 ? 1 : 0))
632 sa -> sa_reason = sc -> sc_result;
633 sa -> sa_info = s -> s_udata, sa -> sa_cc = s -> s_ulen;
634 sa -> sa_realinfo = s -> s_udata, s -> s_udata = NULL;
635 }
636 result = DONE;
637 break;
638
639 default:
640 result = spktlose (sb -> sb_fd, si, SC_PROTOCOL, NULLCP,
641 "session protocol mangled: expecting 0x%x, got 0x%x",
642 SPDU_AC, s -> s_code);
643 break;
644 }
645
646out2: ;
647 freespkt (s);
648out1: ;
649 freesblk (sb);
650
651 return result;
652}
653
654#undef dotoken