kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / netproto / atm / uni / sscop_timer.c
CommitLineData
984263bc
MD
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 $
d2438d69 27 * @(#) $DragonFly: src/sys/netproto/atm/uni/sscop_timer.c,v 1.4 2003/08/07 21:54:34 dillon Exp $
984263bc
MD
28 */
29
30/*
31 * ATM Forum UNI Support
32 * ---------------------
33 *
34 * SSCOP - Timer processing
35 *
36 */
37
d2438d69 38#include <netproto/atm/kern_include.h>
984263bc 39
1f2de5d4
MD
40#include "sscop.h"
41#include "sscop_misc.h"
42#include "sscop_var.h"
984263bc 43
984263bc
MD
44/*
45 * Local functions
46 */
47static void sscop_poll_expire __P((struct sscop *));
48static void sscop_noresponse_expire __P((struct sscop *));
49static void sscop_cc_expire __P((struct sscop *));
50static void sscop_idle_expire __P((struct sscop *));
51
52/*
53 * Local variables
54 */
55static 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 */
79void
80sscop_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 */
155static void
156sscop_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 */
201static void
202sscop_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 */
250static void
251sscop_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 */
328static void
329sscop_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:
439rexmitrs:
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