HAMMER Utilities: MFC work to date.
[dragonfly.git] / sys / netproto / atm / uni / sscop_pdu.c
blob374f000c0dc86022d2b95221394c8ad010513159
1 /*
3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
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 $
31 * ATM Forum UNI Support
32 * ---------------------
34 * SSCOP - PDU subroutines
38 #include <netproto/atm/kern_include.h>
40 #include "sscop.h"
41 #include "sscop_misc.h"
42 #include "sscop_pdu.h"
43 #include "sscop_var.h"
46 * Local functions
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 **);
57 * Build and send BGN PDU
59 * A BGN PDU will be constructed and passed down the protocol stack.
60 * The SSCOP-UU/N(UU) field is not supported.
62 * Arguments:
63 * sop pointer to sscop connection control block
64 * source originator of BGN PDU (Q.SAAL1 only)
66 * Returns:
67 * 0 PDU successfully built and passed down the stack
68 * else unable to build or send pdu
71 int
72 sscop_send_bgn(struct sscop *sop, int source)
74 KBuffer *m;
75 struct bgn_pdu *bp;
76 int err;
80 * Get buffer for PDU
82 KB_ALLOCPKT(m, sizeof(struct bgn_pdu), KB_F_NOWAIT, KB_T_HEADER);
83 if (m == NULL)
84 return (1);
87 * Setup buffer controls
89 KB_HEADSET(m, MIN(sop->so_headout,
90 KB_BFRLEN(m) - sizeof(struct bgn_pdu)));
91 KB_LEN(m) = sizeof(struct bgn_pdu);
94 * Build PDU
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;
107 * Send PDU towards peer
109 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
110 sop->so_connvc, (int)m, 0, err);
112 if (err)
113 KB_FREEALL(m);
115 return (err);
120 * Build and send BGAK PDU
122 * A BGAK PDU will be constructed and passed down the protocol stack.
123 * The SSCOP-UU/N(UU) field is not supported.
125 * Arguments:
126 * sop pointer to sscop connection control block
128 * Returns:
129 * 0 PDU successfully built and passed down the stack
130 * else unable to build or send pdu
134 sscop_send_bgak(struct sscop *sop)
136 KBuffer *m;
137 struct bgak_pdu *bp;
138 int err;
142 * Get buffer for PDU
144 KB_ALLOCPKT(m, sizeof(struct bgak_pdu), KB_F_NOWAIT, KB_T_HEADER);
145 if (m == NULL)
146 return (1);
149 * Setup buffer controls
151 KB_HEADSET(m, MIN(sop->so_headout,
152 KB_BFRLEN(m) - sizeof(struct bgak_pdu)));
153 KB_LEN(m) = sizeof(struct bgak_pdu);
156 * Build PDU
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));
164 * Send PDU towards peer
166 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
167 sop->so_connvc, (int)m, 0, err);
169 if (err)
170 KB_FREEALL(m);
172 return (err);
177 * Build and send BGREJ PDU
179 * A BGREJ PDU will be constructed and passed down the protocol stack.
180 * The SSCOP-UU/N(UU) field is not supported.
182 * Arguments:
183 * sop pointer to sscop connection control block
185 * Returns:
186 * 0 PDU successfully built and passed down the stack
187 * else unable to build or send pdu
191 sscop_send_bgrej(struct sscop *sop)
193 KBuffer *m;
194 struct bgrej_pdu *bp;
195 int err;
199 * Get buffer for PDU
201 KB_ALLOCPKT(m, sizeof(struct bgrej_pdu), KB_F_NOWAIT, KB_T_HEADER);
202 if (m == NULL)
203 return (1);
206 * Setup buffer controls
208 KB_HEADSET(m, MIN(sop->so_headout,
209 KB_BFRLEN(m) - sizeof(struct bgrej_pdu)));
210 KB_LEN(m) = sizeof(struct bgrej_pdu);
213 * Build PDU
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);
220 * Send PDU towards peer
222 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
223 sop->so_connvc, (int)m, 0, err);
225 if (err)
226 KB_FREEALL(m);
228 return (err);
233 * Build and send END PDU
235 * An END PDU will be constructed and passed down the protocol stack.
236 * The SSCOP-UU/N(UU) field is not supported.
238 * Arguments:
239 * sop pointer to sscop connection control block
240 * source originator of END PDU
242 * Returns:
243 * 0 PDU successfully built and passed down the stack
244 * else unable to build or send pdu
248 sscop_send_end(struct sscop *sop, int source)
250 KBuffer *m;
251 struct end_pdu *ep;
252 int err;
256 * Get buffer for PDU
258 KB_ALLOCPKT(m, sizeof(struct end_pdu), KB_F_NOWAIT, KB_T_HEADER);
259 if (m == NULL)
260 return (1);
263 * Setup buffer controls
265 KB_HEADSET(m, MIN(sop->so_headout,
266 KB_BFRLEN(m) - sizeof(struct end_pdu)));
267 KB_LEN(m) = sizeof(struct end_pdu);
270 * Build PDU
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;
285 * Send PDU towards peer
287 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
288 sop->so_connvc, (int)m, 0, err);
290 if (err)
291 KB_FREEALL(m);
293 return (err);
298 * Build and send ENDAK PDU
300 * An ENDAK PDU will be constructed and passed down the protocol stack.
302 * Arguments:
303 * sop pointer to sscop connection control block
305 * Returns:
306 * 0 PDU successfully built and passed down the stack
307 * else unable to build or send pdu
311 sscop_send_endak(struct sscop *sop)
313 KBuffer *m;
314 struct endak_q2110_pdu *e2p;
315 struct endak_qsaal_pdu *esp;
316 int err, size;
320 * Get size of PDU
322 if (sop->so_vers == SSCOP_VERS_QSAAL)
323 size = sizeof(struct endak_qsaal_pdu);
324 else
325 size = sizeof(struct endak_q2110_pdu);
328 * Get buffer for PDU
330 KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER);
331 if (m == NULL)
332 return (1);
335 * Setup buffer controls
337 KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size));
338 KB_LEN(m) = size;
341 * Build PDU
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);
355 * Send PDU towards peer
357 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
358 sop->so_connvc, (int)m, 0, err);
360 if (err)
361 KB_FREEALL(m);
363 return (err);
368 * Build and send RS PDU
370 * A RS PDU will be constructed and passed down the protocol stack.
371 * The SSCOP-UU/N(UU) field is not supported.
373 * Arguments:
374 * sop pointer to sscop connection control block
376 * Returns:
377 * 0 PDU successfully built and passed down the stack
378 * else unable to build or send pdu
382 sscop_send_rs(struct sscop *sop)
384 KBuffer *m;
385 struct rs_pdu *rp;
386 int err;
390 * Get buffer for PDU
392 KB_ALLOCPKT(m, sizeof(struct rs_pdu), KB_F_NOWAIT, KB_T_HEADER);
393 if (m == NULL)
394 return (1);
397 * Setup buffer controls
399 KB_HEADSET(m, MIN(sop->so_headout,
400 KB_BFRLEN(m) - sizeof(struct rs_pdu)));
401 KB_LEN(m) = sizeof(struct rs_pdu);
404 * Build PDU
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);
417 * Send PDU towards peer
419 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
420 sop->so_connvc, (int)m, 0, err);
422 if (err)
423 KB_FREEALL(m);
425 return (err);
430 * Build and send RSAK PDU
432 * An RSAK PDU will be constructed and passed down the protocol stack.
434 * Arguments:
435 * sop pointer to sscop connection control block
437 * Returns:
438 * 0 PDU successfully built and passed down the stack
439 * else unable to build or send pdu
443 sscop_send_rsak(struct sscop *sop)
445 KBuffer *m;
446 struct rsak_q2110_pdu *r2p;
447 struct rsak_qsaal_pdu *rsp;
448 int err, size;
452 * Get size of PDU
454 if (sop->so_vers == SSCOP_VERS_QSAAL)
455 size = sizeof(struct rsak_qsaal_pdu);
456 else
457 size = sizeof(struct rsak_q2110_pdu);
460 * Get buffer for PDU
462 KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER);
463 if (m == NULL)
464 return (1);
467 * Setup buffer controls
469 KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size));
470 KB_LEN(m) = size;
473 * Build PDU
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));
487 * Send PDU towards peer
489 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
490 sop->so_connvc, (int)m, 0, err);
492 if (err)
493 KB_FREEALL(m);
495 return (err);
500 * Build and send ER PDU
502 * An ER PDU will be constructed and passed down the protocol stack.
504 * Arguments:
505 * sop pointer to sscop connection control block
507 * Returns:
508 * 0 PDU successfully built and passed down the stack
509 * else unable to build or send pdu
513 sscop_send_er(struct sscop *sop)
515 KBuffer *m;
516 struct er_pdu *ep;
517 int err;
521 * Get buffer for PDU
523 KB_ALLOCPKT(m, sizeof(struct er_pdu), KB_F_NOWAIT, KB_T_HEADER);
524 if (m == NULL)
525 return (1);
528 * Setup buffer controls
530 KB_HEADSET(m, MIN(sop->so_headout,
531 KB_BFRLEN(m) - sizeof(struct er_pdu)));
532 KB_LEN(m) = sizeof(struct er_pdu);
535 * Build PDU
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));
543 * Send PDU towards peer
545 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
546 sop->so_connvc, (int)m, 0, err);
548 if (err)
549 KB_FREEALL(m);
551 return (err);
556 * Build and send ERAK PDU
558 * An ERAK PDU will be constructed and passed down the protocol stack.
560 * Arguments:
561 * sop pointer to sscop connection control block
563 * Returns:
564 * 0 PDU successfully built and passed down the stack
565 * else unable to build or send pdu
569 sscop_send_erak(struct sscop *sop)
571 KBuffer *m;
572 struct erak_pdu *ep;
573 int err;
577 * Get buffer for PDU
579 KB_ALLOCPKT(m, sizeof(struct erak_pdu), KB_F_NOWAIT, KB_T_HEADER);
580 if (m == NULL)
581 return (1);
584 * Setup buffer controls
586 KB_HEADSET(m, MIN(sop->so_headout,
587 KB_BFRLEN(m) - sizeof(struct erak_pdu)));
588 KB_LEN(m) = sizeof(struct erak_pdu);
591 * Build PDU
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));
599 * Send PDU towards peer
601 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
602 sop->so_connvc, (int)m, 0, err);
604 if (err)
605 KB_FREEALL(m);
607 return (err);
612 * Build and send POLL PDU
614 * A POLL PDU will be constructed and passed down the protocol stack.
616 * Arguments:
617 * sop pointer to sscop connection control block
619 * Returns:
620 * 0 PDU successfully built and passed down the stack
621 * else unable to build or send pdu
625 sscop_send_poll(struct sscop *sop)
627 KBuffer *m;
628 struct poll_pdu *pp;
629 int err;
633 * Get buffer for PDU
635 KB_ALLOCPKT(m, sizeof(struct poll_pdu), KB_F_NOWAIT, KB_T_HEADER);
636 if (m == NULL)
637 return (1);
640 * Setup buffer controls
642 KB_HEADSET(m, MIN(sop->so_headout,
643 KB_BFRLEN(m) - sizeof(struct poll_pdu)));
644 KB_LEN(m) = sizeof(struct poll_pdu);
647 * Build PDU
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));
654 * Send PDU towards peer
656 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
657 sop->so_connvc, (int)m, 0, err);
659 if (err)
660 KB_FREEALL(m);
662 return (err);
667 * STAT PDU Construction - Initialize for new PDU
669 * Arguments:
670 * sop pointer to sscop connection control block
672 * Returns:
673 * addr pointer to initialized buffer
674 * 0 unable to allocate buffer
677 static KBuffer *
678 sscop_stat_init(struct sscop *sop)
680 KBuffer *m;
682 #define STAT_INIT_SIZE (sizeof(struct stat_pdu) + 2 * sizeof(sscop_seq))
685 * Get buffer for PDU
687 KB_ALLOCPKT(m, STAT_INIT_SIZE, KB_F_NOWAIT, KB_T_HEADER);
688 if (m == NULL)
689 return (0);
692 * Setup buffer controls
694 KB_HEADSET(m, sop->so_headout < (KB_BFRLEN(m) - STAT_INIT_SIZE) ?
695 sop->so_headout : 0);
696 KB_LEN(m) = 0;
698 return (m);
699 #undef STAT_INIT_SIZE
704 * STAT PDU Construction - Add List Element
706 * Arguments:
707 * elem sequence number to add to list
708 * m pointer to current buffer
710 * Returns:
711 * addr pointer to current buffer (updated)
712 * 0 buffer allocation failure
715 static KBuffer *
716 sscop_stat_add(sscop_seq elem, KBuffer *m)
718 KBuffer *n;
719 sscop_seq *sp;
720 int space;
723 * See if new element will fit in current buffer
725 KB_TAILROOM(m, space);
726 if (space < sizeof(elem)) {
729 * Nope, so get another buffer
731 KB_ALLOC(n, sizeof(elem), KB_F_NOWAIT, KB_T_DATA);
732 if (n == NULL)
733 return (0);
736 * Link in new buffer
738 KB_LINK(n, m);
739 KB_LEN(n) = 0;
740 m = n;
744 * Add new element
746 KB_DATAEND(m, sp, sscop_seq *);
747 *sp = htonl(elem);
748 KB_LEN(m) += sizeof (elem);
749 return (m);
754 * STAT PDU Construction - Add Trailer and Send
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
762 * Returns:
763 * 0 STAT successfully sent
764 * else unable to send STAT or truncated STAT was sent - buffer freed
767 static int
768 sscop_stat_end(struct sscop *sop, sscop_seq nps, KBuffer *head, KBuffer *m)
770 struct stat_pdu *sp;
771 KBuffer *n;
772 int err, space, trunc = 0;
775 * See if PDU trailer will fit in current buffer
777 KB_TAILROOM(m, space);
778 if (space < sizeof(struct stat_pdu)) {
781 * Doesn't fit, so get another buffer
783 KB_ALLOC(n, sizeof(struct stat_pdu), KB_F_NOWAIT, KB_T_DATA);
784 if (n == NULL) {
786 * Out of buffers - truncate elements and send
787 * what we can, but tell caller that we can't
788 * send any more segments.
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 {
797 * Link in new buffer
799 KB_LINK(n, m);
800 KB_LEN(n) = 0;
801 m = n;
806 * Build PDU trailer
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);
816 * Finally, send the STAT
818 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
819 sop->so_connvc, (int)head, 0, err);
821 if (err) {
823 * We lie about the STACK_CALL failing...
825 KB_FREEALL(head);
828 if (trunc)
829 return (1);
830 else
831 return (0);
836 * Check for PDU in Receive Queue
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.
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
848 * Returns:
849 * 0 reqeusted PDU not in receive queue
850 * 1 requested PDU located in receive queue
853 static int
854 sscop_recv_locate(struct sscop *sop, sscop_seq seq, struct pdu_hdr **currp)
856 sscop_seq cs;
859 * Search queue until we know the answer
861 while (1) {
863 * If we're at the end of the queue, the PDU isn't there
865 if (*currp == NULL)
866 return (0);
869 * Get the current PDU sequence number
871 cs = (*currp)->ph_ns;
874 * See if we're at the requested PDU
876 if (seq == cs)
877 return (1);
880 * If we're past the requested seq number,
881 * the PDU isn't there
883 if (SEQ_LT(seq, cs, sop->so_rcvnext))
884 return (0);
887 * Go to next PDU and keep looking
889 *currp = (*currp)->ph_recv_lk;
895 * Build and send STAT PDU
897 * A STAT PDU will be constructed and passed down the protocol stack.
899 * Arguments:
900 * sop pointer to sscop connection control block
901 * nps received poll sequence number (POLL.N(PS))
903 * Returns:
904 * 0 PDU successfully built and passed down the stack
905 * else unable to build or send complete pdu
909 sscop_send_stat(struct sscop *sop, sscop_seq nps)
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;
919 * Initialize for start of STAT PDU
921 head = sscop_stat_init(sop);
922 if (head == NULL)
923 return (1);
924 curr = head;
927 * Start with first PDU not yet received
929 i = vrr;
932 * Keep looping until we get to last sent PDU
934 while (i != vrh) {
937 * Find next missing PDU
939 while (SEQ_LT(i, vrh, vrr) && sscop_recv_locate(sop, i, &rq)) {
940 SEQ_INCR(i, 1);
944 * Add odd (start of missing gap) STAT element
946 n = sscop_stat_add(i, curr);
947 if (n == NULL) {
948 goto nobufs;
950 curr = n;
951 len++;
954 * Have we reached the last sent PDU sequence number??
956 if (i == vrh) {
958 * Yes, then we're done, send STAT
960 break;
964 * Have we reached the max STAT size yet??
966 if (len >= PDU_MAX_ELEM) {
968 * Yes, send this STAT segment
970 if (sscop_stat_end(sop, nps, head, curr)) {
971 return (1);
975 * Start a new segment
977 head = sscop_stat_init(sop);
978 if (head == NULL)
979 return (1);
980 curr = head;
983 * Restart missing gap
985 curr = sscop_stat_add(i, curr);
986 if (curr == NULL) {
987 KB_FREEALL(head);
988 return (1);
990 len = 1;
994 * Now find the end of the missing gap
996 do {
997 SEQ_INCR(i, 1);
998 } while (SEQ_LT(i, vrh, vrr) &&
999 (sscop_recv_locate(sop, i, &rq) == 0));
1002 * Add even (start of received gap) STAT element
1004 n = sscop_stat_add(i, curr);
1005 if (n == NULL) {
1006 goto nobufs;
1008 curr = n;
1009 len++;
1013 * Finally, send the STAT PDU (or last STAT segment)
1015 if (sscop_stat_end(sop, nps, head, curr)) {
1016 return (1);
1019 return (0);
1021 nobufs:
1023 * Send a truncated STAT PDU
1025 sscop_stat_end(sop, nps, head, curr);
1027 return (1);
1032 * Build and send USTAT PDU
1034 * A USTAT PDU will be constructed and passed down the protocol stack.
1036 * Arguments:
1037 * sop pointer to sscop connection control block
1038 * ns sequence number for second list element
1040 * Returns:
1041 * 0 PDU successfully built and passed down the stack
1042 * else unable to build or send pdu
1046 sscop_send_ustat(struct sscop *sop, sscop_seq ns)
1048 KBuffer *m;
1049 struct ustat_pdu *up;
1050 int err;
1054 * Get buffer for PDU
1056 KB_ALLOCPKT(m, sizeof(struct ustat_pdu), KB_F_NOWAIT, KB_T_HEADER);
1057 if (m == NULL)
1058 return (1);
1061 * Setup buffer controls
1063 KB_HEADSET(m, MIN(sop->so_headout,
1064 KB_BFRLEN(m) - sizeof(struct ustat_pdu)));
1065 KB_LEN(m) = sizeof(struct ustat_pdu);
1068 * Build PDU
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));
1078 * Send PDU towards peer
1080 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
1081 sop->so_connvc, (int)m, 0, err);
1083 if (err)
1084 KB_FREEALL(m);
1086 return (err);
1091 * Build and send UD PDU
1093 * A UD PDU will be constructed and passed down the protocol stack.
1095 * Arguments:
1096 * sop pointer to sscop connection control block
1097 * m pointer to user data buffer chain
1099 * Returns:
1100 * 0 PDU successfully built and passed down the stack
1101 * else unable to build or send pdu (buffer released)
1105 sscop_send_ud(struct sscop *sop, KBuffer *m)
1107 KBuffer *ml, *n;
1108 int len = 0, err;
1109 int pad, trlen, space;
1110 u_char *cp;
1113 * Count data and get to last buffer in chain
1115 for (ml = m; ; ml = KB_NEXT(ml)) {
1116 len += KB_LEN(ml);
1117 if (KB_NEXT(ml) == NULL)
1118 break;
1122 * Verify data length
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);
1131 * Figure out how much padding we'll need
1133 pad = ((len + (PDU_PAD_ALIGN - 1)) & ~(PDU_PAD_ALIGN - 1)) - len;
1134 trlen = pad + sizeof(struct ud_pdu);
1137 * Get space for PDU trailer and padding
1139 KB_TAILROOM(ml, space);
1140 if (space < trlen) {
1142 * Allocate & link buffer for pad and trailer
1144 KB_ALLOC(n, trlen, KB_F_NOWAIT, KB_T_HEADER);
1145 if (n == NULL)
1146 return (1);
1148 KB_LEN(n) = 0;
1149 KB_LINK(n, ml);
1150 ml = n;
1154 * Build the PDU trailer
1156 * Since we can't be sure of alignment in the buffers, we
1157 * have to move this a byte at a time.
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;
1166 * Now pass PDU down the stack
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);
1175 return (0);
1180 * Print an SSCOP PDU
1182 * Arguments:
1183 * sop pointer to sscop connection control block
1184 * m pointer to pdu buffer chain
1185 * msg pointer to message string
1187 * Returns:
1188 * none
1191 void
1192 sscop_pdu_print(struct sscop *sop, KBuffer *m, char *msg)
1194 char buf[128];
1195 struct vccb *vcp;
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);