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