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