Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / atm / uni / sscop_timer.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_timer.c,v 1.6 2000/01/17 20:49:53 mks Exp $
27  *
28  */
29
30 /*
31  * ATM Forum UNI Support
32  * ---------------------
33  *
34  * SSCOP - Timer processing
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_var.h>
43
44 #ifndef lint
45 __RCSID("@(#) $FreeBSD: src/sys/netatm/uni/sscop_timer.c,v 1.6 2000/01/17 20:49:53 mks Exp $");
46 #endif
47
48
49 /*
50  * Local functions
51  */
52 static void     sscop_poll_expire __P((struct sscop *));
53 static void     sscop_noresponse_expire __P((struct sscop *));
54 static void     sscop_cc_expire __P((struct sscop *));
55 static void     sscop_idle_expire __P((struct sscop *));
56
57 /*
58  * Local variables
59  */
60 static void     (*sscop_expired[SSCOP_T_NUM]) __P((struct sscop *)) = {
61         sscop_poll_expire,
62         sscop_noresponse_expire,
63         sscop_cc_expire,
64         sscop_idle_expire
65 };
66
67
68 /*
69  * Process an SSCOP timer tick
70  * 
71  * This function is called SSCOP_HZ times a second in order to update
72  * all of the sscop connection timers.  The sscop expiration function
73  * will be called to process all timer expirations.
74  *
75  * Called at splnet.
76  *
77  * Arguments:
78  *      tip     pointer to sscop timer control block
79  *
80  * Returns:
81  *      none
82  *
83  */
84 void
85 sscop_timeout(tip)
86         struct atm_time *tip;
87 {
88         struct sscop    *sop, **sprev;
89         int             i;
90
91
92         /*
93          * Schedule next timeout
94          */
95         atm_timeout(&sscop_timer, ATM_HZ/SSCOP_HZ, sscop_timeout);
96
97         /*
98          * Run through all connections, updating each active timer.
99          * If an expired timer is found, notify that entry.
100          */
101         sprev = &sscop_head;
102         while ((sop = *sprev) != NULL) {
103
104                 /*
105                  * Check out each timer
106                  */
107                 for (i =0; i < SSCOP_T_NUM; i++) {
108
109                         /*
110                          * Decrement timer if it's active
111                          */
112                         if (sop->so_timer[i] && (--sop->so_timer[i] == 0)) {
113
114 #ifdef DIAGNOSTIC
115                                 {
116                                         static char     *tn[] = {
117                                                 "POLL",
118                                                 "NORESPONSE",
119                                                 "CC",
120                                                 "IDLE"
121                                         };
122                                         ATM_DEBUG3("sscop_timer: %s expired, sop=%p, state=%d\n",
123                                                 tn[i], sop, sop->so_state);
124                                 }
125 #endif
126
127                                 /*
128                                  * Expired timer - process it
129                                  */
130                                 (*sscop_expired[i])(sop);
131
132                                 /*
133                                  * Make sure connection still exists
134                                  */
135                                 if (*sprev != sop)
136                                         break;
137                         }
138                 }
139
140                 /*
141                  * Update previous pointer if current control
142                  * block wasn't deleted
143                  */
144                 if (*sprev == sop)
145                         sprev = &sop->so_next;
146         }
147 }
148
149
150 /*
151  * Process an SSCOP Timer_POLL expiration
152  * 
153  * Arguments:
154  *      sop     pointer to sscop connection control block
155  *
156  * Returns:
157  *      none
158  *
159  */
160 static void
161 sscop_poll_expire(sop)
162         struct sscop    *sop;
163 {
164
165         /*
166          * Validate current state 
167          */
168         if ((sop->so_state != SOS_READY) &&
169             ((sop->so_state != SOS_INRESYN) ||
170              (sop->so_vers != SSCOP_VERS_QSAAL))) {
171                 log(LOG_ERR, "sscop: invalid %s state: sop=%p, state=%d\n",
172                         "Timer_POLL", sop, sop->so_state);
173                 return;
174         }
175
176         /*
177          * Send next poll along its way
178          */
179         SEQ_INCR(sop->so_pollsend, 1);
180         (void) sscop_send_poll(sop);
181
182         /*
183          * Reset data counter for this poll cycle
184          */
185         sop->so_polldata = 0;
186
187         /*
188          * Reset polling timer
189          */
190         sscop_set_poll(sop);
191
192         return;
193 }
194
195
196 /*
197  * Process an SSCOP Timer_IDLE expiration
198  * 
199  * Arguments:
200  *      sop     pointer to sscop connection control block
201  *
202  * Returns:
203  *      none
204  *
205  */
206 static void
207 sscop_idle_expire(sop)
208         struct sscop    *sop;
209 {
210
211         /*
212          * Timer_IDLE only valid in READY state
213          */
214         if (sop->so_state != SOS_READY) {
215                 log(LOG_ERR, "sscop: invalid %s state: sop=%p, state=%d\n",
216                         "Timer_IDLE", sop, sop->so_state);
217                 return;
218         }
219
220         /*
221          * Send next poll along its way
222          */
223         SEQ_INCR(sop->so_pollsend, 1);
224         (void) sscop_send_poll(sop);
225
226         /*
227          * Reset data counter for this poll cycle
228          */
229         sop->so_polldata = 0;
230
231         /*
232          * Start NO-RESPONSE timer
233          */
234         sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
235
236         /*
237          * Reset polling timer
238          */
239         sscop_set_poll(sop);
240
241         return;
242 }
243
244
245 /*
246  * Process an SSCOP Timer_NORESPONSE expiration
247  * 
248  * Arguments:
249  *      sop     pointer to sscop connection control block
250  *
251  * Returns:
252  *      none
253  *
254  */
255 static void
256 sscop_noresponse_expire(sop)
257         struct sscop    *sop;
258 {
259         int             err;
260
261         /*
262          * Validate current state 
263          */
264         if ((sop->so_state != SOS_READY) &&
265             ((sop->so_state != SOS_INRESYN) ||
266              (sop->so_vers != SSCOP_VERS_QSAAL))) {
267                 log(LOG_ERR, "sscop: invalid %s state: sop=%p, state=%d\n",
268                         "Timer_NORESPONSE", sop, sop->so_state);
269                 return;
270         }
271
272         /*
273          * Peer seems to be dead, so terminate session
274          */
275         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, 
276                 sop->so_toku, sop->so_connvc, 
277                 SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
278         if (err) {
279                 /*
280                  * Error, force retry
281                  */
282                 sop->so_timer[SSCOP_T_NORESP] = 1;
283                 return;
284         }
285
286         /*
287          * Stop data transfer timers
288          */
289         sop->so_timer[SSCOP_T_POLL] = 0;
290         sop->so_timer[SSCOP_T_IDLE] = 0;
291         sop->so_flags &= ~SOF_KEEPALIVE;
292
293         /*
294          * Notify peer of termination
295          */
296         (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
297
298         /*
299          * Report peer's failure
300          */
301         sscop_maa_error(sop, 'P');
302
303         if (sop->so_vers == SSCOP_VERS_QSAAL)
304                 /*
305                  * Clear connection data
306                  */
307                 qsaal1_clear_connection(sop);
308         else
309                 /*
310                  * Clear out appropriate queues
311                  */
312                 q2110_prep_retrieve(sop);
313
314         /*
315          * Return to IDLE state
316          */
317         sop->so_state = SOS_IDLE;
318
319         return;
320 }
321
322
323 /*
324  * Process an SSCOP Timer_CC expiration
325  * 
326  * Arguments:
327  *      sop     pointer to sscop connection control block
328  *
329  * Returns:
330  *      none
331  *
332  */
333 static void
334 sscop_cc_expire(sop)
335         struct sscop    *sop;
336 {
337         int             err;
338
339         /*
340          * Process timeout based on protocol state
341          */
342         switch (sop->so_state) {
343
344         case SOS_OUTCONN:
345                 /*
346                  * No response to our BGN yet
347                  */
348                 if (sop->so_connctl < sop->so_parm.sp_maxcc) {
349
350                         /*
351                          * Send another BGN PDU
352                          */
353                         sop->so_connctl++;
354                         (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER);
355
356                         /*
357                          * Restart retransmit timer
358                          */
359                         sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
360
361                 } else {
362
363                         /*
364                          * Retransmit limit exceeded, terminate session
365                          */
366                         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, 
367                                 sop->so_toku, sop->so_connvc, 
368                                 SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
369                         if (err) {
370                                 /*
371                                  * Error, force retry
372                                  */
373                                 sop->so_timer[SSCOP_T_CC] = 1;
374                                 break;
375                         }
376
377                         /*
378                          * Notify peer of termination
379                          */
380                         (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
381
382                         /*
383                          * Report establishment failure
384                          */
385                         sscop_maa_error(sop, 'O');
386
387                         /*
388                          * Clear reestablishment flag
389                          */
390                         sop->so_flags &= ~SOF_REESTAB;
391
392                         /*
393                          * Return to IDLE state
394                          */
395                         sop->so_state = SOS_IDLE;
396                 }
397                 break;
398
399         case SOS_OUTDISC:
400                 /*
401                  * No response to our END yet
402                  */
403                 if (sop->so_connctl < sop->so_parm.sp_maxcc) {
404
405                         /*
406                          * Send another END PDU
407                          */
408                         sop->so_connctl++;
409                         (void) sscop_send_end(sop, SSCOP_SOURCE_LAST);
410
411                         /*
412                          * Restart retransmit timer
413                          */
414                         sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
415
416                 } else {
417
418                         /*
419                          * Retransmit limit exceeded, force session termination
420                          */
421                         STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, 
422                                 sop->so_toku, sop->so_connvc, 0, 0, err);
423                         if (err) {
424                                 /*
425                                  * Error, force retry
426                                  */
427                                 sop->so_timer[SSCOP_T_CC] = 1;
428                                 break;
429                         }
430
431                         /*
432                          * Report establishment failure
433                          */
434                         sscop_maa_error(sop, 'O');
435
436                         /*
437                          * Return to IDLE state
438                          */
439                         sop->so_state = SOS_IDLE;
440                 }
441                 break;
442
443         case SOS_OUTRESYN:
444 rexmitrs:
445                 /*
446                  * No response to our RS yet
447                  */
448                 if (sop->so_connctl < sop->so_parm.sp_maxcc) {
449
450                         /*
451                          * Send another RS PDU
452                          */
453                         sop->so_connctl++;
454                         (void) sscop_send_rs(sop);
455
456                         /*
457                          * Restart retransmit timer
458                          */
459                         sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
460
461                 } else {
462
463                         /*
464                          * Retransmit limit exceeded, terminate session
465                          */
466                         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, 
467                                 sop->so_toku, sop->so_connvc, 
468                                 SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
469                         if (err) {
470                                 /*
471                                  * Error, force retry
472                                  */
473                                 sop->so_timer[SSCOP_T_CC] = 1;
474                                 break;
475                         }
476
477                         /*
478                          * Notify peer of termination
479                          */
480                         (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
481
482                         /*
483                          * Report establishment failure
484                          */
485                         sscop_maa_error(sop, 'O');
486
487                         if (sop->so_vers == SSCOP_VERS_QSAAL)
488                                 /*
489                                  * Clear connection data
490                                  */
491                                 qsaal1_clear_connection(sop);
492
493                         /*
494                          * Return to IDLE state
495                          */
496                         sop->so_state = SOS_IDLE;
497                 }
498                 break;
499
500         case SOS_CONRESYN:      /* Q.SAAL1 */
501 #if (SOS_OUTRECOV != SOS_CONRESYN)
502         case SOS_OUTRECOV:      /* Q.2110 */
503 #endif
504                 if (sop->so_vers == SSCOP_VERS_QSAAL) {
505                         /*
506                          * Handle timeout for SOS_CONRESYN
507                          */
508                         goto rexmitrs;
509                 } 
510
511                 /*
512                  * Handle timeout for SOS_OUTRECOV
513                  */
514
515                 /*
516                  * No response to our ER yet
517                  */
518                 if (sop->so_connctl < sop->so_parm.sp_maxcc) {
519
520                         /*
521                          * Send another ER PDU
522                          */
523                         sop->so_connctl++;
524                         (void) sscop_send_er(sop);
525
526                         /*
527                          * Restart retransmit timer
528                          */
529                         sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc;
530
531                 } else {
532
533                         /*
534                          * Retransmit limit exceeded, terminate session
535                          */
536                         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, 
537                                 sop->so_toku, sop->so_connvc, 
538                                 SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
539                         if (err) {
540                                 /*
541                                  * Error, force retry
542                                  */
543                                 sop->so_timer[SSCOP_T_CC] = 1;
544                                 break;
545                         }
546
547                         /*
548                          * Notify peer of termination
549                          */
550                         (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
551
552                         /*
553                          * Report establishment failure
554                          */
555                         sscop_maa_error(sop, 'O');
556
557                         /*
558                          * Clear receiver buffer
559                          */
560                         sscop_rcvr_drain(sop);
561
562                         /*
563                          * Return to IDLE state
564                          */
565                         sop->so_state = SOS_IDLE;
566                 }
567                 break;
568
569         default:
570                 log(LOG_ERR, "sscop: invalid %s state: sop=%p, state=%d\n",
571                         "Timer_CC", sop, sop->so_state);
572         }
573 }
574