Blame view

net/caif/cfctrl.c 15.7 KB
b482cd205   Sjur Braendeland   net-caif: add CAI...
1
2
3
4
5
  /*
   * Copyright (C) ST-Ericsson AB 2010
   * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
   * License terms: GNU General Public License (GPL) version 2
   */
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
6
  #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
b482cd205   Sjur Braendeland   net-caif: add CAI...
7
8
9
10
11
12
13
14
15
16
  #include <linux/stddef.h>
  #include <linux/spinlock.h>
  #include <linux/slab.h>
  #include <net/caif/caif_layer.h>
  #include <net/caif/cfpkt.h>
  #include <net/caif/cfctrl.h>
  
  #define container_obj(layr) container_of(layr, struct cfctrl, serv.layer)
  #define UTILITY_NAME_LENGTH 16
  #define CFPKT_CTRL_PKT_LEN 20
b482cd205   Sjur Braendeland   net-caif: add CAI...
17
18
19
  #ifdef CAIF_NO_LOOP
  static int handle_loop(struct cfctrl *ctrl,
  			      int cmd, struct cfpkt *pkt){
2aa40aef9   Sjur Braendeland   caif: Use link la...
20
  	return -1;
b482cd205   Sjur Braendeland   net-caif: add CAI...
21
22
23
24
25
26
27
28
29
30
31
32
  }
  #else
  static int handle_loop(struct cfctrl *ctrl,
  		int cmd, struct cfpkt *pkt);
  #endif
  static int cfctrl_recv(struct cflayer *layr, struct cfpkt *pkt);
  static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
  			   int phyid);
  
  
  struct cflayer *cfctrl_create(void)
  {
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
33
  	struct dev_info dev_info;
b482cd205   Sjur Braendeland   net-caif: add CAI...
34
  	struct cfctrl *this =
7ac2ed0ce   Joe Perches   caif: Remove OOM ...
35
36
  		kzalloc(sizeof(struct cfctrl), GFP_ATOMIC);
  	if (!this)
b482cd205   Sjur Braendeland   net-caif: add CAI...
37
  		return NULL;
b482cd205   Sjur Braendeland   net-caif: add CAI...
38
  	caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
39
40
  	memset(&dev_info, 0, sizeof(dev_info));
  	dev_info.id = 0xff;
b1c74247b   Sjur Braendeland   caif: Bugfix not ...
41
  	cfsrvl_init(&this->serv, 0, &dev_info, false);
b482cd205   Sjur Braendeland   net-caif: add CAI...
42
43
  	atomic_set(&this->req_seq_no, 1);
  	atomic_set(&this->rsp_seq_no, 1);
b482cd205   Sjur Braendeland   net-caif: add CAI...
44
45
46
  	this->serv.layer.receive = cfctrl_recv;
  	sprintf(this->serv.layer.name, "ctrl");
  	this->serv.layer.ctrlcmd = cfctrl_ctrlcmd;
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
47
  #ifndef CAIF_NO_LOOP
b482cd205   Sjur Braendeland   net-caif: add CAI...
48
  	spin_lock_init(&this->loop_linkid_lock);
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
49
50
  	this->loop_linkid = 1;
  #endif
7aecf4944   Sjur Braendeland   caif: Bugfix - us...
51
52
  	spin_lock_init(&this->info_list_lock);
  	INIT_LIST_HEAD(&this->list);
b482cd205   Sjur Braendeland   net-caif: add CAI...
53
54
  	return &this->serv.layer;
  }
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
55
56
57
58
59
60
61
62
63
64
65
66
67
  void cfctrl_remove(struct cflayer *layer)
  {
  	struct cfctrl_request_info *p, *tmp;
  	struct cfctrl *ctrl = container_obj(layer);
  
  	spin_lock_bh(&ctrl->info_list_lock);
  	list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
  		list_del(&p->list);
  		kfree(p);
  	}
  	spin_unlock_bh(&ctrl->info_list_lock);
  	kfree(layer);
  }
73d6ac633   Stephen Hemminger   caif: code cleanup
68
69
  static bool param_eq(const struct cfctrl_link_param *p1,
  			const struct cfctrl_link_param *p2)
b482cd205   Sjur Braendeland   net-caif: add CAI...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  {
  	bool eq =
  	    p1->linktype == p2->linktype &&
  	    p1->priority == p2->priority &&
  	    p1->phyid == p2->phyid &&
  	    p1->endpoint == p2->endpoint && p1->chtype == p2->chtype;
  
  	if (!eq)
  		return false;
  
  	switch (p1->linktype) {
  	case CFCTRL_SRV_VEI:
  		return true;
  	case CFCTRL_SRV_DATAGRAM:
  		return p1->u.datagram.connid == p2->u.datagram.connid;
  	case CFCTRL_SRV_RFM:
  		return
  		    p1->u.rfm.connid == p2->u.rfm.connid &&
  		    strcmp(p1->u.rfm.volume, p2->u.rfm.volume) == 0;
  	case CFCTRL_SRV_UTIL:
  		return
  		    p1->u.utility.fifosize_kb == p2->u.utility.fifosize_kb
  		    && p1->u.utility.fifosize_bufs ==
  		    p2->u.utility.fifosize_bufs
  		    && strcmp(p1->u.utility.name, p2->u.utility.name) == 0
  		    && p1->u.utility.paramlen == p2->u.utility.paramlen
  		    && memcmp(p1->u.utility.params, p2->u.utility.params,
  			      p1->u.utility.paramlen) == 0;
  
  	case CFCTRL_SRV_VIDEO:
  		return p1->u.video.connid == p2->u.video.connid;
  	case CFCTRL_SRV_DBG:
  		return true;
  	case CFCTRL_SRV_DECM:
  		return false;
  	default:
  		return false;
  	}
  	return false;
  }
73d6ac633   Stephen Hemminger   caif: code cleanup
110
111
  static bool cfctrl_req_eq(const struct cfctrl_request_info *r1,
  			  const struct cfctrl_request_info *r2)
b482cd205   Sjur Braendeland   net-caif: add CAI...
112
113
114
115
116
117
118
119
120
121
  {
  	if (r1->cmd != r2->cmd)
  		return false;
  	if (r1->cmd == CFCTRL_CMD_LINK_SETUP)
  		return param_eq(&r1->param, &r2->param);
  	else
  		return r1->channel_id == r2->channel_id;
  }
  
  /* Insert request at the end */
73d6ac633   Stephen Hemminger   caif: code cleanup
122
  static void cfctrl_insert_req(struct cfctrl *ctrl,
b482cd205   Sjur Braendeland   net-caif: add CAI...
123
124
  			      struct cfctrl_request_info *req)
  {
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
125
  	spin_lock_bh(&ctrl->info_list_lock);
b482cd205   Sjur Braendeland   net-caif: add CAI...
126
127
  	atomic_inc(&ctrl->req_seq_no);
  	req->sequence_no = atomic_read(&ctrl->req_seq_no);
7aecf4944   Sjur Braendeland   caif: Bugfix - us...
128
  	list_add_tail(&req->list, &ctrl->list);
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
129
  	spin_unlock_bh(&ctrl->info_list_lock);
b482cd205   Sjur Braendeland   net-caif: add CAI...
130
  }
b482cd205   Sjur Braendeland   net-caif: add CAI...
131
  /* Compare and remove request */
73d6ac633   Stephen Hemminger   caif: code cleanup
132
133
  static struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
  						struct cfctrl_request_info *req)
