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