Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / netproto / atm / uni / sscop_subr.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_subr.c,v 1.6 2000/01/17 20:49:52 mks Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/uni/sscop_subr.c,v 1.2 2003/06/17 04:28:49 dillon Exp $
28  */
29
30 /*
31  * ATM Forum UNI Support
32  * ---------------------
33  *
34  * SSCOP - Subroutines
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include <netatm/uni/sscop.h>
41 #include <netatm/uni/sscop_misc.h>
42 #include <netatm/uni/sscop_pdu.h>
43 #include <netatm/uni/sscop_var.h>
44
45 /*
46  * Local functions
47  */
48 static int sscop_proc_xmit __P((struct sscop *));
49
50
51 /*
52  * Get Next Element from STAT PDU
53  *
54  * Arguments:
55  *      m       pointer to current buffer in STAT PDU
56  *      pelem   pointer to location to store element value
57  *
58  * Returns:
59  *      addr    pointer to updated current buffer in STAT PDU
60  *
61  */
62 KBuffer *
63 sscop_stat_getelem(m, pelem)
64         KBuffer         *m;
65         sscop_seq       *pelem;
66 {
67         caddr_t         cp;
68
69         /*
70          * Get to start of element
71          *
72          * Note that we always ensure that the current buffer has
73          * at least one byte of the next element.
74          */
75         KB_DATASTART(m, cp, caddr_t);
76
77         /*
78          * See how much of element is in this buffer
79          */
80         if (KB_LEN(m) >= sizeof(sscop_seq)) {
81                 /*
82                  * Get element from this buffer
83                  */
84                 if ((int)cp & (sizeof(sscop_seq) - 1))
85                         KM_COPY(cp, (caddr_t)pelem, sizeof(sscop_seq));
86                 else
87                         *pelem = *(sscop_seq *)cp;
88
89                 /*
90                  * Update buffer controls
91                  */
92                 KB_HEADADJ(m, -sizeof(sscop_seq));
93         } else {
94                 /*
95                  * Get element split between two buffers
96                  */
97                 int     i, j;
98
99                 /*
100                  * Copy what's in this buffer
101                  */
102                 i = KB_LEN(m);
103                 KM_COPY(cp, (caddr_t)pelem, i);
104                 KB_LEN(m) = 0;
105
106                 /*
107                  * Now get to next buffer
108                  */
109                 while (m && (KB_LEN(m) == 0))
110                         m = KB_NEXT(m);
111
112                 /*
113                  * And copy remainder of element
114                  */
115                 j = sizeof(sscop_seq) - i;
116                 KB_DATASTART(m, cp, caddr_t);
117                 KM_COPY(cp, (caddr_t)pelem + i, j);
118
119                 /*
120                  * Update buffer controls
121                  */
122                 KB_HEADADJ(m, -j);
123         }
124
125         /*
126          * Put element (sequence number) into host order
127          */
128         NTOHL(*pelem);
129
130         /*
131          * Get pointers set for next call
132          */
133         while (m && (KB_LEN(m) == 0))
134                 m = KB_NEXT(m);
135
136         return (m);
137 }
138
139
140 /*
141  * Locate SD PDU on Pending Ack Queue
142  *
143  * Arguments:
144  *      sop     pointer to sscop connection block
145  *      seq     sequence number of PDU to locate
146  *
147  * Returns:
148  *      addr    pointer to located PDU header
149  *      0       SD PDU sequence number not found
150  *
151  */
152 struct pdu_hdr *
153 sscop_pack_locate(sop, seq)
154         struct sscop    *sop;
155         sscop_seq       seq;
156 {
157         struct pdu_hdr  *php;
158
159         /*
160          * Loop thru queue until we either find the PDU or the queue's
161          * sequence numbers are greater than the PDU's sequence number,
162          * indicating that the PDU is not on the queue.
163          */
164         for (php = sop->so_pack_hd; php; php = php->ph_pack_lk) {
165                 if (php->ph_ns == seq)
166                         break;
167
168                 if (SEQ_GT(php->ph_ns, seq, sop->so_ack)) {
169                         php = NULL;
170                         break;
171                 }
172         }
173
174         return (php);
175 }
176
177
178 /*
179  * Free Acknowledged SD PDU
180  *
181  * Arguments:
182  *      sop     pointer to sscop connection block
183  *      seq     sequence number of PDU to free
184  *
185  * Returns:
186  *      none
187  *
188  */
189 void
190 sscop_pack_free(sop, seq)
191         struct sscop    *sop;
192         sscop_seq       seq;
193 {
194         struct pdu_hdr  *php, *prev;
195
196         /*
197          * Unlink PDU from pending ack queue
198          *
199          * First, check for an empty queue
200          */
201         php = sop->so_pack_hd;
202         if (php == NULL)
203                 return;
204
205         /*
206          * Now check for PDU at head of queue
207          */
208         if (php->ph_ns == seq) {
209                 if ((sop->so_pack_hd = php->ph_pack_lk) == NULL)
210                         sop->so_pack_tl = NULL;
211                 goto found;
212         }
213
214         /*
215          * Otherwise, loop thru queue until we either find the PDU or
216          * the queue's sequence numbers are greater than the PDU's
217          * sequence number, indicating that the PDU is not on the queue.
218          */
219         prev = php;
220         php = php->ph_pack_lk;
221         while (php) {
222                 if (php->ph_ns == seq) {
223                         if ((prev->ph_pack_lk = php->ph_pack_lk) == NULL)
224                                 sop->so_pack_tl = prev;
225                         goto found;
226                 }
227
228                 if (SEQ_GT(php->ph_ns, seq, sop->so_ack))
229                         return;
230
231                 prev = php;
232                 php = php->ph_pack_lk;
233         }
234
235         return;
236
237 found:
238         /*
239          * We've got the ack'ed PDU - unlink it from retransmit queue
240          */
241         sscop_rexmit_unlink(sop, php);
242
243         /*
244          * Free PDU buffers
245          */
246         KB_FREEALL(php->ph_buf);
247
248         return;
249 }
250
251
252 /*
253  * Insert SD PDU into Retransmit Queue
254  *
255  * Arguments:
256  *      sop     pointer to sscop connection block
257  *      php     pointer to SD PDU header
258  *
259  * Returns:
260  *      none
261  *
262  */
263 void
264 sscop_rexmit_insert(sop, php)
265         struct sscop    *sop;
266         struct pdu_hdr  *php;
267 {
268         struct pdu_hdr  *curr, *next;
269         sscop_seq       seq = php->ph_ns;
270
271         /*
272          * Check for an empty queue
273          */
274         if ((curr = sop->so_rexmit_hd) == NULL) {
275                 php->ph_rexmit_lk = NULL;
276                 sop->so_rexmit_hd = php;
277                 sop->so_rexmit_tl = php;
278                 return;
279         }
280
281         /*
282          * Now see if PDU belongs at head of queue
283          */
284         if (SEQ_LT(seq, curr->ph_ns, sop->so_ack)) {
285                 php->ph_rexmit_lk = curr;
286                 sop->so_rexmit_hd = php;
287                 return;
288         }
289
290         /*
291          * Otherwise, loop thru the queue until we find the
292          * proper insertion point for the PDU
293          */
294         while ((next = curr->ph_rexmit_lk) != NULL) {
295                 if (SEQ_LT(seq, next->ph_ns, sop->so_ack)) {
296                         php->ph_rexmit_lk = next;
297                         curr->ph_rexmit_lk = php;
298                         return;
299                 }
300                 curr = next;
301         }
302
303         /*
304          * Insert PDU at end of queue
305          */
306         php->ph_rexmit_lk = NULL;
307         curr->ph_rexmit_lk = php;
308         sop->so_rexmit_tl = php;
309
310         return;
311 }
312
313
314 /*
315  * Unlink SD PDU from Retransmit Queue
316  *
317  * Arguments:
318  *      sop     pointer to sscop connection block
319  *      php     pointer to PDU header to unlink
320  *
321  * Returns:
322  *      none
323  *
324  */
325 void
326 sscop_rexmit_unlink(sop, php)
327         struct sscop    *sop;
328         struct pdu_hdr  *php;
329 {
330         struct pdu_hdr  *curr;
331
332         /*
333          * See if PDU is on retransmit queue
334          */
335         if ((php->ph_rexmit_lk == NULL) && (sop->so_rexmit_tl != php))
336                 return;
337
338         /*
339          * It's here somewhere, so first check for the PDU at the
340          * head of the queue
341          */
342         if (php == sop->so_rexmit_hd) {
343                 if ((sop->so_rexmit_hd = php->ph_rexmit_lk) == NULL)
344                         sop->so_rexmit_tl = NULL;
345                 php->ph_rexmit_lk = NULL;
346                 return;
347         }
348
349         /*
350          * Otherwise, loop thru the queue until we find the PDU
351          */
352         for (curr = sop->so_rexmit_hd; curr; curr = curr->ph_rexmit_lk) {
353                 if (curr->ph_rexmit_lk == php)
354                         break;
355         }
356         if (curr) {
357                 if ((curr->ph_rexmit_lk = php->ph_rexmit_lk) == NULL)
358                         sop->so_rexmit_tl = curr;
359         } else {
360                 log(LOG_ERR,
361                         "sscop_rexmit_unlink: Not found - sop=%p, php=%p\n",
362                         sop, php);
363 #ifdef DIAGNOSTIC
364                 panic("sscop_rexmit_unlink: Not found");
365 #endif
366         }
367         php->ph_rexmit_lk = NULL;
368
369         return;
370 }
371
372
373 /*
374  * Drain Transmission Queues
375  *
376  * Arguments:
377  *      sop     pointer to sscop connection block
378  *
379  * Returns:
380  *      none
381  *
382  */
383 void
384 sscop_xmit_drain(sop)
385         struct sscop    *sop;
386 {
387         KBuffer         *m;
388         struct pdu_hdr  *php;
389
390         /*
391          * Free transmission queue buffers
392          */
393         while ((m = sop->so_xmit_hd) != NULL) {
394                 sop->so_xmit_hd = KB_QNEXT(m);
395                 KB_FREEALL(m);
396         }
397         sop->so_xmit_tl = NULL;
398
399         /*
400          * Free retransmission queue
401          *
402          * All retranmission buffers are also on the pending ack
403          * queue (but not the converse), so we just clear the queue
404          * pointers here and do all the real work below.
405          */
406         sop->so_rexmit_hd = NULL;
407         sop->so_rexmit_tl = NULL;
408
409         /*
410          * Free pending ack queue buffers
411          */
412         while ((php = sop->so_pack_hd) != NULL) {
413                 sop->so_pack_hd = php->ph_pack_lk;
414                 KB_FREEALL(php->ph_buf);
415         }
416         sop->so_pack_tl = NULL;
417
418         /*
419          * Clear service required flag
420          */
421         sop->so_flags &= ~SOF_XMITSRVC;
422
423         return;
424 }
425
426
427 /*
428  * Insert SD PDU into Receive Queue
429  *
430  * Arguments:
431  *      sop     pointer to sscop connection block
432  *      php     pointer to SD PDU header
433  *
434  * Returns:
435  *      0       PDU successfully inserted into queue
436  *      1       duplicate sequence number PDU on queue, PDU not inserted
437  *
438  */
439 int
440 sscop_recv_insert(sop, php)
441         struct sscop    *sop;
442         struct pdu_hdr  *php;
443 {
444         struct pdu_hdr  *curr, *next;
445         sscop_seq       seq = php->ph_ns;
446
447         /*
448          * Check for an empty queue
449          */
450         if ((curr = sop->so_recv_hd) == NULL) {
451                 php->ph_recv_lk = NULL;
452                 sop->so_recv_hd = php;
453                 sop->so_recv_tl = php;
454                 return (0);
455         }
456
457         /*
458          * Now see if PDU belongs at head of queue
459          */
460         if (SEQ_LT(seq, curr->ph_ns, sop->so_rcvnext)) {
461                 php->ph_recv_lk = curr;
462                 sop->so_recv_hd = php;
463                 return (0);
464         }
465
466         /*
467          * Otherwise, loop thru the queue until we find the
468          * proper insertion point for the PDU.  We also check
469          * to make sure there isn't a PDU already on the queue
470          * with a matching sequence number.
471          */
472         while ((next = curr->ph_recv_lk) != NULL) {
473                 if (SEQ_LT(seq, next->ph_ns, sop->so_rcvnext)) {
474                         if (seq == curr->ph_ns)
475                                 return (1);
476                         php->ph_recv_lk = next;
477                         curr->ph_recv_lk = php;
478                         return (0);
479                 }
480                 curr = next;
481         }
482
483         /*
484          * Insert PDU at end of queue
485          */
486         if (seq == curr->ph_ns)
487                 return (1);
488         php->ph_recv_lk = NULL;
489         curr->ph_recv_lk = php;
490         sop->so_recv_tl = php;
491
492         return (0);
493 }
494
495
496 /*
497  * Drain Receiver Queues
498  *
499  * Arguments:
500  *      sop     pointer to sscop connection block
501  *
502  * Returns:
503  *      none
504  *
505  */
506 void
507 sscop_rcvr_drain(sop)
508         struct sscop    *sop;
509 {
510         struct pdu_hdr  *php;
511
512         /*
513          * Free receive queue buffers
514          */
515         while ((php = sop->so_recv_hd) != NULL) {
516                 sop->so_recv_hd = php->ph_recv_lk;
517                 KB_FREEALL(php->ph_buf);
518         }
519         sop->so_recv_tl = NULL;
520
521         return;
522 }
523
524
525 /*
526  * Service connection's transmit queues
527  *
528  * Arguments:
529  *      sop     pointer to sscop connection block
530  *
531  * Returns:
532  *      none
533  *
534  */
535 void
536 sscop_service_xmit(sop)
537         struct sscop    *sop;
538 {
539         KBuffer         *m, *n;
540         struct pdu_hdr  *php;
541         int             err = 0, pollsent = 0;
542
543         /*
544          * Initially assume we need service
545          */
546         sop->so_flags |= SOF_XMITSRVC;
547
548         /*
549          * Loop until done with queues
550          *
551          * (Congestion control will be added later)
552          */
553         while (1) {
554                 if ((php = sop->so_rexmit_hd) != NULL) {
555
556                         /*
557                          * Send SD PDU from retransmit queue
558                          *
559                          * First, get a copy of the PDU to send
560                          */
561                         m = php->ph_buf;
562                         if (KB_LEN(m) == 0)
563                                 m = KB_NEXT(m);
564                         KB_COPY(m, 0, KB_COPYALL, n, KB_F_NOWAIT);
565                         if (n == NULL) {
566                                 err = 1;
567                                 break;
568                         }
569
570                         /*
571                          * Now pass it down the stack
572                          */
573                         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower,
574                                 sop->so_tokl, sop->so_connvc, (int)n, 0, err);
575                         if (err) {
576                                 KB_FREEALL(n);
577                                 break;
578                         }
579
580                         /*
581                          * PDU is on its way, so remove it from
582                          * the retransmit queue
583                          */
584                         if (sop->so_rexmit_tl == php) {
585                                 sop->so_rexmit_hd = NULL;
586                                 sop->so_rexmit_tl = NULL;
587                         } else {
588                                 sop->so_rexmit_hd = php->ph_rexmit_lk;
589                         }
590                         php->ph_rexmit_lk = NULL;
591
592                         /*
593                          * Update PDU's poll sequence
594                          */
595                         php->ph_nps = sop->so_pollsend;
596
597                 } else if (sop->so_xmit_hd) {
598
599                         /*
600                          * Newly arrived data waiting to be sent.
601                          * See if transmit window allows us to send it.
602                          */
603                         if (SEQ_LT(sop->so_send, sop->so_sendmax, sop->so_ack)){
604                                 /*
605                                  * OK, send SD PDU from transmission queue
606                                  */
607                                 err = sscop_proc_xmit(sop);
608                                 if (err)
609                                         break;
610                         } else {
611                                 /*
612                                  * Can't send now, so leave idle phase.
613                                  */
614                                 if (sop->so_timer[SSCOP_T_IDLE] != 0) {
615                                         sop->so_timer[SSCOP_T_IDLE] = 0;
616                                         sop->so_timer[SSCOP_T_NORESP] =
617                                                 sop->so_parm.sp_timeresp;
618                                         err = 1;
619                                 }
620                                 break;
621                         }
622
623                 } else {
624
625                         /*
626                          * We're finished, so clear service required flag
627                          */
628                         sop->so_flags &= ~SOF_XMITSRVC;
629                         break;
630                 }
631
632                 /*
633                  * We've sent another SD PDU
634                  */
635                 sop->so_polldata++;
636
637                 /*
638                  * Transition into active (polling) phase
639                  */
640                 if (sop->so_timer[SSCOP_T_POLL] != 0) {
641                         if (sop->so_flags & SOF_KEEPALIVE) {
642                                 /*
643                                  * Leaving transient phase
644                                  */
645                                 sop->so_flags &= ~SOF_KEEPALIVE;
646                                 sop->so_timer[SSCOP_T_POLL] =
647                                                 sop->so_parm.sp_timepoll;
648                         }
649                 } else {
650                         /*
651                          * Leaving idle phase
652                          */
653                         sop->so_timer[SSCOP_T_IDLE] = 0;
654                         sop->so_timer[SSCOP_T_NORESP] =
655                                                 sop->so_parm.sp_timeresp;
656                         sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
657                 }
658
659                 /*
660                  * Let's see if we need to send a POLL yet
661                  */
662                 if (sop->so_polldata < sop->so_parm.sp_maxpd)
663                         continue;
664
665                 /*
666                  * Yup, send another poll out
667                  */
668                 SEQ_INCR(sop->so_pollsend, 1);
669                 (void) sscop_send_poll(sop);
670                 pollsent++;
671
672                 /*
673                  * Reset data counter for this poll cycle
674                  */
675                 sop->so_polldata = 0;
676
677                 /*
678                  * Restart polling timer in active phase
679                  */
680                 sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
681         }
682
683         /*
684          * If we need/want to send a poll, but haven't sent any yet
685          * on this servicing, send one now
686          */
687         if (err && (pollsent == 0)) {
688                 /*
689                  * Send poll
690                  */
691                 SEQ_INCR(sop->so_pollsend, 1);
692                 (void) sscop_send_poll(sop);
693
694                 /*
695                  * Reset data counter for this poll cycle
696                  */
697                 sop->so_polldata = 0;
698
699                 /*
700                  * Restart polling timer in active phase
701                  */
702                 sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
703                 sop->so_flags &= ~SOF_KEEPALIVE;
704         }
705
706         return;
707 }
708
709
710 /*
711  * Process Transmission Queue PDU
712  *
713  * For the first entry on the transmission queue: add a PDU header and
714  * trailer, send a copy of the PDU down the stack and move the PDU from
715  * the transmission queue to the pending ack queue.
716  *
717  * Arguments:
718  *      sop     pointer to sscop connection block
719  *
720  * Returns:
721  *      0       head of transmission queue successfully processed
722  *      else    processing error, tranmission queue unchanged
723  *
724  */
725 static int
726 sscop_proc_xmit(sop)
727         struct sscop    *sop;
728 {
729         KBuffer         *m, *ml, *n;
730         struct pdu_hdr  *php;
731         sscop_seq       seq;
732         int             len = 0, err;
733         int             pad, trlen, space;
734         u_char          *cp;
735
736         /*
737          * Get first buffer chain on queue
738          */
739         if ((m = sop->so_xmit_hd) == NULL)
740                 return (0);
741
742         /*
743          * Count data and get to last buffer in chain
744          */
745         for (ml = m; ; ml = KB_NEXT(ml)) {
746                 len += KB_LEN(ml);
747                 if (KB_NEXT(ml) == NULL)
748                         break;
749         }
750
751         /*
752          * Verify data length
753          */
754         if (len > sop->so_parm.sp_maxinfo) {
755                 sscop_abort(sop, "sscop: maximum data size exceeded\n");
756                 return (1);
757         }
758
759         /*
760          * Get space for PDU header
761          */
762         KB_HEADROOM(m, space);
763         if (space < sizeof(struct pdu_hdr)) {
764                 /*
765                  * Allocate & link buffer for header
766                  */
767                 KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER);
768                 if (n == NULL)
769                         return (1);
770
771                 KB_LEN(n) = 0;
772                 KB_HEADSET(n, sizeof(struct pdu_hdr));
773                 KB_LINKHEAD(n, m);
774                 KB_QNEXT(n) = KB_QNEXT(m);
775                 KB_QNEXT(m) = NULL;
776                 sop->so_xmit_hd = n;
777                 if (sop->so_xmit_tl == m)
778                         sop->so_xmit_tl = n;
779                 m = n;
780         }
781
782         /*
783          * Figure out how much padding we'll need
784          */
785         pad = ((len + (PDU_PAD_ALIGN - 1)) & ~(PDU_PAD_ALIGN - 1)) - len;
786         trlen = pad + sizeof(struct sd_pdu);
787
788         /*
789          * Now get space for PDU trailer and padding
790          */
791         KB_TAILROOM(ml, space);
792         if (space < trlen) {
793                 /*
794                  * Allocate & link buffer for pad and trailer
795                  */
796                 KB_ALLOC(n, trlen, KB_F_NOWAIT, KB_T_HEADER);
797                 if (n == NULL)
798                         return (1);
799
800                 KB_LEN(n) = 0;
801                 KB_LINK(n, ml);
802                 ml = n;
803         }
804
805         /*
806          * Build the PDU trailer
807          *
808          * Since we can't be sure of alignment in the buffers, we
809          * have to move this a byte at a time and we have to be
810          * careful with host byte order issues.
811          */
812         KB_DATASTART(ml, cp, u_char *);
813         cp += KB_LEN(ml) + pad;
814         *cp++ = (pad << PT_PAD_SHIFT) | PT_SD;
815         seq = sop->so_send;
816         *(cp + 2) = (u_char)(seq & 0xff);
817         seq >>= 8;
818         *(cp + 1) = (u_char)(seq & 0xff);
819         seq >>= 8;
820         *(cp) = (u_char)(seq & 0xff);
821         KB_LEN(ml) += trlen;
822
823         /*
824          * Get a copy of the SD PDU to send
825          */
826         if (KB_LEN(m) == 0)
827                 n = KB_NEXT(m);
828         else
829                 n = m;
830         KB_COPY(n, 0, KB_COPYALL, n, KB_F_NOWAIT);
831         if (n == NULL) {
832                 KB_LEN(ml) -= trlen;
833                 return (1);
834         }
835
836         /*
837          * Now pass copy down the stack
838          */
839         STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl,
840                 sop->so_connvc, (int)n, 0, err);
841         if (err) {
842                 KB_FREEALL(n);
843                 KB_LEN(ml) -= trlen;
844                 return (1);
845         }
846
847         /*
848          * PDU is on its way, so remove buffer from
849          * the transmission queue
850          */
851         if (sop->so_xmit_tl == m) {
852                 sop->so_xmit_hd = NULL;
853                 sop->so_xmit_tl = NULL;
854         } else {
855                 sop->so_xmit_hd = KB_QNEXT(m);
856         }
857         KB_QNEXT(m) = NULL;
858
859         /*
860          * Build PDU header
861          *
862          * We can at least assume/require that the start of
863          * the user data is aligned.  Also note that we don't
864          * include this header in the buffer len/offset fields.
865          */
866         KB_DATASTART(m, php, struct pdu_hdr *);
867         php--;
868         php->ph_ns = sop->so_send;
869         php->ph_nps = sop->so_pollsend;
870         php->ph_buf = m;
871         php->ph_rexmit_lk = NULL;
872         php->ph_pack_lk = NULL;
873
874         /*
875          * Put PDU onto the pending ack queue
876          */
877         if (sop->so_pack_hd == NULL)
878                 sop->so_pack_hd = php;
879         else
880                 sop->so_pack_tl->ph_pack_lk = php;
881         sop->so_pack_tl = php;
882
883         /*
884          * Finally, bump send sequence number
885          */
886         SEQ_INCR(sop->so_send, 1);
887
888         return (0);
889 }
890
891
892 /*
893  * Detect Retransmitted PDUs
894  *
895  * Arguments:
896  *      sop     pointer to sscop connection block
897  *      nsq     connection sequence value (N(SQ)) from received PDU
898  *
899  * Returns:
900  *      0       received PDU was NOT retransmitted
901  *      1       received PDU was retransmitted
902  *
903  */
904 int
905 sscop_is_rexmit(sop, nsq)
906         struct sscop    *sop;
907         u_char          nsq;
908 {
909
910         /*
911          * For Q.SAAL1, N(SQ) doesn't exist
912          */
913         if (sop->so_vers == SSCOP_VERS_QSAAL)
914                 return (0);
915
916         /*
917          * If we've already received the N(SQ) value,
918          * then this PDU has been retransmitted
919          */
920         if (nsq == sop->so_rcvconn)
921                 return (1);
922
923         /*
924          * New PDU, save its N(SQ)
925          */
926         sop->so_rcvconn = nsq;
927
928         return (0);
929 }
930
931
932 /*
933  * Start connection poll timer
934  *
935  * Arguments:
936  *      sop     pointer to sscop connection block
937  *
938  * Returns:
939  *      none
940  *
941  */
942 void
943 sscop_set_poll(sop)
944         struct sscop    *sop;
945 {
946
947         /*
948          * Decide which polling timer value to set
949          */
950         if ((sop->so_xmit_hd != NULL) || SEQ_NEQ(sop->so_send, sop->so_ack)) {
951                 /*
952                  * Data outstanding, poll frequently
953                  */
954                 sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
955                 sop->so_flags &= ~SOF_KEEPALIVE;
956         } else {
957                 /*
958                  * No data outstanding, just poll occassionally
959                  */
960                 sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timekeep;
961                 sop->so_flags |= SOF_KEEPALIVE;
962         }
963
964         return;
965 }
966