cfcnfg.c 14.7 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 48 49 50 51 52

	/* Interface index */
	int ifindex;

	/* Use Start of frame extension */
	bool use_stx;

	/* 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) {
J
Joe Perches 已提交
82
		pr_warn("Out of memory\n");
83 84 85 86 87 88 89 90 91 92 93 94
		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;
95
	resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp;
96 97 98 99
	resp->sleep_rsp = cfctrl_resp_func;
	resp->wake_rsp = cfctrl_resp_func;
	resp->restart_rsp = cfctrl_resp_func;
	resp->radioset_rsp = cfctrl_resp_func;
100 101
	resp->linksetup_rsp = cfcnfg_linkup_rsp;
	resp->reject_rsp = cfcnfg_reject_rsp;
102
	INIT_LIST_HEAD(&this->phys);
103 104 105 106

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

109 110
	return this;
out_of_mem:
J
Joe Perches 已提交
111
	pr_warn("Out of memory\n");
112 113 114

	synchronize_rcu();

115 116 117 118 119 120 121 122 123
	kfree(this->mux);
	kfree(this->ctrl);
	kfree(this);
	return NULL;
}
EXPORT_SYMBOL(cfcnfg_create);

void cfcnfg_remove(struct cfcnfg *cfg)
{
124
	might_sleep();
125
	if (cfg) {
126 127
		synchronize_rcu();

128 129 130 131 132 133 134 135 136 137
		kfree(cfg->mux);
		kfree(cfg->ctrl);
		kfree(cfg);
	}
}

static void cfctrl_resp_func(void)
{
}

138 139 140 141 142 143 144 145 146 147 148
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;
}

149 150 151 152
static void cfctrl_enum_resp(void)
{
}

153
static struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
154 155 156
				  enum cfcnfg_phy_preference phy_pref)
{
	/* Try to match with specified preference */
157 158 159 160 161 162 163
	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;
164 165
	}

166 167 168 169
	/* Otherwise just return something */
	list_for_each_entry_rcu(phy, &cnfg->phys, node)
		if (phy->up)
			return &phy->dev_info;
170 171 172 173

	return NULL;
}

174
static int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
175
{
176 177 178 179 180
	struct cfcnfg_phyinfo *phy;

	list_for_each_entry_rcu(phy, &cnfg->phys, node)
		if (phy->ifindex == ifi && phy->up)
			return phy->id;
181
	return -ENODEV;
182 183
}

184
int caif_disconnect_client(struct net *net, struct cflayer *adap_layer)
185 186 187
{
	u8 channel_id = 0;
	int ret = 0;
188
	struct cflayer *servl = NULL;
189
	struct cfcnfg *cfg = get_cfcnfg(net);
190

191
	caif_assert(adap_layer != NULL);
192

193
	channel_id = adap_layer->id;
194
	if (adap_layer->dn == NULL || channel_id == 0) {
195
		pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n");
196 197 198
		ret = -ENOTCONN;
		goto end;
	}
199 200

	servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
201
	if (servl == NULL) {
202 203 204
		pr_err("PROTOCOL ERROR - "
				"Error removing service_layer Channel_Id(%d)",
				channel_id);
205 206 207
		ret = -EINVAL;
		goto end;
	}
208 209 210

	ret = cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);

211
end:
212 213 214 215
	cfctrl_cancel_req(cfg->ctrl, adap_layer);

	/* Do RCU sync before initiating cleanup */
	synchronize_rcu();
216 217
	if (adap_layer->ctrlcmd != NULL)
		adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
218 219 220
	return ret;

}
221
EXPORT_SYMBOL(caif_disconnect_client);
222

223
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
224 225 226
{
}

S
Stephen Hemminger 已提交
227
static const int protohead[CFCTRL_SRV_MASK] = {
228 229 230 231 232 233 234
	[CFCTRL_SRV_VEI] = 4,
	[CFCTRL_SRV_DATAGRAM] = 7,
	[CFCTRL_SRV_UTIL] = 4,
	[CFCTRL_SRV_RFM] = 3,
	[CFCTRL_SRV_DBG] = 3,
};

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 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321

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,
322 323
				int *proto_head,
				int *proto_tail)