b482cd205   Sjur Braendeland   net-caif: add CAI...
134
  {
7aecf4944   Sjur Braendeland   caif: Bugfix - us...
135
  	struct cfctrl_request_info *p, *tmp, *first;
b482cd205   Sjur Braendeland   net-caif: add CAI...
136

7aecf4944   Sjur Braendeland   caif: Bugfix - us...
137
  	first = list_first_entry(&ctrl->list, struct cfctrl_request_info, list);
b482cd205   Sjur Braendeland   net-caif: add CAI...
138

7aecf4944   Sjur Braendeland   caif: Bugfix - us...
139
140
141
  	list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
  		if (cfctrl_req_eq(req, p)) {
  			if (p != first)
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
142
143
  				pr_warn("Requests are not received in order
  ");
7aecf4944   Sjur Braendeland   caif: Bugfix - us...
144

b482cd205   Sjur Braendeland   net-caif: add CAI...
145
  			atomic_set(&ctrl->rsp_seq_no,
7aecf4944   Sjur Braendeland   caif: Bugfix - us...
146
147
148
  					 p->sequence_no);
  			list_del(&p->list);
  			goto out;
b482cd205   Sjur Braendeland   net-caif: add CAI...
149
  		}
b482cd205   Sjur Braendeland   net-caif: add CAI...
150
  	}
7aecf4944   Sjur Braendeland   caif: Bugfix - us...
151
152
  	p = NULL;
  out:
7aecf4944   Sjur Braendeland   caif: Bugfix - us...
153
  	return p;
b482cd205   Sjur Braendeland   net-caif: add CAI...
154
155
156
157
158
159
160
  }
  
  struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer)
  {
  	struct cfctrl *this = container_obj(layer);
  	return &this->res;
  }
