Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[linux-2.6] / net / irda / ircomm / ircomm_event.c
1 /*********************************************************************
2  *
3  * Filename:      ircomm_event.c
4  * Version:       1.0
5  * Description:   IrCOMM layer state machine
6  * Status:        Stable
7  * Author:        Dag Brattli <dagb@cs.uit.no>
8  * Created at:    Sun Jun  6 20:33:11 1999
9  * Modified at:   Sun Dec 12 13:44:32 1999
10  * Modified by:   Dag Brattli <dagb@cs.uit.no>
11  *
12  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
13  *
14  *     This program is free software; you can redistribute it and/or
15  *     modify it under the terms of the GNU General Public License as
16  *     published by the Free Software Foundation; either version 2 of
17  *     the License, or (at your option) any later version.
18  *
19  *     This program is distributed in the hope that it will be useful,
20  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  *     GNU General Public License for more details.
23  *
24  *     You should have received a copy of the GNU General Public License
25  *     along with this program; if not, write to the Free Software
26  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27  *     MA 02111-1307 USA
28  *
29  ********************************************************************/
30
31 #include <linux/proc_fs.h>
32 #include <linux/init.h>
33
34 #include <net/irda/irda.h>
35 #include <net/irda/irlmp.h>
36 #include <net/irda/iriap.h>
37 #include <net/irda/irttp.h>
38 #include <net/irda/irias_object.h>
39
40 #include <net/irda/ircomm_core.h>
41 #include <net/irda/ircomm_event.h>
42
43 static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
44                              struct sk_buff *skb, struct ircomm_info *info);
45 static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
46                               struct sk_buff *skb, struct ircomm_info *info);
47 static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
48                               struct sk_buff *skb, struct ircomm_info *info);
49 static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
50                              struct sk_buff *skb, struct ircomm_info *info);
51
52 char *ircomm_state[] = {
53         "IRCOMM_IDLE",
54         "IRCOMM_WAITI",
55         "IRCOMM_WAITR",
56         "IRCOMM_CONN",
57 };
58
59 #ifdef CONFIG_IRDA_DEBUG
60 static char *ircomm_event[] = {
61         "IRCOMM_CONNECT_REQUEST",
62         "IRCOMM_CONNECT_RESPONSE",
63         "IRCOMM_TTP_CONNECT_INDICATION",
64         "IRCOMM_LMP_CONNECT_INDICATION",
65         "IRCOMM_TTP_CONNECT_CONFIRM",
66         "IRCOMM_LMP_CONNECT_CONFIRM",
67
68         "IRCOMM_LMP_DISCONNECT_INDICATION",
69         "IRCOMM_TTP_DISCONNECT_INDICATION",
70         "IRCOMM_DISCONNECT_REQUEST",
71
72         "IRCOMM_TTP_DATA_INDICATION",
73         "IRCOMM_LMP_DATA_INDICATION",
74         "IRCOMM_DATA_REQUEST",
75         "IRCOMM_CONTROL_REQUEST",
76         "IRCOMM_CONTROL_INDICATION",
77 };
78 #endif /* CONFIG_IRDA_DEBUG */
79
80 static int (*state[])(struct ircomm_cb *self, IRCOMM_EVENT event,
81                       struct sk_buff *skb, struct ircomm_info *info) =
82 {
83         ircomm_state_idle,
84         ircomm_state_waiti,
85         ircomm_state_waitr,
86         ircomm_state_conn,
87 };
88
89 /*
90  * Function ircomm_state_idle (self, event, skb)
91  *
92  *    IrCOMM is currently idle
93  *
94  */
95 static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
96                              struct sk_buff *skb, struct ircomm_info *info)
97 {
98         int ret = 0;
99
100         switch (event) {
101         case IRCOMM_CONNECT_REQUEST:
102                 ircomm_next_state(self, IRCOMM_WAITI);
103                 ret = self->issue.connect_request(self, skb, info);
104                 break;
105         case IRCOMM_TTP_CONNECT_INDICATION:
106         case IRCOMM_LMP_CONNECT_INDICATION:
107                 ircomm_next_state(self, IRCOMM_WAITR);
108                 ircomm_connect_indication(self, skb, info);
109                 break;
110         default:
111                 IRDA_DEBUG(4, "%s(), unknown event: %s\n", __func__ ,
112                            ircomm_event[event]);
113                 ret = -EINVAL;
114         }
115         return ret;
116 }
117
118 /*
119  * Function ircomm_state_waiti (self, event, skb)
120  *
121  *    The IrCOMM user has requested an IrCOMM connection to the remote
122  *    device and is awaiting confirmation
123  */
124 static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
125                               struct sk_buff *skb, struct ircomm_info *info)
126 {
127         int ret = 0;
128
129         switch (event) {
130         case IRCOMM_TTP_CONNECT_CONFIRM:
131         case IRCOMM_LMP_CONNECT_CONFIRM:
132                 ircomm_next_state(self, IRCOMM_CONN);
133                 ircomm_connect_confirm(self, skb, info);
134                 break;
135         case IRCOMM_TTP_DISCONNECT_INDICATION:
136         case IRCOMM_LMP_DISCONNECT_INDICATION:
137                 ircomm_next_state(self, IRCOMM_IDLE);
138                 ircomm_disconnect_indication(self, skb, info);
139                 break;
140         default:
141                 IRDA_DEBUG(0, "%s(), unknown event: %s\n", __func__ ,
142                            ircomm_event[event]);
143                 ret = -EINVAL;
144         }
145         return ret;
146 }
147
148 /*
149  * Function ircomm_state_waitr (self, event, skb)
150  *
151  *    IrCOMM has received an incoming connection request and is awaiting
152  *    response from the user
153  */
154 static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
155                               struct sk_buff *skb, struct ircomm_info *info)
156 {
157         int ret = 0;
158
159         switch (event) {
160         case IRCOMM_CONNECT_RESPONSE:
161                 ircomm_next_state(self, IRCOMM_CONN);
162                 ret = self->issue.connect_response(self, skb);
163                 break;
164         case IRCOMM_DISCONNECT_REQUEST:
165                 ircomm_next_state(self, IRCOMM_IDLE);
166                 ret = self->issue.disconnect_request(self, skb, info);
167                 break;
168         case IRCOMM_TTP_DISCONNECT_INDICATION:
169         case IRCOMM_LMP_DISCONNECT_INDICATION:
170                 ircomm_next_state(self, IRCOMM_IDLE);
171                 ircomm_disconnect_indication(self, skb, info);
172                 break;
173         default:
174                 IRDA_DEBUG(0, "%s(), unknown event = %s\n", __func__ ,
175                            ircomm_event[event]);
176                 ret = -EINVAL;
177         }
178         return ret;
179 }
180
181 /*
182  * Function ircomm_state_conn (self, event, skb)
183  *
184  *    IrCOMM is connected to the peer IrCOMM device
185  *
186  */
187 static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
188                              struct sk_buff *skb, struct ircomm_info *info)
189 {
190         int ret = 0;
191
192         switch (event) {
193         case IRCOMM_DATA_REQUEST:
194                 ret = self->issue.data_request(self, skb, 0);
195                 break;
196         case IRCOMM_TTP_DATA_INDICATION:
197                 ircomm_process_data(self, skb);
198                 break;
199         case IRCOMM_LMP_DATA_INDICATION:
200                 ircomm_data_indication(self, skb);
201                 break;
202         case IRCOMM_CONTROL_REQUEST:
203                 /* Just send a separate frame for now */
204                 ret = self->issue.data_request(self, skb, skb->len);
205                 break;
206         case IRCOMM_TTP_DISCONNECT_INDICATION:
207         case IRCOMM_LMP_DISCONNECT_INDICATION:
208                 ircomm_next_state(self, IRCOMM_IDLE);
209                 ircomm_disconnect_indication(self, skb, info);
210                 break;
211         case IRCOMM_DISCONNECT_REQUEST:
212                 ircomm_next_state(self, IRCOMM_IDLE);
213                 ret = self->issue.disconnect_request(self, skb, info);
214                 break;
215         default:
216                 IRDA_DEBUG(0, "%s(), unknown event = %s\n", __func__ ,
217                            ircomm_event[event]);
218                 ret = -EINVAL;
219         }
220         return ret;
221 }
222
223 /*
224  * Function ircomm_do_event (self, event, skb)
225  *
226  *    Process event
227  *
228  */
229 int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event,
230                     struct sk_buff *skb, struct ircomm_info *info)
231 {
232         IRDA_DEBUG(4, "%s: state=%s, event=%s\n", __func__ ,
233                    ircomm_state[self->state], ircomm_event[event]);
234
235         return (*state[self->state])(self, event, skb, info);
236 }
237
238 /*
239  * Function ircomm_next_state (self, state)
240  *
241  *    Switch state
242  *
243  */
244 void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state)
245 {
246         self->state = state;
247
248         IRDA_DEBUG(4, "%s: next state=%s, service type=%d\n", __func__ ,
249                    ircomm_state[self->state], self->service_type);
250 }