#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/caif/caif_socket.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <net/sock.h>
#include <net/tcp_states.h>
#include <net/caif/caif_layer.h>
if (sk->sk_shutdown & SHUTDOWN_MASK) {
/* Allow re-connect after SHUTDOWN_IND */
caif_disconnect_client(sock_net(sk), &cf_sk->layer);
+ caif_free_client(&cf_sk->layer);
break;
}
/* No reconnect on a seqpacket socket */
{
struct sock *sk = sock->sk;
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
- int res = 0;
if (!sk)
return 0;
sk->sk_state = CAIF_DISCONNECTED;
sk->sk_shutdown = SHUTDOWN_MASK;
- if (cf_sk->sk.sk_socket->state == SS_CONNECTED ||
- cf_sk->sk.sk_socket->state == SS_CONNECTING)
- res = caif_disconnect_client(sock_net(sk), &cf_sk->layer);
-
+ caif_disconnect_client(sock_net(sk), &cf_sk->layer);
cf_sk->sk.sk_socket->state = SS_DISCONNECTING;
wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP);
sk_stream_kill_queues(&cf_sk->sk);
release_sock(sk);
sock_put(sk);
- return res;
+ return 0;
}
/* Copied from af_unix.c:unix_poll(), added CAIF tx_flow handling */
set_rx_flow_on(cf_sk);
/* Set default options on configuration */
- cf_sk->sk.sk_priority= CAIF_PRIO_NORMAL;
+ cf_sk->sk.sk_priority = CAIF_PRIO_NORMAL;
cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY;
cf_sk->conn_req.protocol = protocol;
/* Increase the number of sockets created. */
int caif_disconnect_client(struct net *net, struct cflayer *adap_layer)
{
- u8 channel_id = 0;
- int ret = 0;
- struct cflayer *servl = NULL;
+ u8 channel_id;
struct cfcnfg *cfg = get_cfcnfg(net);
caif_assert(adap_layer != NULL);
-
- channel_id = adap_layer->id;
- if (adap_layer->dn == NULL || channel_id == 0) {
- pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n");
- ret = -ENOTCONN;
- goto end;
- }
-
- servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
- if (servl == NULL) {
- pr_err("PROTOCOL ERROR - "
- "Error removing service_layer Channel_Id(%d)",
- channel_id);
- ret = -EINVAL;
- goto end;
- }
-
- ret = cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);
-
-end:
cfctrl_cancel_req(cfg->ctrl, adap_layer);
+ channel_id = adap_layer->id;
+ if (channel_id != 0) {
+ struct cflayer *servl;
+ servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
+ if (servl != NULL)
+ layer_set_up(servl, NULL);
+ } else
+ pr_debug("nothing to disconnect\n");
+ cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);
/* Do RCU sync before initiating cleanup */
synchronize_rcu();
if (adap_layer->ctrlcmd != NULL)
adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
- return ret;
+ return 0;
}
EXPORT_SYMBOL(caif_disconnect_client);
struct cfcnfg_phyinfo *phyinfo;
struct net_device *netdev;
+ 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;
+ }
+
rcu_read_lock();
if (adapt_layer == NULL) {
phyinfo->use_stx = stx;
phyinfo->use_fcs = fcs;
- phy_layer->type = phy_type;
frml = cffrml_create(phyid, fcs);
if (!frml) {
return &this->layer;
}
-int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid)
-{
- struct cfmuxl *muxl = container_obj(layr);
-
- spin_lock_bh(&muxl->receive_lock);
- list_add_rcu(&up->node, &muxl->srvl_list);
- spin_unlock_bh(&muxl->receive_lock);
- return 0;
-}
-
int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid)
{
struct cfmuxl *muxl = (struct cfmuxl *) layr;
return NULL;
}
+int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid)
+{
+ struct cfmuxl *muxl = container_obj(layr);
+ struct cflayer *old;
+
+ spin_lock_bh(&muxl->receive_lock);
+
+ /* Two entries with same id is wrong, so remove old layer from mux */
+ old = get_from_id(&muxl->srvl_list, linkid);
+ if (old != NULL)
+ list_del_rcu(&old->node);
+
+ list_add_rcu(&up->node, &muxl->srvl_list);
+ spin_unlock_bh(&muxl->receive_lock);
+
+ return 0;
+}
+
struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid)
{
struct cfmuxl *muxl = container_obj(layr);
struct cfmuxl *muxl = container_obj(layr);
int idx = id % UP_CACHE_SIZE;
+ if (id == 0) {
+ pr_warn("Trying to remove control layer\n");
+ return NULL;
+ }
+
spin_lock_bh(&muxl->receive_lock);
up = get_from_id(&muxl->srvl_list, id);
if (up == NULL)
{
struct cfmuxl *muxl = container_obj(layr);
struct cflayer *layer;
+ int idx;
rcu_read_lock();
list_for_each_entry_rcu(layer, &muxl->srvl_list, node) {
- if (cfsrvl_phyid_match(layer, phyid) && layer->ctrlcmd)
+
+ if (cfsrvl_phyid_match(layer, phyid) && layer->ctrlcmd) {
+
+ if ((ctrl == _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND ||
+ ctrl == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND) &&
+ layer->id != 0) {
+
+ idx = layer->id % UP_CACHE_SIZE;
+ spin_lock_bh(&muxl->receive_lock);
+ rcu_assign_pointer(muxl->up_cache[idx], NULL);
+ list_del_rcu(&layer->node);
+ spin_unlock_bh(&muxl->receive_lock);
+ }
/* NOTE: ctrlcmd is not allowed to block */
layer->ctrlcmd(layer, ctrl, phyid);
+ }
}
rcu_read_unlock();
}