b482cd205   Sjur Braendeland   net-caif: add CAI...
161
162
163
164
165
166
167
168
169
170
  static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl)
  {
  	info->hdr_len = 0;
  	info->channel_id = cfctrl->serv.layer.id;
  	info->dev_info = &cfctrl->serv.dev_info;
  }
  
  void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
  {
  	struct cfctrl *cfctrl = container_obj(layer);
b482cd205   Sjur Braendeland   net-caif: add CAI...
171
  	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
172
  	struct cflayer *dn = cfctrl->serv.layer.dn;
7ac2ed0ce   Joe Perches   caif: Remove OOM ...
173
  	if (!pkt)
b482cd205   Sjur Braendeland   net-caif: add CAI...
174
  		return;
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
175
176
177
178
179
  	if (!dn) {
  		pr_debug("not able to send enum request
  ");
  		return;
  	}
b482cd205   Sjur Braendeland   net-caif: add CAI...
180
181
182
183
184
185
  	caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
  	init_info(cfpkt_info(pkt), cfctrl);
  	cfpkt_info(pkt)->dev_info->id = physlinkid;
  	cfctrl->serv.dev_info.id = physlinkid;
  	cfpkt_addbdy(pkt, CFCTRL_CMD_ENUM);
  	cfpkt_addbdy(pkt, physlinkid);
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
186
  	dn->transmit(dn, pkt);
b482cd205   Sjur Braendeland   net-caif: add CAI...
187
  }
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
188
  int cfctrl_linkup_request(struct cflayer *layer,
b482cd205   Sjur Braendeland   net-caif: add CAI...
189
190
191
192
193
194
195
196
197
198
  			   struct cfctrl_link_param *param,
  			   struct cflayer *user_layer)
  {
  	struct cfctrl *cfctrl = container_obj(layer);
  	u32 tmp32;
  	u16 tmp16;
  	u8 tmp8;
  	struct cfctrl_request_info *req;
  	int ret;
  	char utility_name[16];
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
199
  	struct cfpkt *pkt;
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
200
201
202
203
204
205
206
  	struct cflayer *dn = cfctrl->serv.layer.dn;
  
  	if (!dn) {
  		pr_debug("not able to send linkup request
  ");
  		return -ENODEV;
  	}
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
207
208
209
210
211
212
213
214
215
216
  
  	if (cfctrl_cancel_req(layer, user_layer) > 0) {
  		/* Slight Paranoia, check if already connecting */
  		pr_err("Duplicate connect request for same client
  ");
  		WARN_ON(1);
  		return -EALREADY;
  	}
  
  	pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
7ac2ed0ce   Joe Perches   caif: Remove OOM ...
217
  	if (!pkt)
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
218
  		return -ENOMEM;
b482cd205   Sjur Braendeland   net-caif: add CAI...
219
  	cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP);
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
220
221
  	cfpkt_addbdy(pkt, (param->chtype << 4) | param->linktype);
  	cfpkt_addbdy(pkt, (param->priority << 3) | param->phyid);
b482cd205   Sjur Braendeland   net-caif: add CAI...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  	cfpkt_addbdy(pkt, param->endpoint & 0x03);
  
  	switch (param->linktype) {
  	case CFCTRL_SRV_VEI:
  		break;
  	case CFCTRL_SRV_VIDEO:
  		cfpkt_addbdy(pkt, (u8) param->u.video.connid);
  		break;
  	case CFCTRL_SRV_DBG:
  		break;
  	case CFCTRL_SRV_DATAGRAM:
  		tmp32 = cpu_to_le32(param->u.datagram.connid);
  		cfpkt_add_body(pkt, &tmp32, 4);
  		break;
  	case CFCTRL_SRV_RFM:
  		/* Construct a frame, convert DatagramConnectionID to network
  		 * format long and copy it out...
  		 */
  		tmp32 = cpu_to_le32(param->u.rfm.connid);
  		cfpkt_add_body(pkt, &tmp32, 4);
  		/* Add volume name, including zero termination... */
  		cfpkt_add_body(pkt, param->u.rfm.volume,
  			       strlen(param->u.rfm.volume) + 1);
  		break;
  	case CFCTRL_SRV_UTIL:
  		tmp16 = cpu_to_le16(param->u.utility.fifosize_kb);
  		cfpkt_add_body(pkt, &tmp16, 2);
  		tmp16 = cpu_to_le16(param->u.utility.fifosize_bufs);
  		cfpkt_add_body(pkt, &tmp16, 2);
  		memset(utility_name, 0, sizeof(utility_name));
  		strncpy(utility_name, param->u.utility.name,
  			UTILITY_NAME_LENGTH - 1);
  		cfpkt_add_body(pkt, utility_name, UTILITY_NAME_LENGTH);
  		tmp8 = param->u.utility.paramlen;
  		cfpkt_add_body(pkt, &tmp8, 1);
  		cfpkt_add_body(pkt, param->u.utility.params,
  			       param->u.utility.paramlen);
  		break;
  	default:
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
261
262
263
  		pr_warn("Request setup of bad link type = %d
  ",
  			param->linktype);
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
264
  		return -EINVAL;
b482cd205   Sjur Braendeland   net-caif: add CAI...
265
  	}
49afa55b5   Julia Lawall   net/caif: Use kza...
266
  	req = kzalloc(sizeof(*req), GFP_KERNEL);
7ac2ed0ce   Joe Perches   caif: Remove OOM ...
267
  	if (!req)
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
268
  		return -ENOMEM;
b482cd205   Sjur Braendeland   net-caif: add CAI...
269
270
271
272
273
  	req->client_layer = user_layer;
  	req->cmd = CFCTRL_CMD_LINK_SETUP;
  	req->param = *param;
  	cfctrl_insert_req(cfctrl, req);
  	init_info(cfpkt_info(pkt), cfctrl);
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
274
275
276
277
278
  	/*
  	 * NOTE:Always send linkup and linkdown request on the same
  	 *	device as the payload. Otherwise old queued up payload
  	 *	might arrive with the newly allocated channel ID.
  	 */
b482cd205   Sjur Braendeland   net-caif: add CAI...
279
280
  	cfpkt_info(pkt)->dev_info->id = param->phyid;
  	ret =
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
281
  	    dn->transmit(dn, pkt);
b482cd205   Sjur Braendeland   net-caif: add CAI...
282
  	if (ret < 0) {
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
283
284
285
286
287
288
289
  		int count;
  
  		count = cfctrl_cancel_req(&cfctrl->serv.layer,
  						user_layer);
  		if (count != 1)
  			pr_err("Could not remove request (%d)", count);
  			return -ENODEV;
b482cd205   Sjur Braendeland   net-caif: add CAI...
290
  	}
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
291
  	return 0;
b482cd205   Sjur Braendeland   net-caif: add CAI...
292
293
294
295
296
297
298
299
  }
  
  int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
  				struct cflayer *client)
  {
  	int ret;
  	struct cfctrl *cfctrl = container_obj(layer);
  	struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
300
  	struct cflayer *dn = cfctrl->serv.layer.dn;
7ac2ed0ce   Joe Perches   caif: Remove OOM ...
301
  	if (!pkt)
b482cd205   Sjur Braendeland   net-caif: add CAI...
302
  		return -ENOMEM;
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
303
304
305
306
307
308
  
  	if (!dn) {
  		pr_debug("not able to send link-down request
  ");
  		return -ENODEV;
  	}
b482cd205   Sjur Braendeland   net-caif: add CAI...
309
310
311
312
  	cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY);
  	cfpkt_addbdy(pkt, channelid);
  	init_info(cfpkt_info(pkt), cfctrl);
  	ret =
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
313
  	    dn->transmit(dn, pkt);
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
314
315
316
  #ifndef CAIF_NO_LOOP
  	cfctrl->loop_linkused[channelid] = 0;
  #endif
b482cd205   Sjur Braendeland   net-caif: add CAI...
317
318
  	return ret;
  }
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
319
  int cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
320
  {
7aecf4944   Sjur Braendeland   caif: Bugfix - us...
321
  	struct cfctrl_request_info *p, *tmp;
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
322
  	struct cfctrl *ctrl = container_obj(layr);
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
323
324
  	int found = 0;
  	spin_lock_bh(&ctrl->info_list_lock);
7aecf4944   Sjur Braendeland   caif: Bugfix - us...
325
326
327
  
  	list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
  		if (p->client_layer == adap_layer) {
7aecf4944   Sjur Braendeland   caif: Bugfix - us...
328
329
  			list_del(&p->list);
  			kfree(p);
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
330
  			found++;
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
331
  		}
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
332
  	}
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
333
334
  	spin_unlock_bh(&ctrl->info_list_lock);
  	return found;
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
335
  }
b482cd205   Sjur Braendeland   net-caif: add CAI...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
  {
  	u8 cmdrsp;
  	u8 cmd;
  	int ret = -1;
  	u16 tmp16;
  	u8 len;
  	u8 param[255];
  	u8 linkid;
  	struct cfctrl *cfctrl = container_obj(layer);
  	struct cfctrl_request_info rsp, *req;
  
  
  	cfpkt_extr_head(pkt, &cmdrsp, 1);
  	cmd = cmdrsp & CFCTRL_CMD_MASK;
  	if (cmd != CFCTRL_CMD_LINK_ERR
96796ea8b   sjur.brandeland@stericsson.com   caif: Fix freezes...
352
353
  	    && CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp)
  		&& CFCTRL_ERR_BIT != (CFCTRL_ERR_BIT & cmdrsp)) {
2aa40aef9   Sjur Braendeland   caif: Use link la...
354
  		if (handle_loop(cfctrl, cmd, pkt) != 0)
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
355
  			cmdrsp |= CFCTRL_ERR_BIT;
b482cd205   Sjur Braendeland   net-caif: add CAI...
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  	}
  
  	switch (cmd) {
  	case CFCTRL_CMD_LINK_SETUP:
  		{
  			enum cfctrl_srv serv;
  			enum cfctrl_srv servtype;
  			u8 endpoint;
  			u8 physlinkid;
  			u8 prio;
  			u8 tmp;
  			u32 tmp32;
  			u8 *cp;
  			int i;
  			struct cfctrl_link_param linkparam;
  			memset(&linkparam, 0, sizeof(linkparam));
  
  			cfpkt_extr_head(pkt, &tmp, 1);
  
  			serv = tmp & CFCTRL_SRV_MASK;
  			linkparam.linktype = serv;
  
  			servtype = tmp >> 4;
  			linkparam.chtype = servtype;
  
  			cfpkt_extr_head(pkt, &tmp, 1);
  			physlinkid = tmp & 0x07;
  			prio = tmp >> 3;
  
  			linkparam.priority = prio;
  			linkparam.phyid = physlinkid;
  			cfpkt_extr_head(pkt, &endpoint, 1);
  			linkparam.endpoint = endpoint & 0x03;
  
  			switch (serv) {
  			case CFCTRL_SRV_VEI:
  			case CFCTRL_SRV_DBG:
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
393
394
  				if (CFCTRL_ERR_BIT & cmdrsp)
  					break;
b482cd205   Sjur Braendeland   net-caif: add CAI...
395
396
397
398
399
400
  				/* Link ID */
  				cfpkt_extr_head(pkt, &linkid, 1);
  				break;
  			case CFCTRL_SRV_VIDEO:
  				cfpkt_extr_head(pkt, &tmp, 1);
  				linkparam.u.video.connid = tmp;
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
401
402
  				if (CFCTRL_ERR_BIT & cmdrsp)
  					break;
b482cd205   Sjur Braendeland   net-caif: add CAI...
403
404
405
406
407
408
409
410
  				/* Link ID */
  				cfpkt_extr_head(pkt, &linkid, 1);
  				break;
  
  			case CFCTRL_SRV_DATAGRAM:
  				cfpkt_extr_head(pkt, &tmp32, 4);
  				linkparam.u.datagram.connid =
  				    le32_to_cpu(tmp32);
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
411
412
  				if (CFCTRL_ERR_BIT & cmdrsp)
  					break;
b482cd205   Sjur Braendeland   net-caif: add CAI...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  				/* Link ID */
  				cfpkt_extr_head(pkt, &linkid, 1);
  				break;
  			case CFCTRL_SRV_RFM:
  				/* Construct a frame, convert
  				 * DatagramConnectionID
  				 * to network format long and copy it out...
  				 */
  				cfpkt_extr_head(pkt, &tmp32, 4);
  				linkparam.u.rfm.connid =
  				  le32_to_cpu(tmp32);
  				cp = (u8 *) linkparam.u.rfm.volume;
  				for (cfpkt_extr_head(pkt, &tmp, 1);
  				     cfpkt_more(pkt) && tmp != '\0';
  				     cfpkt_extr_head(pkt, &tmp, 1))
  					*cp++ = tmp;
  				*cp = '\0';
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
430
431
  				if (CFCTRL_ERR_BIT & cmdrsp)
  					break;
b482cd205   Sjur Braendeland   net-caif: add CAI...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
  				/* Link ID */
  				cfpkt_extr_head(pkt, &linkid, 1);
  
  				break;
  			case CFCTRL_SRV_UTIL:
  				/* Construct a frame, convert
  				 * DatagramConnectionID
  				 * to network format long and copy it out...
  				 */
  				/* Fifosize KB */
  				cfpkt_extr_head(pkt, &tmp16, 2);
  				linkparam.u.utility.fifosize_kb =
  				    le16_to_cpu(tmp16);
  				/* Fifosize bufs */
  				cfpkt_extr_head(pkt, &tmp16, 2);
  				linkparam.u.utility.fifosize_bufs =
  				    le16_to_cpu(tmp16);
  				/* name */
  				cp = (u8 *) linkparam.u.utility.name;
  				caif_assert(sizeof(linkparam.u.utility.name)
  					     >= UTILITY_NAME_LENGTH);
  				for (i = 0;
  				     i < UTILITY_NAME_LENGTH
  				     && cfpkt_more(pkt); i++) {
  					cfpkt_extr_head(pkt, &tmp, 1);
  					*cp++ = tmp;
  				}
  				/* Length */
  				cfpkt_extr_head(pkt, &len, 1);
  				linkparam.u.utility.paramlen = len;
  				/* Param Data */
  				cp = linkparam.u.utility.params;
  				while (cfpkt_more(pkt) && len--) {
  					cfpkt_extr_head(pkt, &tmp, 1);
  					*cp++ = tmp;
  				}
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
468
469
  				if (CFCTRL_ERR_BIT & cmdrsp)
  					break;
b482cd205   Sjur Braendeland   net-caif: add CAI...
470
471
472
473
474
475
476
477
  				/* Link ID */
  				cfpkt_extr_head(pkt, &linkid, 1);
  				/* Length */
  				cfpkt_extr_head(pkt, &len, 1);
  				/* Param Data */
  				cfpkt_extr_head(pkt, &param, len);
  				break;
  			default:
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
478
479
  				pr_warn("Request setup, invalid type (%d)
  ",
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
480
  					serv);
b482cd205   Sjur Braendeland   net-caif: add CAI...
481
482
483
484
485
  				goto error;
  			}
  
  			rsp.cmd = cmd;
  			rsp.param = linkparam;
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
486
  			spin_lock_bh(&cfctrl->info_list_lock);
b482cd205   Sjur Braendeland   net-caif: add CAI...
487
488
489
490
  			req = cfctrl_remove_req(cfctrl, &rsp);
  
  			if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) ||
  				cfpkt_erroneous(pkt)) {
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
491
492
493
  				pr_err("Invalid O/E bit or parse error "
  						"on CAIF control channel
  ");
b482cd205   Sjur Braendeland   net-caif: add CAI...
494
495
496
497
498
499
500
501
502
503
504
505
506
507
  				cfctrl->res.reject_rsp(cfctrl->serv.layer.up,
  						       0,
  						       req ? req->client_layer
  						       : NULL);
  			} else {
  				cfctrl->res.linksetup_rsp(cfctrl->serv.
  							  layer.up, linkid,
  							  serv, physlinkid,
  							  req ? req->
  							  client_layer : NULL);
  			}
  
  			if (req != NULL)
  				kfree(req);
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
508
509
  
  			spin_unlock_bh(&cfctrl->info_list_lock);
b482cd205   Sjur Braendeland   net-caif: add CAI...
510
511
512
513
  		}
  		break;
  	case CFCTRL_CMD_LINK_DESTROY:
  		cfpkt_extr_head(pkt, &linkid, 1);
