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 const char *const ircomm_state[] = {
53 	"IRCOMM_IDLE",
54 	"IRCOMM_WAITI",
55 	"IRCOMM_WAITR",
56 	"IRCOMM_CONN",
57 };
58 
59 #ifdef CONFIG_IRDA_DEBUG
60 static const char *const 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  */
ircomm_state_idle(struct ircomm_cb * self,IRCOMM_EVENT event,struct sk_buff * skb,struct ircomm_info * info)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  */
ircomm_state_waiti(struct ircomm_cb * self,IRCOMM_EVENT event,struct sk_buff * skb,struct ircomm_info * info)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  */
ircomm_state_waitr(struct ircomm_cb * self,IRCOMM_EVENT event,struct sk_buff * skb,struct ircomm_info * info)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  */
ircomm_state_conn(struct ircomm_cb * self,IRCOMM_EVENT event,struct sk_buff * skb,struct ircomm_info * info)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  */
ircomm_do_event(struct ircomm_cb * self,IRCOMM_EVENT event,struct sk_buff * skb,struct ircomm_info * info)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  */
ircomm_next_state(struct ircomm_cb * self,IRCOMM_STATE state)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 }
251