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