Commit bee925db authored by sjur.brandeland@stericsson.com's avatar sjur.brandeland@stericsson.com Committed by David S. Miller

caif: prepare support for namespaces

Use struct net to reference CAIF configuration object instead of static variables.
Refactor functions caif_connect_client, caif_disconnect_client and squach
files cfcnfg.c and caif_config_utils.
Signed-off-by: default avatarSjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b3ccfbe4
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <net/caif/cfcnfg.h> #include <net/caif/cfcnfg.h>
#include <linux/caif/caif_socket.h> #include <linux/caif/caif_socket.h>
#include <linux/if.h> #include <linux/if.h>
#include <linux/net.h>
/** /**
* struct caif_param - CAIF parameters. * struct caif_param - CAIF parameters.
...@@ -62,16 +63,18 @@ struct caif_connect_request { ...@@ -62,16 +63,18 @@ struct caif_connect_request {
* E.g. CAIF Socket will call this function for each socket it connects * E.g. CAIF Socket will call this function for each socket it connects
* and have one client_layer instance for each socket. * and have one client_layer instance for each socket.
*/ */
int caif_connect_client(struct caif_connect_request *conn_req, int caif_connect_client(struct net *net,
struct caif_connect_request *conn_req,
struct cflayer *client_layer, int *ifindex, struct cflayer *client_layer, int *ifindex,
int *headroom, int *tailroom); int *headroom, int *tailroom);
/** /**
* caif_disconnect_client - Disconnects a client from the CAIF stack. * caif_disconnect_client - Disconnects a client from the CAIF stack.
* *
* @client_layer: Client layer to be removed. * @client_layer: Client layer to be disconnected.
*/ */
int caif_disconnect_client(struct cflayer *client_layer); int caif_disconnect_client(struct net *net, struct cflayer *client_layer);
/** /**
* caif_client_register_refcnt - register ref-count functions provided by client. * caif_client_register_refcnt - register ref-count functions provided by client.
...@@ -90,21 +93,6 @@ int caif_disconnect_client(struct cflayer *client_layer); ...@@ -90,21 +93,6 @@ int caif_disconnect_client(struct cflayer *client_layer);
void caif_client_register_refcnt(struct cflayer *adapt_layer, void caif_client_register_refcnt(struct cflayer *adapt_layer,
void (*hold)(struct cflayer *lyr), void (*hold)(struct cflayer *lyr),
void (*put)(struct cflayer *lyr)); void (*put)(struct cflayer *lyr));
/**
* caif_connect_req_to_link_param - Translate configuration parameters
* from socket format to internal format.
* @cnfg: Pointer to configuration handler
* @con_req: Configuration parameters supplied in function
* caif_connect_client
* @channel_setup_param: Parameters supplied to the CAIF Core stack for
* setting up channels.
*
*/
int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
struct caif_connect_request *con_req,
struct cfctrl_link_param *setup_param);
/** /**
* caif_free_client - Free memory used to manage the client in the CAIF Stack. * caif_free_client - Free memory used to manage the client in the CAIF Stack.
* *
......
...@@ -45,6 +45,12 @@ enum cfcnfg_phy_preference { ...@@ -45,6 +45,12 @@ enum cfcnfg_phy_preference {
CFPHYPREF_LOOP CFPHYPREF_LOOP
}; };
/**
* cfcnfg_create() - Get the CAIF configuration object given network.
* @net: Network for the CAIF configuration object.
*/
struct cfcnfg *get_cfcnfg(struct net *net);
/** /**
* cfcnfg_create() - Create the CAIF configuration object. * cfcnfg_create() - Create the CAIF configuration object.
*/ */
...@@ -65,17 +71,15 @@ void cfcnfg_remove(struct cfcnfg *cfg); ...@@ -65,17 +71,15 @@ void cfcnfg_remove(struct cfcnfg *cfg);
* @dev: Pointer to link layer device * @dev: Pointer to link layer device
* @phy_layer: Specify the physical layer. The transmit function * @phy_layer: Specify the physical layer. The transmit function
* MUST be set in the structure. * MUST be set in the structure.
* @phyid: The assigned physical ID for this layer, used in
* cfcnfg_add_adapt_layer to specify PHY for the link.
* @pref: The phy (link layer) preference. * @pref: The phy (link layer) preference.
* @fcs: Specify if checksum is used in CAIF Framing Layer. * @fcs: Specify if checksum is used in CAIF Framing Layer.
* @stx: Specify if Start Of Frame extension is used. * @stx: Specify if Start Of Frame eXtention is used.
*/ */
void void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
struct net_device *dev, struct cflayer *phy_layer, struct net_device *dev, struct cflayer *phy_layer,
u16 *phyid, enum cfcnfg_phy_preference pref, enum cfcnfg_phy_preference pref,
bool fcs, bool stx); bool fcs, bool stx);
/** /**
...@@ -87,65 +91,6 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, ...@@ -87,65 +91,6 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
*/ */
int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer); int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer);
/**
* cfcnfg_disconn_adapt_layer - Disconnects an adaptation layer.
*
* @cnfg: Pointer to a CAIF configuration object, created by
* cfcnfg_create().
* @adap_layer: Adaptation layer to be removed.
*/
int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg,
struct cflayer *adap_layer);
/**
* cfcnfg_release_adap_layer - Used by client to release the adaptation layer.
*
* @adap_layer: Adaptation layer.
*/
void cfcnfg_release_adap_layer(struct cflayer *adap_layer);
/**
* cfcnfg_add_adaptation_layer - Add an adaptation layer to the CAIF stack.
*
* The adaptation Layer is where the interface to application or higher-level
* driver functionality is implemented.
*
* @cnfg: Pointer to a CAIF configuration object, created by
* cfcnfg_create().
* @param: Link setup parameters.
* @adap_layer: Specify the adaptation layer; the receive and
* flow-control functions MUST be set in the structure.
* @ifindex: Link layer interface index used for this connection.
* @proto_head: Protocol head-space needed by CAIF protocol,
* excluding link layer.
* @proto_tail: Protocol tail-space needed by CAIF protocol,
* excluding link layer.
*/
int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
struct cfctrl_link_param *param,
struct cflayer *adap_layer,
int *ifindex,
int *proto_head,
int *proto_tail);
/**
* cfcnfg_get_phyid() - Get physical ID, given type.
* Returns one of the physical interfaces matching the given type.
* Zero if no match is found.
* @cnfg: Configuration object
* @phy_pref: Caif Link Layer preference
*/
struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
enum cfcnfg_phy_preference phy_pref);
/**
* cfcnfg_get_id_from_ifi() - Get the Physical Identifier of ifindex,
* it matches caif physical id with the kernel interface id.
* @cnfg: Configuration object
* @ifi: ifindex obtained from socket.c bindtodevice.
*/
int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi);
/** /**
* cfcnfg_set_phy_state() - Set the state of the physical interface device. * cfcnfg_set_phy_state() - Set the state of the physical interface device.
* @cnfg: Configuration object * @cnfg: Configuration object
......
...@@ -5,7 +5,7 @@ caif-y := caif_dev.o \ ...@@ -5,7 +5,7 @@ caif-y := caif_dev.o \
cffrml.o cfveil.o cfdbgl.o\ cffrml.o cfveil.o cfdbgl.o\
cfserl.o cfdgml.o \ cfserl.o cfdgml.o \
cfrfml.o cfvidl.o cfutill.o \ cfrfml.o cfvidl.o cfutill.o \
cfsrvl.o cfpkt_skbuff.o caif_config_util.o cfsrvl.o cfpkt_skbuff.o
obj-$(CONFIG_CAIF) += caif.o obj-$(CONFIG_CAIF) += caif.o
obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o
......
/*
* Copyright (C) ST-Ericsson AB 2010
* Author: Sjur Brendeland sjur.brandeland@stericsson.com
* License terms: GNU General Public License (GPL) version 2
*/
#include <linux/module.h>
#include <linux/spinlock.h>
#include <net/caif/cfctrl.h>
#include <net/caif/cfcnfg.h>
#include <net/caif/caif_dev.h>
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;
if (s->sockaddr.u.at.type == CAIF_ATTYPE_PLAIN)
l->chtype = 0x02;
else
l->chtype = s->sockaddr.u.at.type;
l->endpoint = 0x00;
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;
}
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
#include <net/caif/caif_device.h> #include <net/caif/caif_device.h>
#include <net/caif/caif_dev.h>
#include <net/caif/caif_layer.h> #include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h> #include <net/caif/cfpkt.h>
#include <net/caif/cfcnfg.h> #include <net/caif/cfcnfg.h>
...@@ -43,11 +42,21 @@ struct caif_device_entry_list { ...@@ -43,11 +42,21 @@ struct caif_device_entry_list {
}; };
struct caif_net { struct caif_net {
struct cfcnfg *cfg;
struct caif_device_entry_list caifdevs; struct caif_device_entry_list caifdevs;
}; };
static int caif_net_id; static int caif_net_id;
static struct cfcnfg *cfg;
struct cfcnfg *get_cfcnfg(struct net *net)
{
struct caif_net *caifn;
BUG_ON(!net);
caifn = net_generic(net, caif_net_id);
BUG_ON(!caifn);
return caifn->cfg;
}
EXPORT_SYMBOL(get_cfcnfg);
static struct caif_device_entry_list *caif_device_list(struct net *net) static struct caif_device_entry_list *caif_device_list(struct net *net)
{ {
...@@ -191,12 +200,17 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, ...@@ -191,12 +200,17 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
struct caif_dev_common *caifdev; struct caif_dev_common *caifdev;
enum cfcnfg_phy_preference pref; enum cfcnfg_phy_preference pref;
enum cfcnfg_phy_type phy_type; enum cfcnfg_phy_type phy_type;
struct cfcnfg *cfg;
struct caif_device_entry_list *caifdevs = struct caif_device_entry_list *caifdevs =
caif_device_list(dev_net(dev)); caif_device_list(dev_net(dev));
if (dev->type != ARPHRD_CAIF) if (dev->type != ARPHRD_CAIF)
return 0; return 0;
cfg = get_cfcnfg(dev_net(dev));
if (cfg == NULL)
return 0;
switch (what) { switch (what) {
case NETDEV_REGISTER: case NETDEV_REGISTER:
caifd = caif_device_alloc(dev); caifd = caif_device_alloc(dev);
...@@ -235,7 +249,6 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, ...@@ -235,7 +249,6 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
phy_type, phy_type,
dev, dev,
&caifd->layer, &caifd->layer,
0,
pref, pref,
caifdev->use_fcs, caifdev->use_fcs,
caifdev->use_stx); caifdev->use_stx);
...@@ -323,35 +336,20 @@ static struct notifier_block caif_device_notifier = { ...@@ -323,35 +336,20 @@ static struct notifier_block caif_device_notifier = {
.priority = 0, .priority = 0,
}; };
int caif_connect_client(struct caif_connect_request *conn_req,
struct cflayer *client_layer, int *ifindex,
int *headroom, int *tailroom)
{
struct cfctrl_link_param param;
int ret;
ret = caif_connect_req_to_link_param(cfg, conn_req, &param);
if (ret)
return ret;
/* Hook up the adaptation layer. */
return cfcnfg_add_adaptation_layer(cfg, &param,
client_layer, ifindex,
headroom, tailroom);
}
EXPORT_SYMBOL(caif_connect_client);
int caif_disconnect_client(struct cflayer *adap_layer)
{
return cfcnfg_disconn_adapt_layer(cfg, adap_layer);
}
EXPORT_SYMBOL(caif_disconnect_client);
/* Per-namespace Caif devices handling */ /* Per-namespace Caif devices handling */
static int caif_init_net(struct net *net) static int caif_init_net(struct net *net)
{ {
struct caif_net *caifn = net_generic(net, caif_net_id); struct caif_net *caifn = net_generic(net, caif_net_id);
BUG_ON(!caifn);
INIT_LIST_HEAD(&caifn->caifdevs.list); INIT_LIST_HEAD(&caifn->caifdevs.list);
mutex_init(&caifn->caifdevs.lock); mutex_init(&caifn->caifdevs.lock);
caifn->cfg = cfcnfg_create();
if (!caifn->cfg) {
pr_warn("can't create cfcnfg\n");
return -ENOMEM;
}
return 0; return 0;
} }
...@@ -360,10 +358,17 @@ static void caif_exit_net(struct net *net) ...@@ -360,10 +358,17 @@ static void caif_exit_net(struct net *net)
struct caif_device_entry *caifd, *tmp; struct caif_device_entry *caifd, *tmp;
struct caif_device_entry_list *caifdevs = struct caif_device_entry_list *caifdevs =
caif_device_list(net); caif_device_list(net);
struct cfcnfg *cfg;
rtnl_lock(); rtnl_lock();
mutex_lock(&caifdevs->lock); mutex_lock(&caifdevs->lock);
cfg = get_cfcnfg(net);
if (cfg == NULL) {
mutex_unlock(&caifdevs->lock);
return;
}
list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) { list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) {
int i = 0; int i = 0;
list_del_rcu(&caifd->list); list_del_rcu(&caifd->list);
...@@ -382,7 +387,7 @@ static void caif_exit_net(struct net *net) ...@@ -382,7 +387,7 @@ static void caif_exit_net(struct net *net)
free_percpu(caifd->pcpu_refcnt); free_percpu(caifd->pcpu_refcnt);
kfree(caifd); kfree(caifd);
} }
cfcnfg_remove(cfg);
mutex_unlock(&caifdevs->lock); mutex_unlock(&caifdevs->lock);
rtnl_unlock(); rtnl_unlock();
...@@ -400,32 +405,22 @@ static int __init caif_device_init(void) ...@@ -400,32 +405,22 @@ static int __init caif_device_init(void)
{ {
int result; int result;
cfg = cfcnfg_create();
if (!cfg) {
pr_warn("can't create cfcnfg\n");
goto err_cfcnfg_create_failed;
}
result = register_pernet_device(&caif_net_ops); result = register_pernet_device(&caif_net_ops);
if (result) { if (result)
kfree(cfg);
cfg = NULL;
return result; return result;
}
dev_add_pack(&caif_packet_type);
register_netdevice_notifier(&caif_device_notifier); register_netdevice_notifier(&caif_device_notifier);
dev_add_pack(&caif_packet_type);
return result; return result;
err_cfcnfg_create_failed:
return -ENODEV;
} }
static void __exit caif_device_exit(void) static void __exit caif_device_exit(void)
{ {
dev_remove_pack(&caif_packet_type);
unregister_pernet_device(&caif_net_ops); unregister_pernet_device(&caif_net_ops);
unregister_netdevice_notifier(&caif_device_notifier); unregister_netdevice_notifier(&caif_device_notifier);
cfcnfg_remove(cfg); dev_remove_pack(&caif_packet_type);
} }
module_init(caif_device_init); module_init(caif_device_init);
......
...@@ -810,7 +810,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -810,7 +810,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
sk->sk_state == CAIF_DISCONNECTED); sk->sk_state == CAIF_DISCONNECTED);
if (sk->sk_shutdown & SHUTDOWN_MASK) { if (sk->sk_shutdown & SHUTDOWN_MASK) {
/* Allow re-connect after SHUTDOWN_IND */ /* Allow re-connect after SHUTDOWN_IND */
caif_disconnect_client(&cf_sk->layer); caif_disconnect_client(sock_net(sk), &cf_sk->layer);
break; break;
} }
/* No reconnect on a seqpacket socket */ /* No reconnect on a seqpacket socket */
...@@ -851,7 +851,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -851,7 +851,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
dbfs_atomic_inc(&cnt.num_connect_req); dbfs_atomic_inc(&cnt.num_connect_req);
cf_sk->layer.receive = caif_sktrecv_cb; cf_sk->layer.receive = caif_sktrecv_cb;
err = caif_connect_client(&cf_sk->conn_req, err = caif_connect_client(sock_net(sk), &cf_sk->conn_req,
&cf_sk->layer, &ifindex, &headroom, &tailroom); &cf_sk->layer, &ifindex, &headroom, &tailroom);
if (err < 0) { if (err < 0) {
...@@ -949,7 +949,7 @@ static int caif_release(struct socket *sock) ...@@ -949,7 +949,7 @@ static int caif_release(struct socket *sock)
if (cf_sk->sk.sk_socket->state == SS_CONNECTED || if (cf_sk->sk.sk_socket->state == SS_CONNECTED ||
cf_sk->sk.sk_socket->state == SS_CONNECTING) cf_sk->sk.sk_socket->state == SS_CONNECTING)
res = caif_disconnect_client(&cf_sk->layer); res = caif_disconnect_client(sock_net(sk), &cf_sk->layer);
cf_sk->sk.sk_socket->state = SS_DISCONNECTING; cf_sk->sk.sk_socket->state = SS_DISCONNECTING;
wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP); wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP);
......
...@@ -150,7 +150,7 @@ static void cfctrl_enum_resp(void) ...@@ -150,7 +150,7 @@ static void cfctrl_enum_resp(void)
{ {
} }
struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, static struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
enum cfcnfg_phy_preference phy_pref) enum cfcnfg_phy_preference phy_pref)
{ {
/* Try to match with specified preference */ /* Try to match with specified preference */
...@@ -171,7 +171,7 @@ struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, ...@@ -171,7 +171,7 @@ struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
return NULL; return NULL;
} }
int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi) static int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
{ {
struct cfcnfg_phyinfo *phy; struct cfcnfg_phyinfo *phy;
...@@ -181,11 +181,12 @@ int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi) ...@@ -181,11 +181,12 @@ int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
return -ENODEV; return -ENODEV;
} }
int cfcnfg_disconn_adapt_layer(struct cfcnfg *cfg, struct cflayer *adap_layer) int caif_disconnect_client(struct net *net, struct cflayer *adap_layer)
{ {
u8 channel_id = 0; u8 channel_id = 0;
int ret = 0; int ret = 0;
struct cflayer *servl = NULL; struct cflayer *servl = NULL;
struct cfcnfg *cfg = get_cfcnfg(net);
caif_assert(adap_layer != NULL); caif_assert(adap_layer != NULL);
...@@ -217,14 +218,7 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cfg, struct cflayer *adap_layer) ...@@ -217,14 +218,7 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cfg, struct cflayer *adap_layer)
return ret; return ret;
} }
EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer); EXPORT_SYMBOL(caif_disconnect_client);
void cfcnfg_release_adap_layer(struct cflayer *adap_layer)
{
if (adap_layer->dn)
cfsrvl_put(adap_layer->dn);
}
EXPORT_SYMBOL(cfcnfg_release_adap_layer);
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id) static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
{ {
...@@ -238,19 +232,109 @@ static const int protohead[CFCTRL_SRV_MASK] = { ...@@ -238,19 +232,109 @@ static const int protohead[CFCTRL_SRV_MASK] = {
[CFCTRL_SRV_DBG] = 3, [CFCTRL_SRV_DBG] = 3,
}; };
int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
struct cfctrl_link_param *param, static int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
struct cflayer *adap_layer, struct caif_connect_request *s,
int *ifindex, 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,
int *proto_head, int *proto_head,
int *proto_tail) int *proto_tail)
{ {
struct cflayer *frml; struct cflayer *frml;
struct cfcnfg_phyinfo *phy; struct cfcnfg_phyinfo *phy;
int err; int err;
struct cfctrl_link_param param;
struct cfcnfg *cfg = get_cfcnfg(net);
caif_assert(cfg != NULL);
rcu_read_lock(); rcu_read_lock();
phy = cfcnfg_get_phyinfo_rcu(cnfg, param->phyid); err = caif_connect_req_to_link_param(cfg, conn_req, &param);
if (err)
goto unlock;
phy = cfcnfg_get_phyinfo_rcu(cfg, param.phyid);
if (!phy) { if (!phy) {
err = -ENODEV; err = -ENODEV;
goto unlock; goto unlock;
...@@ -276,28 +360,29 @@ int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, ...@@ -276,28 +360,29 @@ int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
pr_err("Specified PHY type does not exist!\n"); pr_err("Specified PHY type does not exist!\n");
goto unlock; goto unlock;
} }
caif_assert(param->phyid == phy->id); caif_assert(param.phyid == phy->id);
caif_assert(phy->frm_layer->id == caif_assert(phy->frm_layer->id ==
param->phyid); param.phyid);
caif_assert(phy->phy_layer->id == caif_assert(phy->phy_layer->id ==
param->phyid); param.phyid);
*ifindex = phy->ifindex; *ifindex = phy->ifindex;
*proto_tail = 2; *proto_tail = 2;
*proto_head = *proto_head =
protohead[param->linktype] + (phy->use_stx ? 1 : 0);
protohead[param.linktype] + (phy->use_stx ? 1 : 0);
rcu_read_unlock(); rcu_read_unlock();
/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */ /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
cfctrl_enum_req(cnfg->ctrl, param->phyid); cfctrl_enum_req(cfg->ctrl, param.phyid);
return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer); return cfctrl_linkup_request(cfg->ctrl, &param, adap_layer);
unlock: unlock:
rcu_read_unlock(); rcu_read_unlock();
return err; return err;
} }
EXPORT_SYMBOL(cfcnfg_add_adaptation_layer); EXPORT_SYMBOL(caif_connect_client);
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
struct cflayer *adapt_layer) struct cflayer *adapt_layer)
...@@ -389,7 +474,7 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, ...@@ -389,7 +474,7 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
void void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
struct net_device *dev, struct cflayer *phy_layer, struct net_device *dev, struct cflayer *phy_layer,
u16 *phy_id, enum cfcnfg_phy_preference pref, enum cfcnfg_phy_preference pref,
bool fcs, bool stx) bool fcs, bool stx)
{ {
struct cflayer *frml; struct cflayer *frml;
...@@ -512,23 +597,26 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) ...@@ -512,23 +597,26 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
phyid = phy_layer->id; phyid = phy_layer->id;
phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid); phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid);
if (phyinfo == NULL) if (phyinfo == NULL) {
mutex_unlock(&cnfg->lock);
return 0; return 0;
}
caif_assert(phyid == phyinfo->id); caif_assert(phyid == phyinfo->id);
caif_assert(phy_layer == phyinfo->phy_layer); caif_assert(phy_layer == phyinfo->phy_layer);
caif_assert(phy_layer->id == phyid); caif_assert(phy_layer->id == phyid);
caif_assert(phyinfo->frm_layer->id == phyid); caif_assert(phyinfo->frm_layer->id == phyid);
list_del_rcu(&phyinfo->node);
synchronize_rcu();
/* Fail if reference count is not zero */ /* Fail if reference count is not zero */
if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) { if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) {
pr_info("Wait for device inuse\n"); pr_info("Wait for device inuse\n");
list_add_rcu(&phyinfo->node, &cnfg->phys);
mutex_unlock(&cnfg->lock); mutex_unlock(&cnfg->lock);
return -EAGAIN; return -EAGAIN;
} }
list_del_rcu(&phyinfo->node);
synchronize_rcu();
frml = phyinfo->frm_layer; frml = phyinfo->frm_layer;
frml_dn = frml->dn; frml_dn = frml->dn;
cffrml_set_uplayer(frml, NULL); cffrml_set_uplayer(frml, NULL);
...@@ -539,8 +627,6 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) ...@@ -539,8 +627,6 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
} }
layer_set_up(phy_layer, NULL); layer_set_up(phy_layer, NULL);
if (phyinfo->phy_layer != frml_dn) if (phyinfo->phy_layer != frml_dn)
kfree(frml_dn); kfree(frml_dn);
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/caif/if_caif.h> #include <linux/caif/if_caif.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include <net/caif/caif_layer.h> #include <net/caif/caif_layer.h>
#include <net/caif/cfcnfg.h>
#include <net/caif/cfpkt.h> #include <net/caif/cfpkt.h>
#include <net/caif/caif_dev.h> #include <net/caif/caif_dev.h>
...@@ -270,8 +269,9 @@ static int chnl_net_open(struct net_device *dev) ...@@ -270,8 +269,9 @@ static int chnl_net_open(struct net_device *dev)
if (priv->state != CAIF_CONNECTING) { if (priv->state != CAIF_CONNECTING) {
priv->state = CAIF_CONNECTING; priv->state = CAIF_CONNECTING;
result = caif_connect_client(&priv->conn_req, &priv->chnl, result = caif_connect_client(dev_net(dev), &priv->conn_req,
&llifindex, &headroom, &tailroom); &priv->chnl, &llifindex,
&headroom, &tailroom);
if (result != 0) { if (result != 0) {
pr_debug("err: " pr_debug("err: "
"Unable to register and open device," "Unable to register and open device,"
...@@ -327,7 +327,7 @@ static int chnl_net_open(struct net_device *dev) ...@@ -327,7 +327,7 @@ static int chnl_net_open(struct net_device *dev)
if (result == 0) { if (result == 0) {
pr_debug("connect timeout\n"); pr_debug("connect timeout\n");
caif_disconnect_client(&priv->chnl); caif_disconnect_client(dev_net(dev), &priv->chnl);
priv->state = CAIF_DISCONNECTED; priv->state = CAIF_DISCONNECTED;
pr_debug("state disconnected\n"); pr_debug("state disconnected\n");
result = -ETIMEDOUT; result = -ETIMEDOUT;
...@@ -343,7 +343,7 @@ static int chnl_net_open(struct net_device *dev) ...@@ -343,7 +343,7 @@ static int chnl_net_open(struct net_device *dev)
return 0; return 0;
error: error:
caif_disconnect_client(&priv->chnl); caif_disconnect_client(dev_net(dev), &priv->chnl);
priv->state = CAIF_DISCONNECTED; priv->state = CAIF_DISCONNECTED;
pr_debug("state disconnected\n"); pr_debug("state disconnected\n");
return result; return result;
...@@ -357,7 +357,7 @@ static int chnl_net_stop(struct net_device *dev) ...@@ -357,7 +357,7 @@ static int chnl_net_stop(struct net_device *dev)
ASSERT_RTNL(); ASSERT_RTNL();
priv = netdev_priv(dev); priv = netdev_priv(dev);
priv->state = CAIF_DISCONNECTED; priv->state = CAIF_DISCONNECTED;
caif_disconnect_client(&priv->chnl); caif_disconnect_client(dev_net(dev), &priv->chnl);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment