cfcnfg.c 14.4 KB
Newer Older
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
 */
J
Joe Perches 已提交
6 7 8

#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__

9 10
#include <linux/kernel.h>
#include <linux/stddef.h>
11
#include <linux/slab.h>
12
#include <linux/netdevice.h>
13
#include <linux/module.h>
14 15 16 17 18 19 20 21
#include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfcnfg.h>
#include <net/caif/cfctrl.h>
#include <net/caif/cfmuxl.h>
#include <net/caif/cffrml.h>
#include <net/caif/cfserl.h>
#include <net/caif/cfsrvl.h>
22
#include <net/caif/caif_dev.h>
23 24 25 26 27 28 29

#define container_obj(layr) container_of(layr, struct cfcnfg, layer)

/* Information about CAIF physical interfaces held by Config Module in order
 * to manage physical interfaces
 */
struct cfcnfg_phyinfo {
30 31 32
	struct list_head node;
	bool up;

33 34 35 36 37 38 39 40 41 42 43
	/* Pointer to the layer below the MUX (framing layer) */
	struct cflayer *frm_layer;
	/* Pointer to the lowest actual physical layer */
	struct cflayer *phy_layer;
	/* Unique identifier of the physical interface */
	unsigned int id;
	/* Preference of the physical in interface */
	enum cfcnfg_phy_preference pref;

	/* Information about the physical device */
	struct dev_info dev_info;
44 45 46 47

	/* Interface index */
	int ifindex;

48 49
	/* Protocol head room added for CAIF link layer */
	int head_room;
50 51 52

	/* Use Start of frame checksum */
	bool use_fcs;
53 54 55 56 57 58
};

struct cfcnfg {
	struct cflayer layer;
	struct cflayer *ctrl;
	struct cflayer *mux;
59 60
	struct list_head phys;
	struct mutex lock;
61 62
};

63
static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
64 65
			     enum cfctrl_srv serv, u8 phyid,
			     struct cflayer *adapt_layer);
66
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id);
67
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
68 69 70 71 72 73 74 75
			     struct cflayer *adapt_layer);
static void cfctrl_resp_func(void);
static void cfctrl_enum_resp(void);

struct cfcnfg *cfcnfg_create(void)
{
	struct cfcnfg *this;
	struct cfctrl_rsp *resp;
76 77 78

	might_sleep();

79
	/* Initiate this layer */
J
Julia Lawall 已提交
80
	this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
81
	if (!this)
82 83 84 85 86 87 88 89 90 91 92
		return NULL;
	this->mux = cfmuxl_create();
	if (!this->mux)
		goto out_of_mem;
	this->ctrl = cfctrl_create();
	if (!this->ctrl)
		goto out_of_mem;
	/* Initiate response functions */
	resp = cfctrl_get_respfuncs(this->ctrl);
	resp->enum_rsp = cfctrl_enum_resp;
	resp->linkerror_ind = cfctrl_resp_func;
93
	resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp;
94 95 96 97
	resp->sleep_rsp = cfctrl_resp_func;
	resp->wake_rsp = cfctrl_resp_func;
	resp->restart_rsp = cfctrl_resp_func;
	resp->radioset_rsp = cfctrl_resp_func;
98 99
	resp->linksetup_rsp = cfcnfg_linkup_rsp;
	resp->reject_rsp = cfcnfg_reject_rsp;
100
	INIT_LIST_HEAD(&this->phys);
101 102 103 104

	cfmuxl_set_uplayer(this->mux, this->ctrl, 0);
	layer_set_dn(this->ctrl, this->mux);
	layer_set_up(this->ctrl, this);
105 106
	mutex_init(&this->lock);

107 108
	return this;
out_of_mem:
109 110
	synchronize_rcu();

111 112 113 114 115 116 117 118
	kfree(this->mux);
	kfree(this->ctrl);
	kfree(this);
	return NULL;
}

void cfcnfg_remove(struct cfcnfg *cfg)
{
119
	might_sleep();
120
	if (cfg) {
121 122
		synchronize_rcu();

123
		kfree(cfg->mux);
124
		cfctrl_remove(cfg->ctrl);
125 126 127 128 129 130 131 132
		kfree(cfg);
	}
}

static void cfctrl_resp_func(void)
{
}

133 134 135 136 137 138 139 140 141 142 143
static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo_rcu(struct cfcnfg *cnfg,
							u8 phyid)
{
	struct cfcnfg_phyinfo *phy;

	list_for_each_entry_rcu(phy, &cnfg->phys, node)
		if (phy->id == phyid)
			return phy;
	return NULL;
}

144 145 146 147
static void cfctrl_enum_resp(void)
{
}

148
static struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
149 150 151
				  enum cfcnfg_phy_preference phy_pref)
{
	/* Try to match with specified preference */
152 153 154 155 156 157 158
	struct cfcnfg_phyinfo *phy;

	list_for_each_entry_rcu(phy, &cnfg->phys, node) {
		if (phy->up && phy->pref == phy_pref &&
				phy->frm_layer != NULL)

			return &phy->dev_info;
159 160
	}

161 162 163 164
	/* Otherwise just return something */
	list_for_each_entry_rcu(phy, &cnfg->phys, node)
		if (phy->up)
			return &phy->dev_info;
165 166 167 168

	return NULL;
}

169
static int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
170
{
171 172 173 174 175
	struct cfcnfg_phyinfo *phy;

	list_for_each_entry_rcu(phy, &cnfg->phys, node)
		if (phy->ifindex == ifi && phy->up)
			return phy->id;
176
	return -ENODEV;
177 178
}

179
int caif_disconnect_client(struct net *net, struct cflayer *adap_layer)
180
{
181
	u8 channel_id;
182
	struct cfcnfg *cfg = get_cfcnfg(net);
183

184
	caif_assert(adap_layer != NULL);
185
	cfctrl_cancel_req(cfg->ctrl, adap_layer);
186 187 188 189
	channel_id = adap_layer->id;
	if (channel_id != 0) {
		struct cflayer *servl;
		servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
190
		cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);
191 192 193 194
		if (servl != NULL)
			layer_set_up(servl, NULL);
	} else
		pr_debug("nothing to disconnect\n");
195 196 197

	/* Do RCU sync before initiating cleanup */
	synchronize_rcu();
198 199
	if (adap_layer->ctrlcmd != NULL)
		adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
200
	return 0;
201 202

}
203
EXPORT_SYMBOL(caif_disconnect_client);
204

205
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
206 207 208
{
}

S
Stephen Hemminger 已提交
209
static const int protohead[CFCTRL_SRV_MASK] = {
210 211 212 213 214 215 216
	[CFCTRL_SRV_VEI] = 4,
	[CFCTRL_SRV_DATAGRAM] = 7,
	[CFCTRL_SRV_UTIL] = 4,
	[CFCTRL_SRV_RFM] = 3,
	[CFCTRL_SRV_DBG] = 3,
};

217 218 219 220 221 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 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303

static int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
				   struct caif_connect_request *s,
				   struct cfctrl_link_param *l)
{
	struct dev_info *dev_info;
	enum cfcnfg_phy_preference pref;
	int res;

	memset(l, 0, sizeof(*l));
	/* In caif protocol low value is high priority */
	l->priority = CAIF_PRIO_MAX - s->priority + 1;

	if (s->ifindex != 0) {
		res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex);
		if (res < 0)
			return res;
		l->phyid = res;
	} else {
		switch (s->link_selector) {
		case CAIF_LINK_HIGH_BANDW:
			pref = CFPHYPREF_HIGH_BW;
			break;
		case CAIF_LINK_LOW_LATENCY:
			pref = CFPHYPREF_LOW_LAT;
			break;
		default:
			return -EINVAL;
		}
		dev_info = cfcnfg_get_phyid(cnfg, pref);
		if (dev_info == NULL)
			return -ENODEV;
		l->phyid = dev_info->id;
	}
	switch (s->protocol) {
	case CAIFPROTO_AT:
		l->linktype = CFCTRL_SRV_VEI;
		l->endpoint = (s->sockaddr.u.at.type >> 2) & 0x3;
		l->chtype = s->sockaddr.u.at.type & 0x3;
		break;
	case CAIFPROTO_DATAGRAM:
		l->linktype = CFCTRL_SRV_DATAGRAM;
		l->chtype = 0x00;
		l->u.datagram.connid = s->sockaddr.u.dgm.connection_id;
		break;
	case CAIFPROTO_DATAGRAM_LOOP:
		l->linktype = CFCTRL_SRV_DATAGRAM;
		l->chtype = 0x03;
		l->endpoint = 0x00;
		l->u.datagram.connid = s->sockaddr.u.dgm.connection_id;
		break;
	case CAIFPROTO_RFM:
		l->linktype = CFCTRL_SRV_RFM;
		l->u.datagram.connid = s->sockaddr.u.rfm.connection_id;
		strncpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume,
			sizeof(l->u.rfm.volume)-1);
		l->u.rfm.volume[sizeof(l->u.rfm.volume)-1] = 0;
		break;
	case CAIFPROTO_UTIL:
		l->linktype = CFCTRL_SRV_UTIL;
		l->endpoint = 0x00;
		l->chtype = 0x00;
		strncpy(l->u.utility.name, s->sockaddr.u.util.service,
			sizeof(l->u.utility.name)-1);
		l->u.utility.name[sizeof(l->u.utility.name)-1] = 0;
		caif_assert(sizeof(l->u.utility.name) > 10);
		l->u.utility.paramlen = s->param.size;
		if (l->u.utility.paramlen > sizeof(l->u.utility.params))
			l->u.utility.paramlen = sizeof(l->u.utility.params);

		memcpy(l->u.utility.params, s->param.data,
		       l->u.utility.paramlen);

		break;
	case CAIFPROTO_DEBUG:
		l->linktype = CFCTRL_SRV_DBG;
		l->endpoint = s->sockaddr.u.dbg.service;
		l->chtype = s->sockaddr.u.dbg.type;
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

int caif_connect_client(struct net *net, struct caif_connect_request *conn_req,
			struct cflayer *adap_layer, int *ifindex,
304 305
				int *proto_head,
				int *proto_tail)
306 307
{
	struct cflayer *frml;
308 309
	struct cfcnfg_phyinfo *phy;
	int err;
310 311 312
	struct cfctrl_link_param param;
	struct cfcnfg *cfg = get_cfcnfg(net);
	caif_assert(cfg != NULL);
313 314

	rcu_read_lock();
315 316 317 318 319
	err = caif_connect_req_to_link_param(cfg, conn_req, &param);
	if (err)
		goto unlock;

	phy = cfcnfg_get_phyinfo_rcu(cfg, param.phyid);
320 321 322 323 324 325
	if (!phy) {
		err = -ENODEV;
		goto unlock;
	}
	err = -EINVAL;

326
	if (adap_layer == NULL) {
J
Joe Perches 已提交
327
		pr_err("adap_layer is zero\n");
328
		goto unlock;
329 330
	}
	if (adap_layer->receive == NULL) {
J
Joe Perches 已提交
331
		pr_err("adap_layer->receive is NULL\n");
332
		goto unlock;
333 334
	}
	if (adap_layer->ctrlcmd == NULL) {
J
Joe Perches 已提交
335
		pr_err("adap_layer->ctrlcmd == NULL\n");
336
		goto unlock;
337
	}
338 339 340

	err = -ENODEV;
	frml = phy->frm_layer;
341
	if (frml == NULL) {
J
Joe Perches 已提交
342
		pr_err("Specified PHY type does not exist!\n");
343
		goto unlock;
344
	}
345
	caif_assert(param.phyid == phy->id);
346
	caif_assert(phy->frm_layer->id ==
347
		     param.phyid);
348
	caif_assert(phy->phy_layer->id ==
349
		     param.phyid);
350

351 352
	*ifindex = phy->ifindex;
	*proto_tail = 2;
353
	*proto_head = protohead[param.linktype] + phy->head_room;
354

355
	rcu_read_unlock();
356

357
	/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
358 359
	cfctrl_enum_req(cfg->ctrl, param.phyid);
	return cfctrl_linkup_request(cfg->ctrl, &param, adap_layer);
360 361 362 363

unlock:
	rcu_read_unlock();
	return err;
364
}
365
EXPORT_SYMBOL(caif_connect_client);
366

367
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
368 369 370 371 372 373 374 375
			     struct cflayer *adapt_layer)
{
	if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
		adapt_layer->ctrlcmd(adapt_layer,
				     CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
}

static void
376
cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
377
		  u8 phyid, struct cflayer *adapt_layer)
378 379 380 381
{
	struct cfcnfg *cnfg = container_obj(layer);
	struct cflayer *servicel = NULL;
	struct cfcnfg_phyinfo *phyinfo;
382 383
	struct net_device *netdev;

384 385 386 387 388 389 390 391
	if (channel_id == 0) {
		pr_warn("received channel_id zero\n");
		if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
			adapt_layer->ctrlcmd(adapt_layer,
						CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
		return;
	}

392 393
	rcu_read_lock();

394
	if (adapt_layer == NULL) {
395 396
		pr_debug("link setup response but no client exist,"
				"send linkdown back\n");
397
		cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
398
		goto unlock;
399 400 401 402
	}

	caif_assert(cnfg != NULL);
	caif_assert(phyid != 0);
403 404 405 406 407 408 409 410 411

	phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid);
	if (phyinfo == NULL) {
		pr_err("ERROR: Link Layer Device dissapeared"
				"while connecting\n");
		goto unlock;
	}

	caif_assert(phyinfo != NULL);
412 413 414 415
	caif_assert(phyinfo->id == phyid);
	caif_assert(phyinfo->phy_layer != NULL);
	caif_assert(phyinfo->phy_layer->id == phyid);

416
	adapt_layer->id = channel_id;
417 418 419

	switch (serv) {
	case CFCTRL_SRV_VEI:
420
		servicel = cfvei_create(channel_id, &phyinfo->dev_info);
421 422
		break;
	case CFCTRL_SRV_DATAGRAM:
423 424
		servicel = cfdgml_create(channel_id,
					&phyinfo->dev_info);
425 426
		break;
	case CFCTRL_SRV_RFM:
427
		netdev = phyinfo->dev_info.dev;
428
		servicel = cfrfml_create(channel_id, &phyinfo->dev_info,
429
						netdev->mtu);
430 431
		break;
	case CFCTRL_SRV_UTIL:
432
		servicel = cfutill_create(channel_id, &phyinfo->dev_info);
433 434
		break;
	case CFCTRL_SRV_VIDEO:
435
		servicel = cfvidl_create(channel_id, &phyinfo->dev_info);
436 437
		break;
	case CFCTRL_SRV_DBG:
438
		servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
439 440
		break;
	default:
441 442 443
		pr_err("Protocol error. Link setup response "
				"- unknown channel type\n");
		goto unlock;
444
	}
445
	if (!servicel)
446
		goto unlock;
447
	layer_set_dn(servicel, cnfg->mux);
448
	cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
449 450
	layer_set_up(servicel, adapt_layer);
	layer_set_dn(adapt_layer, servicel);
451 452 453

	rcu_read_unlock();

454
	servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
455 456 457
	return;
unlock:
	rcu_read_unlock();
458 459 460
}

void
461
cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
462
		     struct net_device *dev, struct cflayer *phy_layer,
463
		     enum cfcnfg_phy_preference pref,
464 465
		     struct cflayer *link_support,
		     bool fcs, int head_room)
466 467
{
	struct cflayer *frml;
468
	struct cfcnfg_phyinfo *phyinfo = NULL;
469
	int i;
470
	u8 phyid;
471

472
	mutex_lock(&cnfg->lock);
473

474 475 476 477 478 479 480
	/* CAIF protocol allow maximum 6 link-layers */
	for (i = 0; i < 7; i++) {
		phyid = (dev->ifindex + i) & 0x7;
		if (phyid == 0)
			continue;
		if (cfcnfg_get_phyinfo_rcu(cnfg, phyid) == NULL)
			goto got_phyid;
481
	}
482
	pr_warn("Too many CAIF Link Layers (max 6)\n");
483
	goto out;
484 485 486

got_phyid:
	phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
487 488
	if (!phyinfo)
		goto out_err;
489

490 491 492 493 494 495 496
	phy_layer->id = phyid;
	phyinfo->pref = pref;
	phyinfo->id = phyid;
	phyinfo->dev_info.id = phyid;
	phyinfo->dev_info.dev = dev;
	phyinfo->phy_layer = phy_layer;
	phyinfo->ifindex = dev->ifindex;
497
	phyinfo->head_room = head_room;
498
	phyinfo->use_fcs = fcs;
499

500 501
	frml = cffrml_create(phyid, fcs);

502 503
	if (!frml)
		goto out_err;
504
	phyinfo->frm_layer = frml;
505 506
	layer_set_up(frml, cnfg->mux);

507 508 509 510 511 512
	if (link_support != NULL) {
		link_support->id = phyid;
		layer_set_dn(frml, link_support);
		layer_set_up(link_support, frml);
		layer_set_dn(link_support, phy_layer);
		layer_set_up(phy_layer, link_support);
513 514 515 516
	} else {
		layer_set_dn(frml, phy_layer);
		layer_set_up(phy_layer, frml);
	}
517 518

	list_add_rcu(&phyinfo->node, &cnfg->phys);
519
out:
520 521 522 523 524
	mutex_unlock(&cnfg->lock);
	return;

out_err:
	kfree(phyinfo);
525
	mutex_unlock(&cnfg->lock);
526 527 528
}
EXPORT_SYMBOL(cfcnfg_add_phy_layer);

529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer,
		bool up)
{
	struct cfcnfg_phyinfo *phyinfo;

	rcu_read_lock();
	phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phy_layer->id);
	if (phyinfo == NULL) {
		rcu_read_unlock();
		return -ENODEV;
	}

	if (phyinfo->up == up) {
		rcu_read_unlock();
		return 0;
	}
	phyinfo->up = up;

	if (up) {
		cffrml_hold(phyinfo->frm_layer);
		cfmuxl_set_dnlayer(cnfg->mux, phyinfo->frm_layer,
					phy_layer->id);
	} else {
		cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id);
		cffrml_put(phyinfo->frm_layer);
	}

	rcu_read_unlock();
	return 0;
}
EXPORT_SYMBOL(cfcnfg_set_phy_state);

561 562 563 564
int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
{
	struct cflayer *frml, *frml_dn;
	u16 phyid;
565 566 567 568 569 570
	struct cfcnfg_phyinfo *phyinfo;

	might_sleep();

	mutex_lock(&cnfg->lock);

571
	phyid = phy_layer->id;
572 573
	phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid);

574 575
	if (phyinfo == NULL) {
		mutex_unlock(&cnfg->lock);
576
		return 0;
577
	}
578 579
	caif_assert(phyid == phyinfo->id);
	caif_assert(phy_layer == phyinfo->phy_layer);
580
	caif_assert(phy_layer->id == phyid);
581 582
	caif_assert(phyinfo->frm_layer->id == phyid);

583 584 585
	list_del_rcu(&phyinfo->node);
	synchronize_rcu();

586 587 588
	/* Fail if reference count is not zero */
	if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) {
		pr_info("Wait for device inuse\n");
589
		list_add_rcu(&phyinfo->node, &cnfg->phys);
590 591 592 593
		mutex_unlock(&cnfg->lock);
		return -EAGAIN;
	}

594
	frml = phyinfo->frm_layer;
595 596 597 598 599 600 601 602
	frml_dn = frml->dn;
	cffrml_set_uplayer(frml, NULL);
	cffrml_set_dnlayer(frml, NULL);
	if (phy_layer != frml_dn) {
		layer_set_up(frml_dn, NULL);
		layer_set_dn(frml_dn, NULL);
	}
	layer_set_up(phy_layer, NULL);
603 604 605 606

	if (phyinfo->phy_layer != frml_dn)
		kfree(frml_dn);

607
	cffrml_free(frml);
608 609 610
	kfree(phyinfo);
	mutex_unlock(&cnfg->lock);

611 612 613
	return 0;
}
EXPORT_SYMBOL(cfcnfg_del_phy_layer);