324 325
{
	struct cflayer *frml;
326 327
	struct cfcnfg_phyinfo *phy;
	int err;
328 329 330
	struct cfctrl_link_param param;
	struct cfcnfg *cfg = get_cfcnfg(net);
	caif_assert(cfg != NULL);
331 332

	rcu_read_lock();
333 334 335 336 337
	err = caif_connect_req_to_link_param(cfg, conn_req, &param);
	if (err)
		goto unlock;

	phy = cfcnfg_get_phyinfo_rcu(cfg, param.phyid);
338 339 340 341 342 343
	if (!phy) {
		err = -ENODEV;
		goto unlock;
	}
	err = -EINVAL;

344
	if (adap_layer == NULL) {
J
Joe Perches 已提交
345
		pr_err("adap_layer is zero\n");
346
		goto unlock;
347 348
	}
	if (adap_layer->receive == NULL) {
J
Joe Perches 已提交
349
		pr_err("adap_layer->receive is NULL\n");
350
		goto unlock;
351 352
	}
	if (adap_layer->ctrlcmd == NULL) {
J
Joe Perches 已提交
353
		pr_err("adap_layer->ctrlcmd == NULL\n");
354
		goto unlock;
355
	}
356 357 358

	err = -ENODEV;
	frml = phy->frm_layer;
359
	if (frml == NULL) {
J
Joe Perches 已提交
360
		pr_err("Specified PHY type does not exist!\n");
361
		goto unlock;
362
	}
363
	caif_assert(param.phyid == phy->id);
364
	caif_assert(phy->frm_layer->id ==
365
		     param.phyid);
366
	caif_assert(phy->phy_layer->id ==
367
		     param.phyid);
368

369 370
	*ifindex = phy->ifindex;
	*proto_tail = 2;
371
	*proto_head =
372 373

	protohead[param.linktype] + (phy->use_stx ? 1 : 0);
374

375
	rcu_read_unlock();
376

377
	/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
378 379
	cfctrl_enum_req(cfg->ctrl, param.phyid);
	return cfctrl_linkup_request(cfg->ctrl, &param, adap_layer);
380 381 382 383

unlock:
	rcu_read_unlock();
	return err;
384
}
385
EXPORT_SYMBOL(caif_connect_client);
386

387
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
388 389 390 391 392 393 394 395
			     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
396
cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
397
		  u8 phyid, struct cflayer *adapt_layer)
398 399 400 401
{
	struct cfcnfg *cnfg = container_obj(layer);
	struct cflayer *servicel = NULL;
	struct cfcnfg_phyinfo *phyinfo;
402 403
	struct net_device *netdev;

404 405
	rcu_read_lock();

406
	if (adapt_layer == NULL) {
407 408
		pr_debug("link setup response but no client exist,"
				"send linkdown back\n");
409
		cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
410
		goto unlock;
411 412 413 414
	}

	caif_assert(cnfg != NULL);
	caif_assert(phyid != 0);
415 416 417 418 419 420 421 422 423

	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);
424 425 426 427
	caif_assert(phyinfo->id == phyid);
	caif_assert(phyinfo->phy_layer != NULL);
	caif_assert(phyinfo->phy_layer->id == phyid);

428
	adapt_layer->id = channel_id;
429 430 431

	switch (serv) {
	case CFCTRL_SRV_VEI:
432
		servicel = cfvei_create(channel_id, &phyinfo->dev_info);
433 434
		break;
	case CFCTRL_SRV_DATAGRAM:
435 436
		servicel = cfdgml_create(channel_id,
					&phyinfo->dev_info);
437 438
		break;
	case CFCTRL_SRV_RFM:
439
		netdev = phyinfo->dev_info.dev;
440
		servicel = cfrfml_create(channel_id, &phyinfo->dev_info,
441
						netdev->mtu);
442 443
		break;
	case CFCTRL_SRV_UTIL:
444
		servicel = cfutill_create(channel_id, &phyinfo->dev_info);
445 446
		break;
	case CFCTRL_SRV_VIDEO:
447
		servicel = cfvidl_create(channel_id, &phyinfo->dev_info);
448 449
		break;
	case CFCTRL_SRV_DBG:
450
		servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
451 452
		break;
	default:
453 454 455
		pr_err("Protocol error. Link setup response "
				"- unknown channel type\n");
		goto unlock;
456 457
	}
	if (!servicel) {
J
Joe Perches 已提交
458
		pr_warn("Out of memory\n");
459
		goto unlock;
460 461
	}
	layer_set_dn(servicel, cnfg->mux);
