/* * ROSE release 002 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * * This module: * This module is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * History * ROSE 001 Jonathan(G4KLX) Cloned from nr_timer.c */ #include #if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void rose_timer(unsigned long); /* * Linux set timer */ void rose_set_timer(struct sock *sk) { unsigned long flags; save_flags(flags); cli(); del_timer(&sk->timer); restore_flags(flags); sk->timer.data = (unsigned long)sk; sk->timer.function = &rose_timer; sk->timer.expires = jiffies + (HZ / 10); add_timer(&sk->timer); } /* * ROSE Timer * * This routine is called every 100ms. Decrement timer by this * amount - if expired then process the event. */ static void rose_timer(unsigned long param) { struct sock *sk = (struct sock *)param; switch (sk->protinfo.rose->state) { case ROSE_STATE_0: /* Magic here: If we listen() and a new link dies before it is accepted() it isn't 'dead' so doesn't get removed. */ if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) { del_timer(&sk->timer); rose_destroy_socket(sk); return; } break; case ROSE_STATE_3: /* * Check for the state of the receive buffer. */ if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)) { sk->protinfo.rose->condition &= ~ROSE_COND_OWN_RX_BUSY; sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; sk->protinfo.rose->vl = sk->protinfo.rose->vr; sk->protinfo.rose->timer = 0; rose_write_internal(sk, ROSE_RR); break; } /* * Check for frames to transmit. */ rose_kick(sk); break; default: break; } if (sk->protinfo.rose->timer == 0 || --sk->protinfo.rose->timer > 0) { rose_set_timer(sk); return; } /* * Timer has expired, it may have been T1, T2, T3 or HB. We can tell * by the socket state. */ switch (sk->protinfo.rose->state) { case ROSE_STATE_3: /* HB */ if (sk->protinfo.rose->condition & ROSE_COND_ACK_PENDING) { sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; rose_enquiry_response(sk); } break; case ROSE_STATE_1: /* T1 */ case ROSE_STATE_4: /* T2 */ rose_write_internal(sk, ROSE_CLEAR_REQUEST); sk->protinfo.rose->state = ROSE_STATE_2; sk->protinfo.rose->timer = sk->protinfo.rose->t3; break; case ROSE_STATE_2: /* T3 */ rose_clear_queues(sk); sk->protinfo.rose->state = ROSE_STATE_0; sk->state = TCP_CLOSE; sk->err = ETIMEDOUT; sk->shutdown |= SEND_SHUTDOWN; if (!sk->dead) sk->state_change(sk); sk->dead = 1; break; } rose_set_timer(sk); } #endif