#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();
 }