8d545c8f9   Sjur Braendeland   caif: Disconnect ...
514
  		cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid);
b482cd205   Sjur Braendeland   net-caif: add CAI...
515
516
  		break;
  	case CFCTRL_CMD_LINK_ERR:
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
517
518
  		pr_err("Frame Error Indication received
  ");
b482cd205   Sjur Braendeland   net-caif: add CAI...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
  		cfctrl->res.linkerror_ind();
  		break;
  	case CFCTRL_CMD_ENUM:
  		cfctrl->res.enum_rsp();
  		break;
  	case CFCTRL_CMD_SLEEP:
  		cfctrl->res.sleep_rsp();
  		break;
  	case CFCTRL_CMD_WAKE:
  		cfctrl->res.wake_rsp();
  		break;
  	case CFCTRL_CMD_LINK_RECONF:
  		cfctrl->res.restart_rsp();
  		break;
  	case CFCTRL_CMD_RADIO_SET:
  		cfctrl->res.radioset_rsp();
  		break;
  	default:
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
537
538
  		pr_err("Unrecognized Control Frame
  ");
b482cd205   Sjur Braendeland   net-caif: add CAI...
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
  		goto error;
  		break;
  	}
  	ret = 0;
  error:
  	cfpkt_destroy(pkt);
  	return ret;
  }
  
  static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
  			int phyid)
  {
  	struct cfctrl *this = container_obj(layr);
  	switch (ctrl) {
  	case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
  	case CAIF_CTRLCMD_FLOW_OFF_IND:
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
555
  		spin_lock_bh(&this->info_list_lock);
0e5a11744   sjur.brandeland@stericsson.com   caif: Bugfix add ...
556
  		if (!list_empty(&this->list))
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
557
558
  			pr_debug("Received flow off in control layer
  ");
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
559
  		spin_unlock_bh(&this->info_list_lock);
b482cd205   Sjur Braendeland   net-caif: add CAI...
560
  		break;
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
  	case _CAIF_CTRLCMD_PHYIF_DOWN_IND: {
  		struct cfctrl_request_info *p, *tmp;
  
  		/* Find all connect request and report failure */
  		spin_lock_bh(&this->info_list_lock);
  		list_for_each_entry_safe(p, tmp, &this->list, list) {
  			if (p->param.phyid == phyid) {
  				list_del(&p->list);
  				p->client_layer->ctrlcmd(p->client_layer,
  						CAIF_CTRLCMD_INIT_FAIL_RSP,
  						phyid);
  				kfree(p);
  			}
  		}
  		spin_unlock_bh(&this->info_list_lock);
  		break;
  	}
b482cd205   Sjur Braendeland   net-caif: add CAI...
578
579
580
581
582
583
584
585
586
  	default:
  		break;
  	}
  }
  
  #ifndef CAIF_NO_LOOP
  static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt)
  {
  	static int last_linkid;
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
587
  	static int dec;
b482cd205   Sjur Braendeland   net-caif: add CAI...
588
589
590
  	u8 linkid, linktype, tmp;
  	switch (cmd) {
  	case CFCTRL_CMD_LINK_SETUP:
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
591
592
  		spin_lock_bh(&ctrl->loop_linkid_lock);
  		if (!dec) {
96796ea8b   sjur.brandeland@stericsson.com   caif: Fix freezes...
593
  			for (linkid = last_linkid + 1; linkid < 254; linkid++)
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
594
595
596
597
  				if (!ctrl->loop_linkused[linkid])
  					goto found;
  		}
  		dec = 1;
96796ea8b   sjur.brandeland@stericsson.com   caif: Fix freezes...
598
  		for (linkid = last_linkid - 1; linkid > 1; linkid--)
b482cd205   Sjur Braendeland   net-caif: add CAI...
599
600
  			if (!ctrl->loop_linkused[linkid])
  				goto found;
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
601
  		spin_unlock_bh(&ctrl->loop_linkid_lock);
96796ea8b   sjur.brandeland@stericsson.com   caif: Fix freezes...
602
  		return -1;
b482cd205   Sjur Braendeland   net-caif: add CAI...
603
  found:
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
604
605
  		if (linkid < 10)
  			dec = 0;
b482cd205   Sjur Braendeland   net-caif: add CAI...
606
607
608
609
610
611
  		if (!ctrl->loop_linkused[linkid])
  			ctrl->loop_linkused[linkid] = 1;
  
  		last_linkid = linkid;
  
  		cfpkt_add_trail(pkt, &linkid, 1);
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
612
  		spin_unlock_bh(&ctrl->loop_linkid_lock);
b482cd205   Sjur Braendeland   net-caif: add CAI...
613
614
615
616
617
618
619
620
621
  		cfpkt_peek_head(pkt, &linktype, 1);
  		if (linktype ==  CFCTRL_SRV_UTIL) {
  			tmp = 0x01;
  			cfpkt_add_trail(pkt, &tmp, 1);
  			cfpkt_add_trail(pkt, &tmp, 1);
  		}
  		break;
  
  	case CFCTRL_CMD_LINK_DESTROY:
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
622
  		spin_lock_bh(&ctrl->loop_linkid_lock);
b482cd205   Sjur Braendeland   net-caif: add CAI...
623
624
  		cfpkt_peek_head(pkt, &linkid, 1);
  		ctrl->loop_linkused[linkid] = 0;
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
625
  		spin_unlock_bh(&ctrl->loop_linkid_lock);
b482cd205   Sjur Braendeland   net-caif: add CAI...
626
627
628
629
  		break;
  	default:
  		break;
  	}
2aa40aef9   Sjur Braendeland   caif: Use link la...
630
  	return 0;
b482cd205   Sjur Braendeland   net-caif: add CAI...
631
632
  }
  #endif