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