Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / netproto / atm / uni / sscop_pdu.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/netatm/uni/sscop_pdu.c,v 1.5 2000/01/17 20:49:52 mks Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/uni/sscop_pdu.c,v 1.2 2003/06/17 04:28:49 dillon Exp $
28  */
29
30 /*
31  * ATM Forum UNI Support
32  * ---------------------
33  *
34  * SSCOP - PDU subroutines
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include <netatm/uni/sscop.h>
41 #include <netatm/uni/sscop_misc.h>
42 #include <netatm/uni/sscop_pdu.h>
43 #include <netatm/uni/sscop_var.h>
44
45 /*
46  * Local functions
47  */
48 static KBuffer *        sscop_stat_init __P((struct sscop *));
49 static KBuffer *        sscop_stat_add __P((sscop_seq, KBuffer *));
50 static int              sscop_stat_end __P((struct sscop *, sscop_seq,
51                                 KBuffer *, KBuffer *));
52 static int              sscop_recv_locate __P((struct sscop *, sscop_seq,
53                                 struct pdu_hdr **));
54
55
56 /*
57  * Build and send BGN PDU
58  * 
59  * A BGN PDU will be constructed and passed down the protocol stack.
60  * The SSCOP-UU/N(UU) field is not supported.
61  *
62  * Arguments:
63  *      sop     pointer to sscop connection control block
64  *      source  originator of BGN PDU (Q.SAAL1 only)
65  *
66  * Returns:
67  *      0       PDU successfully built and passed down the stack
68  *      else    unable to build or send pdu
69  *
70  */
71 int
72 sscop_send_bgn(sop, source)
73         struct sscop    *sop;
74         int             source;
75 {
76         KBuffer         *m;
77         struct bgn_pdu  *bp;
78         int             err;
79
80
81         /*
82          * Get buffer for PDU
83          */
84         KB_ALLOCPKT(m, sizeof(struct bgn_pdu), KB_F_NOWAIT, KB_T_HEADER);
85         if (m == NULL)
86                 return (1);
87
88         /*
89          * Setup buffer controls
90          */
91         KB_HEADSET(m, MIN(sop->so_headout,
92                 KB_BFRLEN(m) - sizeof(struct bgn_pdu)));
93         KB_LEN(m) = sizeof(struct bgn_pdu);
94
95         /*
96          * Build PDU
97          */
98         KB_DATASTART(m, bp, struct bgn_pdu *);
99         *(int *)&bp->bgn_rsvd[0] = 0;
100         if (sop->so_vers != SSCOP_VERS_QSAAL)
101                 bp->bgn_nsq = sop->so_sendconn;
102         bp->bgn_nmr =
103                 htonl((PT_BGN << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax));
104         if ((sop->so_vers == SSCOP_VERS_QSAAL) &&
105             (source == SSCOP_SOURCE_SSCOP))
106                 bp->bgn_type |= PT_SOURCE_SSCOP;
107
108         /*
109          * Send PDU towards peer
110          */
111         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
112                 sop->so_connvc, (int)m, 0, err);
113
114         if (err)
115                 KB_FREEALL(m);
116
117         return (err);
118 }
119
120
121 /*
122  * Build and send BGAK PDU
123  * 
124  * A BGAK PDU will be constructed and passed down the protocol stack.
125  * The SSCOP-UU/N(UU) field is not supported.
126  *
127  * Arguments:
128  *      sop     pointer to sscop connection control block
129  *
130  * Returns:
131  *      0       PDU successfully built and passed down the stack
132  *      else    unable to build or send pdu
133  *
134  */
135 int
136 sscop_send_bgak(sop)
137         struct sscop    *sop;
138 {
139         KBuffer         *m;
140         struct bgak_pdu *bp;
141         int             err;
142
143
144         /*
145          * Get buffer for PDU
146          */
147         KB_ALLOCPKT(m, sizeof(struct bgak_pdu), KB_F_NOWAIT, KB_T_HEADER);
148         if (m == NULL)
149                 return (1);
150
151         /*
152          * Setup buffer controls
153          */
154         KB_HEADSET(m, MIN(sop->so_headout,
155                 KB_BFRLEN(m) - sizeof(struct bgak_pdu)));
156         KB_LEN(m) = sizeof(struct bgak_pdu);
157
158         /*
159          * Build PDU
160          */
161         KB_DATASTART(m, bp, struct bgak_pdu *);
162         bp->bgak_rsvd = 0;
163         bp->bgak_nmr =
164                 htonl((PT_BGAK << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax));
165
166         /*
167          * Send PDU towards peer
168          */
169         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
170                 sop->so_connvc, (int)m, 0, err);
171
172         if (err)
173                 KB_FREEALL(m);
174
175         return (err);
176 }
177
178
179 /*
180  * Build and send BGREJ PDU
181  * 
182  * A BGREJ PDU will be constructed and passed down the protocol stack.
183  * The SSCOP-UU/N(UU) field is not supported.
184  *
185  * Arguments:
186  *      sop     pointer to sscop connection control block
187  *
188  * Returns:
189  *      0       PDU successfully built and passed down the stack
190  *      else    unable to build or send pdu
191  *
192  */
193 int
194 sscop_send_bgrej(sop)
195         struct sscop    *sop;
196 {
197         KBuffer         *m;
198         struct bgrej_pdu        *bp;
199         int             err;
200
201
202         /*
203          * Get buffer for PDU
204          */
205         KB_ALLOCPKT(m, sizeof(struct bgrej_pdu), KB_F_NOWAIT, KB_T_HEADER);
206         if (m == NULL)
207                 return (1);
208
209         /*
210          * Setup buffer controls
211          */
212         KB_HEADSET(m, MIN(sop->so_headout,
213                 KB_BFRLEN(m) - sizeof(struct bgrej_pdu)));
214         KB_LEN(m) = sizeof(struct bgrej_pdu);
215
216         /*
217          * Build PDU
218          */
219         KB_DATASTART(m, bp, struct bgrej_pdu *);
220         bp->bgrej_rsvd2 = 0;
221         *(u_int *)&bp->bgrej_type = htonl((PT_BGREJ << PT_TYPE_SHIFT) | 0);
222
223         /*
224          * Send PDU towards peer
225          */
226         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
227                 sop->so_connvc, (int)m, 0, err);
228
229         if (err)
230                 KB_FREEALL(m);
231
232         return (err);
233 }
234
235
236 /*
237  * Build and send END PDU
238  * 
239  * An END PDU will be constructed and passed down the protocol stack.
240  * The SSCOP-UU/N(UU) field is not supported.
241  *
242  * Arguments:
243  *      sop     pointer to sscop connection control block
244  *      source  originator of END PDU
245  *
246  * Returns:
247  *      0       PDU successfully built and passed down the stack
248  *      else    unable to build or send pdu
249  *
250  */
251 int
252 sscop_send_end(sop, source)
253         struct sscop    *sop;
254         int             source;
255 {
256         KBuffer         *m;
257         struct end_pdu  *ep;
258         int             err;
259
260
261         /*
262          * Get buffer for PDU
263          */
264         KB_ALLOCPKT(m, sizeof(struct end_pdu), KB_F_NOWAIT, KB_T_HEADER);
265         if (m == NULL)
266                 return (1);
267
268         /*
269          * Setup buffer controls
270          */
271         KB_HEADSET(m, MIN(sop->so_headout,
272                 KB_BFRLEN(m) - sizeof(struct end_pdu)));
273         KB_LEN(m) = sizeof(struct end_pdu);
274
275         /*
276          * Build PDU
277          */
278         KB_DATASTART(m, ep, struct end_pdu *);
279         ep->end_rsvd2 = 0;
280         *(u_int *)&ep->end_type = htonl((PT_END << PT_TYPE_SHIFT) | 0);
281         if (source == SSCOP_SOURCE_SSCOP) {
282                 ep->end_type |= PT_SOURCE_SSCOP;
283                 sop->so_flags |= SOF_ENDSSCOP;
284         } else if (source == SSCOP_SOURCE_USER)
285                 sop->so_flags &= ~SOF_ENDSSCOP;
286         else if ((source == SSCOP_SOURCE_LAST) &&
287                  (sop->so_flags & SOF_ENDSSCOP))
288                 ep->end_type |= PT_SOURCE_SSCOP;
289
290         /*
291          * Send PDU towards peer
292          */
293         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
294                 sop->so_connvc, (int)m, 0, err);
295
296         if (err)
297                 KB_FREEALL(m);
298
299         return (err);
300 }
301
302
303 /*
304  * Build and send ENDAK PDU
305  * 
306  * An ENDAK PDU will be constructed and passed down the protocol stack.
307  *
308  * Arguments:
309  *      sop     pointer to sscop connection control block
310  *
311  * Returns:
312  *      0       PDU successfully built and passed down the stack
313  *      else    unable to build or send pdu
314  *
315  */
316 int
317 sscop_send_endak(sop)
318         struct sscop    *sop;
319 {
320         KBuffer         *m;
321         struct endak_q2110_pdu  *e2p;
322         struct endak_qsaal_pdu  *esp;
323         int             err, size;
324
325
326         /*
327          * Get size of PDU
328          */
329         if (sop->so_vers == SSCOP_VERS_QSAAL)
330                 size = sizeof(struct endak_qsaal_pdu);
331         else
332                 size = sizeof(struct endak_q2110_pdu);
333
334         /*
335          * Get buffer for PDU
336          */
337         KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER);
338         if (m == NULL)
339                 return (1);
340
341         /*
342          * Setup buffer controls
343          */
344         KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size));
345         KB_LEN(m) = size;
346
347         /*
348          * Build PDU
349          */
350         if (sop->so_vers == SSCOP_VERS_QSAAL) {
351                 KB_DATASTART(m, esp, struct endak_qsaal_pdu *);
352                 *(u_int *)&esp->endak_type =
353                         htonl((PT_ENDAK << PT_TYPE_SHIFT) | 0);
354         } else {
355                 KB_DATASTART(m, e2p, struct endak_q2110_pdu *);
356                 e2p->endak_rsvd2 = 0;
357                 *(u_int *)&e2p->endak_type =
358                         htonl((PT_ENDAK << PT_TYPE_SHIFT) | 0);
359         }
360
361         /*
362          * Send PDU towards peer
363          */
364         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
365                 sop->so_connvc, (int)m, 0, err);
366
367         if (err)
368                 KB_FREEALL(m);
369
370         return (err);
371 }
372
373
374 /*
375  * Build and send RS PDU
376  * 
377  * A RS PDU will be constructed and passed down the protocol stack.
378  * The SSCOP-UU/N(UU) field is not supported.
379  *
380  * Arguments:
381  *      sop     pointer to sscop connection control block
382  *
383  * Returns:
384  *      0       PDU successfully built and passed down the stack
385  *      else    unable to build or send pdu
386  *
387  */
388 int
389 sscop_send_rs(sop)
390         struct sscop    *sop;
391 {
392         KBuffer         *m;
393         struct rs_pdu   *rp;
394         int             err;
395
396
397         /*
398          * Get buffer for PDU
399          */
400         KB_ALLOCPKT(m, sizeof(struct rs_pdu), KB_F_NOWAIT, KB_T_HEADER);
401         if (m == NULL)
402                 return (1);
403
404         /*
405          * Setup buffer controls
406          */
407         KB_HEADSET(m, MIN(sop->so_headout,
408                 KB_BFRLEN(m) - sizeof(struct rs_pdu)));
409         KB_LEN(m) = sizeof(struct rs_pdu);
410
411         /*
412          * Build PDU
413          */
414         KB_DATASTART(m, rp, struct rs_pdu *);
415         *(int *)&rp->rs_rsvd[0] = 0;
416         if (sop->so_vers != SSCOP_VERS_QSAAL) {
417                 rp->rs_nsq = sop->so_sendconn;
418                 rp->rs_nmr = htonl((PT_RS << PT_TYPE_SHIFT) |
419                                 SEQ_VAL(sop->so_rcvmax));
420         } else {
421                 rp->rs_nmr = htonl((PT_RS << PT_TYPE_SHIFT) | 0);
422         }
423
424         /*
425          * Send PDU towards peer
426          */
427         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
428                 sop->so_connvc, (int)m, 0, err);
429
430         if (err)
431                 KB_FREEALL(m);
432
433         return (err);
434 }
435
436
437 /*
438  * Build and send RSAK PDU
439  * 
440  * An RSAK PDU will be constructed and passed down the protocol stack.
441  *
442  * Arguments:
443  *      sop     pointer to sscop connection control block
444  *
445  * Returns:
446  *      0       PDU successfully built and passed down the stack
447  *      else    unable to build or send pdu
448  *
449  */
450 int
451 sscop_send_rsak(sop)
452         struct sscop    *sop;
453 {
454         KBuffer         *m;
455         struct rsak_q2110_pdu   *r2p;
456         struct rsak_qsaal_pdu   *rsp;
457         int             err, size;
458
459
460         /*
461          * Get size of PDU
462          */
463         if (sop->so_vers == SSCOP_VERS_QSAAL)
464                 size = sizeof(struct rsak_qsaal_pdu);
465         else
466                 size = sizeof(struct rsak_q2110_pdu);
467
468         /*
469          * Get buffer for PDU
470          */
471         KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER);
472         if (m == NULL)
473                 return (1);
474
475         /*
476          * Setup buffer controls
477          */
478         KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size));
479         KB_LEN(m) = size;
480
481         /*
482          * Build PDU
483          */
484         if (sop->so_vers == SSCOP_VERS_QSAAL) {
485                 KB_DATASTART(m, rsp, struct rsak_qsaal_pdu *);
486                 *(u_int *)&rsp->rsaks_type =
487                         htonl((PT_RSAK << PT_TYPE_SHIFT) | 0);
488         } else {
489                 KB_DATASTART(m, r2p, struct rsak_q2110_pdu *);
490                 r2p->rsak_rsvd = 0;
491                 r2p->rsak_nmr = htonl((PT_RSAK << PT_TYPE_SHIFT) |
492                                         SEQ_VAL(sop->so_rcvmax));
493         }
494
495         /*
496          * Send PDU towards peer
497          */
498         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
499                 sop->so_connvc, (int)m, 0, err);
500
501         if (err)
502                 KB_FREEALL(m);
503
504         return (err);
505 }
506
507
508 /*
509  * Build and send ER PDU
510  * 
511  * An ER PDU will be constructed and passed down the protocol stack.
512  *
513  * Arguments:
514  *      sop     pointer to sscop connection control block
515  *
516  * Returns:
517  *      0       PDU successfully built and passed down the stack
518  *      else    unable to build or send pdu
519  *
520  */
521 int
522 sscop_send_er(sop)
523         struct sscop    *sop;
524 {
525         KBuffer         *m;
526         struct er_pdu   *ep;
527         int             err;
528
529
530         /*
531          * Get buffer for PDU
532          */
533         KB_ALLOCPKT(m, sizeof(struct er_pdu), KB_F_NOWAIT, KB_T_HEADER);
534         if (m == NULL)
535                 return (1);
536
537         /*
538          * Setup buffer controls
539          */
540         KB_HEADSET(m, MIN(sop->so_headout,
541                 KB_BFRLEN(m) - sizeof(struct er_pdu)));
542         KB_LEN(m) = sizeof(struct er_pdu);
543
544         /*
545          * Build PDU
546          */
547         KB_DATASTART(m, ep, struct er_pdu *);
548         *(int *)&ep->er_rsvd[0] = 0;
549         ep->er_nsq = sop->so_sendconn;
550         ep->er_nmr = htonl((PT_ER << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax));
551
552         /*
553          * Send PDU towards peer
554          */
555         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
556                 sop->so_connvc, (int)m, 0, err);
557
558         if (err)
559                 KB_FREEALL(m);
560
561         return (err);
562 }
563
564
565 /*
566  * Build and send ERAK PDU
567  * 
568  * An ERAK PDU will be constructed and passed down the protocol stack.
569  *
570  * Arguments:
571  *      sop     pointer to sscop connection control block
572  *
573  * Returns:
574  *      0       PDU successfully built and passed down the stack
575  *      else    unable to build or send pdu
576  *
577  */
578 int
579 sscop_send_erak(sop)
580         struct sscop    *sop;
581 {
582         KBuffer         *m;
583         struct erak_pdu *ep;
584         int             err;
585
586
587         /*
588          * Get buffer for PDU
589          */
590         KB_ALLOCPKT(m, sizeof(struct erak_pdu), KB_F_NOWAIT, KB_T_HEADER);
591         if (m == NULL)
592                 return (1);
593
594         /*
595          * Setup buffer controls
596          */
597         KB_HEADSET(m, MIN(sop->so_headout,
598                 KB_BFRLEN(m) - sizeof(struct erak_pdu)));
599         KB_LEN(m) = sizeof(struct erak_pdu);
600
601         /*
602          * Build PDU
603          */
604         KB_DATASTART(m, ep, struct erak_pdu *);
605         ep->erak_rsvd = 0;
606         ep->erak_nmr = htonl((PT_ERAK << PT_TYPE_SHIFT) |
607                                 SEQ_VAL(sop->so_rcvmax));
608
609         /*
610          * Send PDU towards peer
611          */
612         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
613                 sop->so_connvc, (int)m, 0, err);
614
615         if (err)
616                 KB_FREEALL(m);
617
618         return (err);
619 }
620
621
622 /*
623  * Build and send POLL PDU
624  * 
625  * A POLL PDU will be constructed and passed down the protocol stack.
626  *
627  * Arguments:
628  *      sop     pointer to sscop connection control block
629  *
630  * Returns:
631  *      0       PDU successfully built and passed down the stack
632  *      else    unable to build or send pdu
633  *
634  */
635 int
636 sscop_send_poll(sop)
637         struct sscop    *sop;
638 {
639         KBuffer         *m;
640         struct poll_pdu *pp;
641         int             err;
642
643
644         /*
645          * Get buffer for PDU
646          */
647         KB_ALLOCPKT(m, sizeof(struct poll_pdu), KB_F_NOWAIT, KB_T_HEADER);
648         if (m == NULL)
649                 return (1);
650
651         /*
652          * Setup buffer controls
653          */
654         KB_HEADSET(m, MIN(sop->so_headout,
655                 KB_BFRLEN(m) - sizeof(struct poll_pdu)));
656         KB_LEN(m) = sizeof(struct poll_pdu);
657
658         /*
659          * Build PDU
660          */
661         KB_DATASTART(m, pp, struct poll_pdu *);
662         pp->poll_nps = htonl(SEQ_VAL(sop->so_pollsend));
663         pp->poll_ns = htonl((PT_POLL << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_send));
664
665         /*
666          * Send PDU towards peer
667          */
668         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
669                 sop->so_connvc, (int)m, 0, err);
670
671         if (err)
672                 KB_FREEALL(m);
673
674         return (err);
675 }
676
677
678 /*
679  * STAT PDU Construction - Initialize for new PDU
680  * 
681  * Arguments:
682  *      sop     pointer to sscop connection control block
683  *
684  * Returns:
685  *      addr    pointer to initialized buffer
686  *      0       unable to allocate buffer
687  *
688  */
689 static KBuffer *
690 sscop_stat_init(sop)
691         struct sscop    *sop;
692 {
693         KBuffer         *m;
694
695 #define STAT_INIT_SIZE  (sizeof(struct stat_pdu) + 2 * sizeof(sscop_seq))
696
697         /*
698          * Get buffer for PDU
699          */
700         KB_ALLOCPKT(m, STAT_INIT_SIZE, KB_F_NOWAIT, KB_T_HEADER);
701         if (m == NULL)
702                 return (0);
703
704         /*
705          * Setup buffer controls
706          */
707         KB_HEADSET(m, sop->so_headout < (KB_BFRLEN(m) - STAT_INIT_SIZE) ?
708                 sop->so_headout : 0);
709         KB_LEN(m) = 0;
710
711         return (m);
712 #undef  STAT_INIT_SIZE
713 }
714
715
716 /*
717  * STAT PDU Construction - Add List Element
718  * 
719  * Arguments:
720  *      elem    sequence number to add to list
721  *      m       pointer to current buffer
722  *
723  * Returns:
724  *      addr    pointer to current buffer (updated)
725  *      0       buffer allocation failure
726  *
727  */
728 static KBuffer *
729 sscop_stat_add(elem, m)
730         sscop_seq       elem;
731         KBuffer         *m;
732 {
733         KBuffer         *n;
734         sscop_seq       *sp;
735         int             space;
736
737         /*
738          * See if new element will fit in current buffer
739          */
740         KB_TAILROOM(m, space);
741         if (space < sizeof(elem)) {
742
743                 /*
744                  * Nope, so get another buffer
745                  */
746                 KB_ALLOC(n, sizeof(elem), KB_F_NOWAIT, KB_T_DATA);
747                 if (n == NULL)
748                         return (0);
749
750                 /*
751                  * Link in new buffer
752                  */
753                 KB_LINK(n, m);
754                 KB_LEN(n) = 0;
755                 m = n;
756         }
757
758         /*
759          * Add new element
760          */
761         KB_DATAEND(m, sp, sscop_seq *);
762         *sp = htonl(elem);
763         KB_LEN(m) += sizeof (elem);
764         return (m);
765 }
766
767
768 /*
769  * STAT PDU Construction - Add Trailer and Send
770  * 
771  * Arguments:
772  *      sop     pointer to sscop connection control block
773  *      nps     received poll sequence number (POLL.N(PS))
774  *      head    pointer to head of buffer chain
775  *      m       pointer to current (last) buffer
776  *
777  * Returns:
778  *      0       STAT successfully sent
779  *      else    unable to send STAT or truncated STAT was sent - buffer freed
780  *
781  */
782 static int
783 sscop_stat_end(sop, nps, head, m)
784         struct sscop    *sop;
785         sscop_seq       nps;
786         KBuffer         *head;
787         KBuffer         *m;
788 {
789         struct stat_pdu *sp;
790         KBuffer         *n;
791         int             err, space, trunc = 0;
792
793         /*
794          * See if PDU trailer will fit in current buffer
795          */
796         KB_TAILROOM(m, space);
797         if (space < sizeof(struct stat_pdu)) {
798
799                 /*
800                  * Doesn't fit, so get another buffer
801                  */
802                 KB_ALLOC(n, sizeof(struct stat_pdu), KB_F_NOWAIT, KB_T_DATA);
803                 if (n == NULL) {
804                         /*
805                          * Out of buffers - truncate elements and send
806                          * what we can, but tell caller that we can't
807                          * send any more segments.
808                          */
809                         trunc = 1;
810                         do {
811                                 KB_LEN(m) -= sizeof(sscop_seq);
812                                 space += sizeof(sscop_seq);
813                         } while (space < sizeof(struct stat_pdu));
814                 } else {
815                         /*
816                          * Link in new buffer
817                          */
818                         KB_LINK(n, m);
819                         KB_LEN(n) = 0;
820                         m = n;
821                 }
822         }
823
824         /*
825          * Build PDU trailer
826          */
827         KB_DATAEND(m, sp, struct stat_pdu *);
828         sp->stat_nps = htonl(nps);
829         sp->stat_nmr = htonl(sop->so_rcvmax);
830         sp->stat_nr = htonl(sop->so_rcvnext);
831         sp->stat_type = PT_STAT;
832         KB_LEN(m) += sizeof(struct stat_pdu);
833
834         /*
835          * Finally, send the STAT
836          */
837         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
838                 sop->so_connvc, (int)head, 0, err);
839
840         if (err) {
841                 /*
842                  * We lie about the STACK_CALL failing...
843                  */
844                 KB_FREEALL(head);
845         }
846
847         if (trunc)
848                 return (1);
849         else
850                 return (0);
851 }
852
853
854 /*
855  * Check for PDU in Receive Queue
856  * 
857  * A receive queue will be searched for an SD PDU matching the requested
858  * sequence number.  The caller must supply a pointer to the address of the
859  * PDU in the particular receive queue at which to begin the search.  This
860  * function will update that pointer as it traverses the queue.
861  *
862  * Arguments:
863  *      sop     pointer to sscop connection control block
864  *      seq     sequence number of PDU to locate
865  *      currp   address of pointer to PDU in receive queue to start search
866  *
867  * Returns:
868  *      0       reqeusted PDU not in receive queue
869  *      1       requested PDU located in receive queue
870  *
871  */
872 static int
873 sscop_recv_locate(sop, seq, currp)
874         struct sscop    *sop;
875         sscop_seq       seq;
876         struct pdu_hdr  **currp;
877 {
878         sscop_seq       cs;
879
880         /*
881          * Search queue until we know the answer
882          */
883         while (1) {
884                 /*
885                  * If we're at the end of the queue, the PDU isn't there
886                  */
887                 if (*currp == NULL)
888                         return (0);
889
890                 /*
891                  * Get the current PDU sequence number
892                  */
893                 cs = (*currp)->ph_ns;
894
895                 /*
896                  * See if we're at the requested PDU
897                  */
898                 if (seq == cs)
899                         return (1);
900
901                 /*
902                  * If we're past the requested seq number, 
903                  * the PDU isn't there
904                  */
905                 if (SEQ_LT(seq, cs, sop->so_rcvnext))
906                         return (0);
907
908                 /*
909                  * Go to next PDU and keep looking
910                  */
911                 *currp = (*currp)->ph_recv_lk;
912         }
913 }
914
915
916 /*
917  * Build and send STAT PDU
918  * 
919  * A STAT PDU will be constructed and passed down the protocol stack.
920  *
921  * Arguments:
922  *      sop     pointer to sscop connection control block
923  *      nps     received poll sequence number (POLL.N(PS))
924  *
925  * Returns:
926  *      0       PDU successfully built and passed down the stack
927  *      else    unable to build or send complete pdu
928  *
929  */
930 int
931 sscop_send_stat(sop, nps)
932         struct sscop    *sop;
933         sscop_seq       nps;
934 {
935         KBuffer         *head, *curr, *n;
936         struct pdu_hdr  *rq = sop->so_recv_hd;
937         sscop_seq       i;
938         sscop_seq       vrh = sop->so_rcvhigh;
939         sscop_seq       vrr = sop->so_rcvnext;
940         int             len = 0;
941
942         /*
943          * Initialize for start of STAT PDU
944          */
945         head = sscop_stat_init(sop);
946         if (head == NULL)
947                 return (1);
948         curr = head;
949
950         /*
951          * Start with first PDU not yet received
952          */
953         i = vrr;
954
955         /*
956          * Keep looping until we get to last sent PDU
957          */
958         while (i != vrh) {
959
960                 /*
961                  * Find next missing PDU
962                  */
963                 while (SEQ_LT(i, vrh, vrr) && sscop_recv_locate(sop, i, &rq)) {
964                         SEQ_INCR(i, 1);
965                 }
966
967                 /*
968                  * Add odd (start of missing gap) STAT element 
969                  */
970                 n = sscop_stat_add(i, curr);
971                 if (n == NULL) {
972                         goto nobufs;
973                 }
974                 curr = n;
975                 len++;
976
977                 /*
978                  * Have we reached the last sent PDU sequence number??
979                  */
980                 if (i == vrh) {
981                         /*
982                          * Yes, then we're done, send STAT
983                          */
984                         break;
985                 }
986
987                 /*
988                  * Have we reached the max STAT size yet??
989                  */
990                 if (len >= PDU_MAX_ELEM) {
991                         /*
992                          * Yes, send this STAT segment
993                          */
994                         if (sscop_stat_end(sop, nps, head, curr)) {
995                                 return (1);
996                         }
997
998                         /*
999                          * Start a new segment
1000                          */
1001                         head = sscop_stat_init(sop);
1002                         if (head == NULL)
1003                                 return (1);
1004                         curr = head;
1005
1006                         /*
1007                          * Restart missing gap
1008                          */
1009                         curr = sscop_stat_add(i, curr);
1010                         if (curr == NULL) {
1011                                 KB_FREEALL(head);
1012                                 return (1);
1013                         }
1014                         len = 1;
1015                 }
1016
1017                 /*
1018                  * Now find the end of the missing gap
1019                  */
1020                 do {
1021                         SEQ_INCR(i, 1);
1022                 } while (SEQ_LT(i, vrh, vrr) && 
1023                          (sscop_recv_locate(sop, i, &rq) == 0));
1024
1025                 /*
1026                  * Add even (start of received gap) STAT element 
1027                  */
1028                 n = sscop_stat_add(i, curr);
1029                 if (n == NULL) {
1030                         goto nobufs;
1031                 }
1032                 curr = n;
1033                 len++;
1034         }
1035
1036         /*
1037          * Finally, send the STAT PDU (or last STAT segment)
1038          */
1039         if (sscop_stat_end(sop, nps, head, curr)) {
1040                 return (1);
1041         }
1042
1043         return (0);
1044
1045 nobufs:
1046         /*
1047          * Send a truncated STAT PDU
1048          */
1049         sscop_stat_end(sop, nps, head, curr);
1050
1051         return (1);
1052 }
1053
1054
1055 /*
1056  * Build and send USTAT PDU
1057  * 
1058  * A USTAT PDU will be constructed and passed down the protocol stack.
1059  *
1060  * Arguments:
1061  *      sop     pointer to sscop connection control block
1062  *      ns      sequence number for second list element 
1063  *
1064  * Returns:
1065  *      0       PDU successfully built and passed down the stack
1066  *      else    unable to build or send pdu
1067  *
1068  */
1069 int
1070 sscop_send_ustat(sop, ns)
1071         struct sscop    *sop;
1072         sscop_seq       ns;
1073 {
1074         KBuffer         *m;
1075         struct ustat_pdu        *up;
1076         int             err;
1077
1078
1079         /*
1080          * Get buffer for PDU
1081          */
1082         KB_ALLOCPKT(m, sizeof(struct ustat_pdu), KB_F_NOWAIT, KB_T_HEADER);
1083         if (m == NULL)
1084                 return (1);
1085
1086         /*
1087          * Setup buffer controls
1088          */
1089         KB_HEADSET(m, MIN(sop->so_headout,
1090                 KB_BFRLEN(m) - sizeof(struct ustat_pdu)));
1091         KB_LEN(m) = sizeof(struct ustat_pdu);
1092
1093         /*
1094          * Build PDU
1095          */
1096         KB_DATASTART(m, up, struct ustat_pdu *);
1097         up->ustat_le1 = htonl(SEQ_VAL(sop->so_rcvhigh));
1098         up->ustat_le2 = htonl(SEQ_VAL(ns));
1099         up->ustat_nmr = htonl(SEQ_VAL(sop->so_rcvmax));
1100         up->ustat_nr =
1101                 htonl((PT_USTAT << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvnext));
1102
1103         /*
1104          * Send PDU towards peer
1105          */
1106         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
1107                 sop->so_connvc, (int)m, 0, err);
1108
1109         if (err)
1110                 KB_FREEALL(m);
1111
1112         return (err);
1113 }
1114
1115
1116 /*
1117  * Build and send UD PDU
1118  * 
1119  * A UD PDU will be constructed and passed down the protocol stack.
1120  *
1121  * Arguments:
1122  *      sop     pointer to sscop connection control block
1123  *      m       pointer to user data buffer chain
1124  *
1125  * Returns:
1126  *      0       PDU successfully built and passed down the stack
1127  *      else    unable to build or send pdu (buffer released)
1128  *
1129  */
1130 int
1131 sscop_send_ud(sop, m)
1132         struct sscop    *sop;
1133         KBuffer         *m;
1134 {
1135         KBuffer         *ml, *n;
1136         int             len = 0, err;
1137         int             pad, trlen, space;
1138         u_char          *cp;
1139
1140         /*
1141          * Count data and get to last buffer in chain
1142          */
1143         for (ml = m; ; ml = KB_NEXT(ml)) {
1144                 len += KB_LEN(ml);
1145                 if (KB_NEXT(ml) == NULL)
1146                         break;
1147         }
1148
1149         /*
1150          * Verify data length
1151          */
1152         if (len > sop->so_parm.sp_maxinfo) {
1153                 KB_FREEALL(m);
1154                 sscop_abort(sop, "sscop: maximum unitdata size exceeded\n");
1155                 return (1);
1156         }
1157
1158         /*
1159          * Figure out how much padding we'll need
1160          */
1161         pad = ((len + (PDU_PAD_ALIGN - 1)) & ~(PDU_PAD_ALIGN - 1)) - len;
1162         trlen = pad + sizeof(struct ud_pdu);
1163
1164         /*
1165          * Get space for PDU trailer and padding
1166          */
1167         KB_TAILROOM(ml, space);
1168         if (space < trlen) {
1169                 /*
1170                  * Allocate & link buffer for pad and trailer
1171                  */
1172                 KB_ALLOC(n, trlen, KB_F_NOWAIT, KB_T_HEADER);
1173                 if (n == NULL)
1174                         return (1);
1175
1176                 KB_LEN(n) = 0;
1177                 KB_LINK(n, ml);
1178                 ml = n;
1179         }
1180
1181         /*
1182          * Build the PDU trailer
1183          *
1184          * Since we can't be sure of alignment in the buffers, we
1185          * have to move this a byte at a time.
1186          */
1187         KB_DATAEND(ml, cp, u_char *);
1188         cp += pad;
1189         *cp++ = (pad << PT_PAD_SHIFT) | PT_UD;
1190         KM_ZERO(cp, 3);
1191         KB_LEN(ml) += trlen;
1192
1193         /*
1194          * Now pass PDU down the stack
1195          */
1196         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, 
1197                 sop->so_connvc, (int)m, 0, err);
1198         if (err) {
1199                 KB_FREEALL(m);
1200                 return (1);
1201         }
1202
1203         return (0);
1204 }
1205
1206
1207 /*
1208  * Print an SSCOP PDU
1209  * 
1210  * Arguments:
1211  *      sop     pointer to sscop connection control block
1212  *      m       pointer to pdu buffer chain
1213  *      msg     pointer to message string
1214  *
1215  * Returns:
1216  *      none
1217  *
1218  */
1219 void
1220 sscop_pdu_print(sop, m, msg)
1221         struct sscop    *sop;
1222         KBuffer         *m;
1223         char            *msg;
1224 {
1225         char            buf[128];
1226         struct vccb     *vcp;
1227
1228         vcp = sop->so_connvc->cvc_vcc;
1229         snprintf(buf, sizeof(buf),
1230             "sscop %s: vcc=(%d,%d)\n", msg, vcp->vc_vpi, vcp->vc_vci);
1231         atm_pdu_print(m, buf);
1232 }
1233