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>
41 #include "sscop_misc.h"
42 #include "sscop_pdu.h"
43 #include "sscop_var.h"
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,
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.
63 * sop pointer to sscop connection control block
64 * source originator of BGN PDU (Q.SAAL1 only)
67 * 0 PDU successfully built and passed down the stack
68 * else unable to build or send pdu
72 sscop_send_bgn(struct sscop *sop, int source)
82 KB_ALLOCPKT(m, sizeof(struct bgn_pdu), KB_F_NOWAIT, KB_T_HEADER);
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);
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;
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);
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.
126 * sop pointer to sscop connection control block
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)
144 KB_ALLOCPKT(m, sizeof(struct bgak_pdu), KB_F_NOWAIT, KB_T_HEADER);
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);
158 KB_DATASTART(m, bp, struct bgak_pdu *);
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);
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.
183 * sop pointer to sscop connection control block
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)
194 struct bgrej_pdu *bp;
201 KB_ALLOCPKT(m, sizeof(struct bgrej_pdu), KB_F_NOWAIT, KB_T_HEADER);
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);
215 KB_DATASTART(m, bp, struct bgrej_pdu *);
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);
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.
239 * sop pointer to sscop connection control block
240 * source originator of END PDU
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)
258 KB_ALLOCPKT(m, sizeof(struct end_pdu), KB_F_NOWAIT, KB_T_HEADER);
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);
272 KB_DATASTART(m, ep, struct end_pdu *);
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);
298 * Build and send ENDAK PDU
300 * An ENDAK PDU will be constructed and passed down the protocol stack.
303 * sop pointer to sscop connection control block
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)
314 struct endak_q2110_pdu *e2p;
315 struct endak_qsaal_pdu *esp;
322 if (sop->so_vers == SSCOP_VERS_QSAAL)
323 size = sizeof(struct endak_qsaal_pdu);
325 size = sizeof(struct endak_q2110_pdu);
330 KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER);
335 * Setup buffer controls
337 KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size));
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);
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);
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.
374 * sop pointer to sscop connection control block
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)
392 KB_ALLOCPKT(m, sizeof(struct rs_pdu), KB_F_NOWAIT, KB_T_HEADER);
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);
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));
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);
430 * Build and send RSAK PDU
432 * An RSAK PDU will be constructed and passed down the protocol stack.
435 * sop pointer to sscop connection control block
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)
446 struct rsak_q2110_pdu *r2p;
447 struct rsak_qsaal_pdu *rsp;
454 if (sop->so_vers == SSCOP_VERS_QSAAL)
455 size = sizeof(struct rsak_qsaal_pdu);
457 size = sizeof(struct rsak_q2110_pdu);
462 KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER);
467 * Setup buffer controls
469 KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size));
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);
480 KB_DATASTART(m, r2p, struct rsak_q2110_pdu *);
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);
500 * Build and send ER PDU
502 * An ER PDU will be constructed and passed down the protocol stack.
505 * sop pointer to sscop connection control block
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)
523 KB_ALLOCPKT(m, sizeof(struct er_pdu), KB_F_NOWAIT, KB_T_HEADER);
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);
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);
556 * Build and send ERAK PDU
558 * An ERAK PDU will be constructed and passed down the protocol stack.
561 * sop pointer to sscop connection control block
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)
579 KB_ALLOCPKT(m, sizeof(struct erak_pdu), KB_F_NOWAIT, KB_T_HEADER);
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);
593 KB_DATASTART(m, ep, struct erak_pdu *);
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);
612 * Build and send POLL PDU
614 * A POLL PDU will be constructed and passed down the protocol stack.
617 * sop pointer to sscop connection control block
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)
635 KB_ALLOCPKT(m, sizeof(struct poll_pdu), KB_F_NOWAIT, KB_T_HEADER);
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);
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);
667 * STAT PDU Construction - Initialize for new PDU
670 * sop pointer to sscop connection control block
673 * addr pointer to initialized buffer
674 * 0 unable to allocate buffer
678 sscop_stat_init(struct sscop *sop)
682 #define STAT_INIT_SIZE (sizeof(struct stat_pdu) + 2 * sizeof(sscop_seq))
687 KB_ALLOCPKT(m, STAT_INIT_SIZE, KB_F_NOWAIT, KB_T_HEADER);
692 * Setup buffer controls
694 KB_HEADSET(m, sop->so_headout < (KB_BFRLEN(m) - STAT_INIT_SIZE) ?
695 sop->so_headout : 0);
699 #undef STAT_INIT_SIZE
704 * STAT PDU Construction - Add List Element
707 * elem sequence number to add to list
708 * m pointer to current buffer
711 * addr pointer to current buffer (updated)
712 * 0 buffer allocation failure
716 sscop_stat_add(sscop_seq elem, KBuffer *m)
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);
746 KB_DATAEND(m, sp, sscop_seq *);
748 KB_LEN(m) += sizeof (elem);
754 * STAT PDU Construction - Add Trailer and Send
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
763 * 0 STAT successfully sent
764 * else unable to send STAT or truncated STAT was sent - buffer freed
768 sscop_stat_end(struct sscop *sop, sscop_seq nps, KBuffer *head, KBuffer *m)
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);
786 * Out of buffers - truncate elements and send
787 * what we can, but tell caller that we can't
788 * send any more segments.
792 KB_LEN(m) -= sizeof(sscop_seq);
793 space += sizeof(sscop_seq);
794 } while (space < sizeof(struct stat_pdu));
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);
823 * We lie about the STACK_CALL failing...
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.
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
849 * 0 reqeusted PDU not in receive queue
850 * 1 requested PDU located in receive queue
854 sscop_recv_locate(struct sscop *sop, sscop_seq seq, struct pdu_hdr **currp)
859 * Search queue until we know the answer
863 * If we're at the end of the queue, the PDU isn't there
869 * Get the current PDU sequence number
871 cs = (*currp)->ph_ns;
874 * See if we're at the requested PDU
880 * If we're past the requested seq number,
881 * the PDU isn't there
883 if (SEQ_LT(seq, cs, sop->so_rcvnext))
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.
900 * sop pointer to sscop connection control block
901 * nps received poll sequence number (POLL.N(PS))
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;
914 sscop_seq vrh = sop->so_rcvhigh;
915 sscop_seq vrr = sop->so_rcvnext;
919 * Initialize for start of STAT PDU
921 head = sscop_stat_init(sop);
927 * Start with first PDU not yet received
932 * Keep looping until we get to last sent PDU
937 * Find next missing PDU
939 while (SEQ_LT(i, vrh, vrr) && sscop_recv_locate(sop, i, &rq)) {
944 * Add odd (start of missing gap) STAT element
946 n = sscop_stat_add(i, curr);
954 * Have we reached the last sent PDU sequence number??
958 * Yes, then we're done, send STAT
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)) {
975 * Start a new segment
977 head = sscop_stat_init(sop);
983 * Restart missing gap
985 curr = sscop_stat_add(i, curr);
994 * Now find the end of the missing gap
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);
1013 * Finally, send the STAT PDU (or last STAT segment)
1015 if (sscop_stat_end(sop, nps, head, curr)) {
1023 * Send a truncated STAT PDU
1025 sscop_stat_end(sop, nps, head, curr);
1032 * Build and send USTAT PDU
1034 * A USTAT PDU will be constructed and passed down the protocol stack.
1037 * sop pointer to sscop connection control block
1038 * ns sequence number for second list element
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)
1049 struct ustat_pdu *up;
1054 * Get buffer for PDU
1056 KB_ALLOCPKT(m, sizeof(struct ustat_pdu), KB_F_NOWAIT, KB_T_HEADER);
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);
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));
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);
1091 * Build and send UD PDU
1093 * A UD PDU will be constructed and passed down the protocol stack.
1096 * sop pointer to sscop connection control block
1097 * m pointer to user data buffer chain
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)
1109 int pad, trlen, space;
1113 * Count data and get to last buffer in chain
1115 for (ml = m; ; ml = KB_NEXT(ml)) {
1117 if (KB_NEXT(ml) == NULL)
1122 * Verify data length
1124 if (len > sop->so_parm.sp_maxinfo) {
1126 sscop_abort(sop, "sscop: maximum unitdata size exceeded\n");
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);
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 *);
1161 *cp++ = (pad << PT_PAD_SHIFT) | PT_UD;
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);
1180 * Print an SSCOP PDU
1183 * sop pointer to sscop connection control block
1184 * m pointer to pdu buffer chain
1185 * msg pointer to message string
1192 sscop_pdu_print(struct sscop *sop, KBuffer *m, char *msg)
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);