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.2 2003/06/17 04:28:49 dillon Exp $
31 * ATM Forum UNI Support
32 * ---------------------
34 * SSCOP - PDU subroutines
38 #include <netatm/kern_include.h>
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>
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,
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(sop, source)
84 KB_ALLOCPKT(m, sizeof(struct bgn_pdu), KB_F_NOWAIT, KB_T_HEADER);
89 * Setup buffer controls
91 KB_HEADSET(m, MIN(sop->so_headout,
92 KB_BFRLEN(m) - sizeof(struct bgn_pdu)));
93 KB_LEN(m) = sizeof(struct bgn_pdu);
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;
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;
109 * Send PDU towards peer
111 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
112 sop->so_connvc, (int)m, 0, err);
122 * Build and send BGAK PDU
124 * A BGAK PDU will be constructed and passed down the protocol stack.
125 * The SSCOP-UU/N(UU) field is not supported.
128 * sop pointer to sscop connection control block
131 * 0 PDU successfully built and passed down the stack
132 * else unable to build or send pdu
147 KB_ALLOCPKT(m, sizeof(struct bgak_pdu), KB_F_NOWAIT, KB_T_HEADER);
152 * Setup buffer controls
154 KB_HEADSET(m, MIN(sop->so_headout,
155 KB_BFRLEN(m) - sizeof(struct bgak_pdu)));
156 KB_LEN(m) = sizeof(struct bgak_pdu);
161 KB_DATASTART(m, bp, struct bgak_pdu *);
164 htonl((PT_BGAK << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax));
167 * Send PDU towards peer
169 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
170 sop->so_connvc, (int)m, 0, err);
180 * Build and send BGREJ PDU
182 * A BGREJ PDU will be constructed and passed down the protocol stack.
183 * The SSCOP-UU/N(UU) field is not supported.
186 * sop pointer to sscop connection control block
189 * 0 PDU successfully built and passed down the stack
190 * else unable to build or send pdu
194 sscop_send_bgrej(sop)
198 struct bgrej_pdu *bp;
205 KB_ALLOCPKT(m, sizeof(struct bgrej_pdu), KB_F_NOWAIT, KB_T_HEADER);
210 * Setup buffer controls
212 KB_HEADSET(m, MIN(sop->so_headout,
213 KB_BFRLEN(m) - sizeof(struct bgrej_pdu)));
214 KB_LEN(m) = sizeof(struct bgrej_pdu);
219 KB_DATASTART(m, bp, struct bgrej_pdu *);
221 *(u_int *)&bp->bgrej_type = htonl((PT_BGREJ << PT_TYPE_SHIFT) | 0);
224 * Send PDU towards peer
226 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
227 sop->so_connvc, (int)m, 0, err);
237 * Build and send END PDU
239 * An END PDU will be constructed and passed down the protocol stack.
240 * The SSCOP-UU/N(UU) field is not supported.
243 * sop pointer to sscop connection control block
244 * source originator of END PDU
247 * 0 PDU successfully built and passed down the stack
248 * else unable to build or send pdu
252 sscop_send_end(sop, source)
264 KB_ALLOCPKT(m, sizeof(struct end_pdu), KB_F_NOWAIT, KB_T_HEADER);
269 * Setup buffer controls
271 KB_HEADSET(m, MIN(sop->so_headout,
272 KB_BFRLEN(m) - sizeof(struct end_pdu)));
273 KB_LEN(m) = sizeof(struct end_pdu);
278 KB_DATASTART(m, ep, struct end_pdu *);
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;
291 * Send PDU towards peer
293 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
294 sop->so_connvc, (int)m, 0, err);
304 * Build and send ENDAK PDU
306 * An ENDAK PDU will be constructed and passed down the protocol stack.
309 * sop pointer to sscop connection control block
312 * 0 PDU successfully built and passed down the stack
313 * else unable to build or send pdu
317 sscop_send_endak(sop)
321 struct endak_q2110_pdu *e2p;
322 struct endak_qsaal_pdu *esp;
329 if (sop->so_vers == SSCOP_VERS_QSAAL)
330 size = sizeof(struct endak_qsaal_pdu);
332 size = sizeof(struct endak_q2110_pdu);
337 KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER);
342 * Setup buffer controls
344 KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size));
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);
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);
362 * Send PDU towards peer
364 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
365 sop->so_connvc, (int)m, 0, err);
375 * Build and send RS PDU
377 * A RS PDU will be constructed and passed down the protocol stack.
378 * The SSCOP-UU/N(UU) field is not supported.
381 * sop pointer to sscop connection control block
384 * 0 PDU successfully built and passed down the stack
385 * else unable to build or send pdu
400 KB_ALLOCPKT(m, sizeof(struct rs_pdu), KB_F_NOWAIT, KB_T_HEADER);
405 * Setup buffer controls
407 KB_HEADSET(m, MIN(sop->so_headout,
408 KB_BFRLEN(m) - sizeof(struct rs_pdu)));
409 KB_LEN(m) = sizeof(struct rs_pdu);
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));
421 rp->rs_nmr = htonl((PT_RS << PT_TYPE_SHIFT) | 0);
425 * Send PDU towards peer
427 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
428 sop->so_connvc, (int)m, 0, err);
438 * Build and send RSAK PDU
440 * An RSAK PDU will be constructed and passed down the protocol stack.
443 * sop pointer to sscop connection control block
446 * 0 PDU successfully built and passed down the stack
447 * else unable to build or send pdu
455 struct rsak_q2110_pdu *r2p;
456 struct rsak_qsaal_pdu *rsp;
463 if (sop->so_vers == SSCOP_VERS_QSAAL)
464 size = sizeof(struct rsak_qsaal_pdu);
466 size = sizeof(struct rsak_q2110_pdu);
471 KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER);
476 * Setup buffer controls
478 KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size));
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);
489 KB_DATASTART(m, r2p, struct rsak_q2110_pdu *);
491 r2p->rsak_nmr = htonl((PT_RSAK << PT_TYPE_SHIFT) |
492 SEQ_VAL(sop->so_rcvmax));
496 * Send PDU towards peer
498 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
499 sop->so_connvc, (int)m, 0, err);
509 * Build and send ER PDU
511 * An ER PDU will be constructed and passed down the protocol stack.
514 * sop pointer to sscop connection control block
517 * 0 PDU successfully built and passed down the stack
518 * else unable to build or send pdu
533 KB_ALLOCPKT(m, sizeof(struct er_pdu), KB_F_NOWAIT, KB_T_HEADER);
538 * Setup buffer controls
540 KB_HEADSET(m, MIN(sop->so_headout,
541 KB_BFRLEN(m) - sizeof(struct er_pdu)));
542 KB_LEN(m) = sizeof(struct er_pdu);
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));
553 * Send PDU towards peer
555 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
556 sop->so_connvc, (int)m, 0, err);
566 * Build and send ERAK PDU
568 * An ERAK PDU will be constructed and passed down the protocol stack.
571 * sop pointer to sscop connection control block
574 * 0 PDU successfully built and passed down the stack
575 * else unable to build or send pdu
590 KB_ALLOCPKT(m, sizeof(struct erak_pdu), KB_F_NOWAIT, KB_T_HEADER);
595 * Setup buffer controls
597 KB_HEADSET(m, MIN(sop->so_headout,
598 KB_BFRLEN(m) - sizeof(struct erak_pdu)));
599 KB_LEN(m) = sizeof(struct erak_pdu);
604 KB_DATASTART(m, ep, struct erak_pdu *);
606 ep->erak_nmr = htonl((PT_ERAK << PT_TYPE_SHIFT) |
607 SEQ_VAL(sop->so_rcvmax));
610 * Send PDU towards peer
612 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
613 sop->so_connvc, (int)m, 0, err);
623 * Build and send POLL PDU
625 * A POLL PDU will be constructed and passed down the protocol stack.
628 * sop pointer to sscop connection control block
631 * 0 PDU successfully built and passed down the stack
632 * else unable to build or send pdu
647 KB_ALLOCPKT(m, sizeof(struct poll_pdu), KB_F_NOWAIT, KB_T_HEADER);
652 * Setup buffer controls
654 KB_HEADSET(m, MIN(sop->so_headout,
655 KB_BFRLEN(m) - sizeof(struct poll_pdu)));
656 KB_LEN(m) = sizeof(struct poll_pdu);
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));
666 * Send PDU towards peer
668 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
669 sop->so_connvc, (int)m, 0, err);
679 * STAT PDU Construction - Initialize for new PDU
682 * sop pointer to sscop connection control block
685 * addr pointer to initialized buffer
686 * 0 unable to allocate buffer
695 #define STAT_INIT_SIZE (sizeof(struct stat_pdu) + 2 * sizeof(sscop_seq))
700 KB_ALLOCPKT(m, STAT_INIT_SIZE, KB_F_NOWAIT, KB_T_HEADER);
705 * Setup buffer controls
707 KB_HEADSET(m, sop->so_headout < (KB_BFRLEN(m) - STAT_INIT_SIZE) ?
708 sop->so_headout : 0);
712 #undef STAT_INIT_SIZE
717 * STAT PDU Construction - Add List Element
720 * elem sequence number to add to list
721 * m pointer to current buffer
724 * addr pointer to current buffer (updated)
725 * 0 buffer allocation failure
729 sscop_stat_add(elem, m)
738 * See if new element will fit in current buffer
740 KB_TAILROOM(m, space);
741 if (space < sizeof(elem)) {
744 * Nope, so get another buffer
746 KB_ALLOC(n, sizeof(elem), KB_F_NOWAIT, KB_T_DATA);
761 KB_DATAEND(m, sp, sscop_seq *);
763 KB_LEN(m) += sizeof (elem);
769 * STAT PDU Construction - Add Trailer and Send
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
778 * 0 STAT successfully sent
779 * else unable to send STAT or truncated STAT was sent - buffer freed
783 sscop_stat_end(sop, nps, head, m)
791 int err, space, trunc = 0;
794 * See if PDU trailer will fit in current buffer
796 KB_TAILROOM(m, space);
797 if (space < sizeof(struct stat_pdu)) {
800 * Doesn't fit, so get another buffer
802 KB_ALLOC(n, sizeof(struct stat_pdu), KB_F_NOWAIT, KB_T_DATA);
805 * Out of buffers - truncate elements and send
806 * what we can, but tell caller that we can't
807 * send any more segments.
811 KB_LEN(m) -= sizeof(sscop_seq);
812 space += sizeof(sscop_seq);
813 } while (space < sizeof(struct stat_pdu));
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);
835 * Finally, send the STAT
837 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
838 sop->so_connvc, (int)head, 0, err);
842 * We lie about the STACK_CALL failing...
855 * Check for PDU in Receive Queue
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.
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
868 * 0 reqeusted PDU not in receive queue
869 * 1 requested PDU located in receive queue
873 sscop_recv_locate(sop, seq, currp)
876 struct pdu_hdr **currp;
881 * Search queue until we know the answer
885 * If we're at the end of the queue, the PDU isn't there
891 * Get the current PDU sequence number
893 cs = (*currp)->ph_ns;
896 * See if we're at the requested PDU
902 * If we're past the requested seq number,
903 * the PDU isn't there
905 if (SEQ_LT(seq, cs, sop->so_rcvnext))
909 * Go to next PDU and keep looking
911 *currp = (*currp)->ph_recv_lk;
917 * Build and send STAT PDU
919 * A STAT PDU will be constructed and passed down the protocol stack.
922 * sop pointer to sscop connection control block
923 * nps received poll sequence number (POLL.N(PS))
926 * 0 PDU successfully built and passed down the stack
927 * else unable to build or send complete pdu
931 sscop_send_stat(sop, nps)
935 KBuffer *head, *curr, *n;
936 struct pdu_hdr *rq = sop->so_recv_hd;
938 sscop_seq vrh = sop->so_rcvhigh;
939 sscop_seq vrr = sop->so_rcvnext;
943 * Initialize for start of STAT PDU
945 head = sscop_stat_init(sop);
951 * Start with first PDU not yet received
956 * Keep looping until we get to last sent PDU
961 * Find next missing PDU
963 while (SEQ_LT(i, vrh, vrr) && sscop_recv_locate(sop, i, &rq)) {
968 * Add odd (start of missing gap) STAT element
970 n = sscop_stat_add(i, curr);
978 * Have we reached the last sent PDU sequence number??
982 * Yes, then we're done, send STAT
988 * Have we reached the max STAT size yet??
990 if (len >= PDU_MAX_ELEM) {
992 * Yes, send this STAT segment
994 if (sscop_stat_end(sop, nps, head, curr)) {
999 * Start a new segment
1001 head = sscop_stat_init(sop);
1007 * Restart missing gap
1009 curr = sscop_stat_add(i, curr);
1018 * Now find the end of the missing gap
1022 } while (SEQ_LT(i, vrh, vrr) &&
1023 (sscop_recv_locate(sop, i, &rq) == 0));
1026 * Add even (start of received gap) STAT element
1028 n = sscop_stat_add(i, curr);
1037 * Finally, send the STAT PDU (or last STAT segment)
1039 if (sscop_stat_end(sop, nps, head, curr)) {
1047 * Send a truncated STAT PDU
1049 sscop_stat_end(sop, nps, head, curr);
1056 * Build and send USTAT PDU
1058 * A USTAT PDU will be constructed and passed down the protocol stack.
1061 * sop pointer to sscop connection control block
1062 * ns sequence number for second list element
1065 * 0 PDU successfully built and passed down the stack
1066 * else unable to build or send pdu
1070 sscop_send_ustat(sop, ns)
1075 struct ustat_pdu *up;
1080 * Get buffer for PDU
1082 KB_ALLOCPKT(m, sizeof(struct ustat_pdu), KB_F_NOWAIT, KB_T_HEADER);
1087 * Setup buffer controls
1089 KB_HEADSET(m, MIN(sop->so_headout,
1090 KB_BFRLEN(m) - sizeof(struct ustat_pdu)));
1091 KB_LEN(m) = sizeof(struct ustat_pdu);
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));
1101 htonl((PT_USTAT << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvnext));
1104 * Send PDU towards peer
1106 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
1107 sop->so_connvc, (int)m, 0, err);
1117 * Build and send UD PDU
1119 * A UD PDU will be constructed and passed down the protocol stack.
1122 * sop pointer to sscop connection control block
1123 * m pointer to user data buffer chain
1126 * 0 PDU successfully built and passed down the stack
1127 * else unable to build or send pdu (buffer released)
1131 sscop_send_ud(sop, m)
1137 int pad, trlen, space;
1141 * Count data and get to last buffer in chain
1143 for (ml = m; ; ml = KB_NEXT(ml)) {
1145 if (KB_NEXT(ml) == NULL)
1150 * Verify data length
1152 if (len > sop->so_parm.sp_maxinfo) {
1154 sscop_abort(sop, "sscop: maximum unitdata size exceeded\n");
1159 * Figure out how much padding we'll need
1161 pad = ((len + (PDU_PAD_ALIGN - 1)) & ~(PDU_PAD_ALIGN - 1)) - len;
1162 trlen = pad + sizeof(struct ud_pdu);
1165 * Get space for PDU trailer and padding
1167 KB_TAILROOM(ml, space);
1168 if (space < trlen) {
1170 * Allocate & link buffer for pad and trailer
1172 KB_ALLOC(n, trlen, KB_F_NOWAIT, KB_T_HEADER);
1182 * Build the PDU trailer
1184 * Since we can't be sure of alignment in the buffers, we
1185 * have to move this a byte at a time.
1187 KB_DATAEND(ml, cp, u_char *);
1189 *cp++ = (pad << PT_PAD_SHIFT) | PT_UD;
1191 KB_LEN(ml) += trlen;
1194 * Now pass PDU down the stack
1196 STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
1197 sop->so_connvc, (int)m, 0, err);
1208 * Print an SSCOP PDU
1211 * sop pointer to sscop connection control block
1212 * m pointer to pdu buffer chain
1213 * msg pointer to message string
1220 sscop_pdu_print(sop, m, msg)
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);