462
	cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
463 464
	layer_set_up(servicel, adapt_layer);
	layer_set_dn(adapt_layer, servicel);
465 466 467

	rcu_read_unlock();

468
	servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
469 470 471
	return;
unlock:
	rcu_read_unlock();
472 473 474 475
}

void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
476
		     struct net_device *dev, struct cflayer *phy_layer,
477
		     enum cfcnfg_phy_preference pref,
478 479 480 481
		     bool fcs, bool stx)
{
	struct cflayer *frml;
	struct cflayer *phy_driver = NULL;
482
	struct cfcnfg_phyinfo *phyinfo;
483
	int i;
484
	u8 phyid;
485

486
	mutex_lock(&cnfg->lock);
487

488 489 490 491 492 493 494
	/* 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;
495
	}
496 497 498 499 500
	pr_warn("Too many CAIF Link Layers (max 6)\n");
	goto out;

got_phyid:
	phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
501 502 503 504

	switch (phy_type) {
	case CFPHYTYPE_FRAG:
		phy_driver =
505
		    cfserl_create(CFPHYTYPE_FRAG, phyid, stx);
506
		if (!phy_driver) {
J
Joe Perches 已提交
507
			pr_warn("Out of memory\n");
508
			goto out;
509 510 511 512 513 514
		}
		break;
	case CFPHYTYPE_CAIF:
		phy_driver = NULL;
		break;
	default:
515
		goto out;
516
	}
517 518 519 520 521 522 523 524 525
	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;
	phyinfo->use_stx = stx;
	phyinfo->use_fcs = fcs;
526

527
	phy_layer->type = phy_type;
528 529
	frml = cffrml_create(phyid, fcs);

530
	if (!frml) {
J
Joe Perches 已提交
531
		pr_warn("Out of memory\n");
532 533
		kfree(phyinfo);
		goto out;
534
	}
535
	phyinfo->frm_layer = frml;
536 537 538
	layer_set_up(frml, cnfg->mux);

	if (phy_driver != NULL) {
539
		phy_driver->id = phyid;
540 541 542 543 544 545 546 547
		layer_set_dn(frml, phy_driver);
		layer_set_up(phy_driver, frml);
		layer_set_dn(phy_driver, phy_layer);
		layer_set_up(phy_layer, phy_driver);
	} else {
		layer_set_dn(frml, phy_layer);
		layer_set_up(phy_layer, frml);
	}
548 549 550 551

	list_add_rcu(&phyinfo->node, &cnfg->phys);
out:
	mutex_unlock(&cnfg->lock);
552 553 554
}
EXPORT_SYMBOL(cfcnfg_add_phy_layer);

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
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);

587 588 589 590
int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
{
	struct cflayer *frml, *frml_dn;
	u16 phyid;
591 592 593 594 595 596
	struct cfcnfg_phyinfo *phyinfo;

	might_sleep();

	mutex_lock(&cnfg->lock);

597
	phyid = phy_layer->id;
598 599
	phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid);

600 601
	if (phyinfo == NULL) {
		mutex_unlock(&cnfg->lock);
602
		return 0;
603
	}
604 605
	caif_assert(phyid == phyinfo->id);
	caif_assert(phy_layer == phyinfo->phy_layer);
606
	caif_assert(phy_layer->id == phyid);
607 608
	caif_assert(phyinfo->frm_layer->id == phyid);

609 610 611
	list_del_rcu(&phyinfo->node);
	synchronize_rcu();

612 613 614
	/* Fail if reference count is not zero */
	if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) {
		pr_info("Wait for device inuse\n");
615
		list_add_rcu(&phyinfo->node, &cnfg->phys);
616 617 618 619
		mutex_unlock(&cnfg->lock);
		return -EAGAIN;
	}

620
	frml = phyinfo->frm_layer;
621 622 623 624 625 626 627 628
	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);
629 630 631 632

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

633
	cffrml_free(frml);
634 635 636
	kfree(phyinfo);
	mutex_unlock(&cnfg->lock);

637 638 639
	return 0;
}
EXPORT_SYMBOL(cfcnfg_del_phy_layer);