import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / net / ax25 / ax25_std_timer.c
1 /*
2  *      AX.25 release 037
3  *
4  *      This code REQUIRES 2.1.15 or higher/ NET3.038
5  *
6  *      This module:
7  *              This module is free software; you can redistribute it and/or
8  *              modify it under the terms of the GNU General Public License
9  *              as published by the Free Software Foundation; either version
10  *              2 of the License, or (at your option) any later version.
11  *
12  *      History
13  *      AX.25 028a      Jonathan(G4KLX) New state machine based on SDL diagrams.
14  *      AX.25 028b      Jonathan(G4KLX) Extracted AX25 control block from the
15  *                                      sock structure.
16  *      AX.25 029       Alan(GW4PTS)    Switched to KA9Q constant names.
17  *      AX.25 031       Joerg(DL1BKE)   Added DAMA support
18  *      AX.25 032       Joerg(DL1BKE)   Fixed DAMA timeout bug
19  *      AX.25 033       Jonathan(G4KLX) Modularisation functions.
20  *      AX.25 035       Frederic(F1OAT) Support for pseudo-digipeating.
21  *      AX.25 036       Jonathan(G4KLX) Split from ax25_timer.c.
22  *      AX.25 037       Jonathan(G4KLX) New timer architecture.
23  */
24
25 #include <linux/errno.h>
26 #include <linux/types.h>
27 #include <linux/socket.h>
28 #include <linux/in.h>
29 #include <linux/kernel.h>
30 #include <linux/sched.h>
31 #include <linux/timer.h>
32 #include <linux/string.h>
33 #include <linux/sockios.h>
34 #include <linux/net.h>
35 #include <net/ax25.h>
36 #include <linux/inet.h>
37 #include <linux/netdevice.h>
38 #include <linux/skbuff.h>
39 #include <net/sock.h>
40 #include <asm/uaccess.h>
41 #include <asm/system.h>
42 #include <linux/fcntl.h>
43 #include <linux/mm.h>
44 #include <linux/interrupt.h>
45
46 void ax25_std_heartbeat_expiry(ax25_cb *ax25)
47 {
48         switch (ax25->state) {
49
50                 case AX25_STATE_0:
51                         /* Magic here: If we listen() and a new link dies before it
52                            is accepted() it isn't 'dead' so doesn't get removed. */
53                         if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
54                                 ax25_destroy_socket(ax25);
55                                 return;
56                         }
57                         break;
58
59                 case AX25_STATE_3:
60                 case AX25_STATE_4:
61                         /*
62                          * Check the state of the receive buffer.
63                          */
64                         if (ax25->sk != NULL) {
65                                 if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
66                                     (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
67                                         ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
68                                         ax25->condition &= ~AX25_COND_ACK_PENDING;
69                                         ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
70                                         break;
71                                 }
72                         }
73         }
74
75         ax25_start_heartbeat(ax25);
76 }
77
78 void ax25_std_t2timer_expiry(ax25_cb *ax25)
79 {
80         if (ax25->condition & AX25_COND_ACK_PENDING) {
81                 ax25->condition &= ~AX25_COND_ACK_PENDING;
82                 ax25_std_timeout_response(ax25);
83         }
84 }
85
86 void ax25_std_t3timer_expiry(ax25_cb *ax25)
87 {
88         ax25->n2count = 0;
89         ax25_std_transmit_enquiry(ax25);
90         ax25->state   = AX25_STATE_4;
91 }
92
93 void ax25_std_idletimer_expiry(ax25_cb *ax25)
94 {
95         ax25_clear_queues(ax25);
96
97         ax25->n2count = 0;
98         ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
99         ax25->state   = AX25_STATE_2;
100
101         ax25_calculate_t1(ax25);
102         ax25_start_t1timer(ax25);
103         ax25_stop_t2timer(ax25);
104         ax25_stop_t3timer(ax25);
105
106         if (ax25->sk != NULL) {
107                 ax25->sk->state     = TCP_CLOSE;
108                 ax25->sk->err       = 0;
109                 ax25->sk->shutdown |= SEND_SHUTDOWN;
110                 if (!ax25->sk->dead)
111                         ax25->sk->state_change(ax25->sk);
112                 ax25->sk->dead      = 1;
113         }
114 }
115
116 void ax25_std_t1timer_expiry(ax25_cb *ax25)
117 {
118         switch (ax25->state) {
119                 case AX25_STATE_1: 
120                         if (ax25->n2count == ax25->n2) {
121                                 if (ax25->modulus == AX25_MODULUS) {
122                                         ax25_disconnect(ax25, ETIMEDOUT);
123                                         return;
124                                 } else {
125                                         ax25->modulus = AX25_MODULUS;
126                                         ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
127                                         ax25->n2count = 0;
128                                         ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
129                                 }
130                         } else {
131                                 ax25->n2count++;
132                                 if (ax25->modulus == AX25_MODULUS)
133                                         ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
134                                 else
135                                         ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
136                         }
137                         break;
138
139                 case AX25_STATE_2:
140                         if (ax25->n2count == ax25->n2) {
141                                 ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
142                                 ax25_disconnect(ax25, ETIMEDOUT);
143                                 return;
144                         } else {
145                                 ax25->n2count++;
146                                 ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
147                         }
148                         break;
149
150                 case AX25_STATE_3: 
151                         ax25->n2count = 1;
152                         ax25_std_transmit_enquiry(ax25);
153                         ax25->state   = AX25_STATE_4;
154                         break;
155
156                 case AX25_STATE_4:
157                         if (ax25->n2count == ax25->n2) {
158                                 ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
159                                 ax25_disconnect(ax25, ETIMEDOUT);
160                                 return;
161                         } else {
162                                 ax25->n2count++;
163                                 ax25_std_transmit_enquiry(ax25);
164                         }
165                         break;
166         }
167
168         ax25_calculate_t1(ax25);
169         ax25_start_t1timer(ax25);
170 }