Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

caif: Protected in-flight packets using dev or sock refcont.



CAIF Socket Layer and ip-interface registers reference counters
in CAIF service layer. The functions sock_hold, sock_put and
dev_hold, dev_put are used by CAIF Stack to protect from freeing
memory while packets are in-flight.

Signed-off-by: default avatarSjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 43e36921
Loading
Loading
Loading
Loading
+29 −0
Original line number Original line Diff line number Diff line
@@ -73,6 +73,23 @@ int caif_connect_client(struct caif_connect_request *conn_req,
 */
 */
int caif_disconnect_client(struct cflayer *client_layer);
int caif_disconnect_client(struct cflayer *client_layer);


/**
 * caif_client_register_refcnt - register ref-count functions provided by client.
 *
 * @adapt_layer: Client layer using CAIF Stack.
 * @hold:	Function provided by client layer increasing ref-count
 * @put:	Function provided by client layer decreasing ref-count
 *
 * Client of the CAIF Stack must register functions for reference counting.
 * These functions are called by the CAIF Stack for every upstream packet,
 * and must therefore be implemented efficiently.
 *
 * Client should call caif_free_client when reference count degrease to zero.
 */

void caif_client_register_refcnt(struct cflayer *adapt_layer,
					void (*hold)(struct cflayer *lyr),
					void (*put)(struct cflayer *lyr));
/**
/**
 * caif_connect_req_to_link_param - Translate configuration parameters
 * caif_connect_req_to_link_param - Translate configuration parameters
 *				    from socket format to internal format.
 *				    from socket format to internal format.
@@ -83,8 +100,20 @@ int caif_disconnect_client(struct cflayer *client_layer);
 *			 setting up channels.
 *			 setting up channels.
 *
 *
 */
 */

int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
				   struct caif_connect_request *con_req,
				   struct caif_connect_request *con_req,
				   struct cfctrl_link_param *setup_param);
				   struct cfctrl_link_param *setup_param);


/**
 * caif_free_client - Free memory used to manage the client in the CAIF Stack.
 *
 * @client_layer: Client layer to be removed.
 *
 * This function must be called from client layer in order to free memory.
 * Caller must guarantee that no packets are in flight upstream when calling
 * this function.
 */
void caif_free_client(struct cflayer *adap_layer);

#endif /* CAIF_DEV_H_ */
#endif /* CAIF_DEV_H_ */
+17 −2
Original line number Original line Diff line number Diff line
@@ -209,6 +209,18 @@ static int caif_sktrecv_cb(struct cflayer *layr, struct cfpkt *pkt)
	return 0;
	return 0;
}
}


static void cfsk_hold(struct cflayer *layr)
{
	struct caifsock *cf_sk = container_of(layr, struct caifsock, layer);
	sock_hold(&cf_sk->sk);
}

static void cfsk_put(struct cflayer *layr)
{
	struct caifsock *cf_sk = container_of(layr, struct caifsock, layer);
	sock_put(&cf_sk->sk);
}

/* Packet Control Callback function called from CAIF */
/* Packet Control Callback function called from CAIF */
static void caif_ctrl_cb(struct cflayer *layr,
static void caif_ctrl_cb(struct cflayer *layr,
				enum caif_ctrlcmd flow,
				enum caif_ctrlcmd flow,
@@ -232,6 +244,8 @@ static void caif_ctrl_cb(struct cflayer *layr,


	case CAIF_CTRLCMD_INIT_RSP:
	case CAIF_CTRLCMD_INIT_RSP:
		/* We're now connected */
		/* We're now connected */
		caif_client_register_refcnt(&cf_sk->layer,
						cfsk_hold, cfsk_put);
		dbfs_atomic_inc(&cnt.num_connect_resp);
		dbfs_atomic_inc(&cnt.num_connect_resp);
		cf_sk->sk.sk_state = CAIF_CONNECTED;
		cf_sk->sk.sk_state = CAIF_CONNECTED;
		set_tx_flow_on(cf_sk);
		set_tx_flow_on(cf_sk);
@@ -242,7 +256,6 @@ static void caif_ctrl_cb(struct cflayer *layr,
		/* We're now disconnected */
		/* We're now disconnected */
		cf_sk->sk.sk_state = CAIF_DISCONNECTED;
		cf_sk->sk.sk_state = CAIF_DISCONNECTED;
		cf_sk->sk.sk_state_change(&cf_sk->sk);
		cf_sk->sk.sk_state_change(&cf_sk->sk);
		cfcnfg_release_adap_layer(&cf_sk->layer);
		break;
		break;


	case CAIF_CTRLCMD_INIT_FAIL_RSP:
	case CAIF_CTRLCMD_INIT_FAIL_RSP:
@@ -837,8 +850,10 @@ 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(&cf_sk->conn_req,
				&cf_sk->layer, &ifindex, &headroom, &tailroom);
				&cf_sk->layer, &ifindex, &headroom, &tailroom);

	if (err < 0) {
	if (err < 0) {
		cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
		cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
		cf_sk->sk.sk_state = CAIF_DISCONNECTED;
		cf_sk->sk.sk_state = CAIF_DISCONNECTED;
@@ -940,7 +955,6 @@ static int caif_release(struct socket *sock)
	wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP);
	wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP);


	sock_orphan(sk);
	sock_orphan(sk);
	cf_sk->layer.dn = NULL;
	sk_stream_kill_queues(&cf_sk->sk);
	sk_stream_kill_queues(&cf_sk->sk);
	release_sock(sk);
	release_sock(sk);
	sock_put(sk);
	sock_put(sk);
@@ -1036,6 +1050,7 @@ static void caif_sock_destructor(struct sock *sk)
	}
	}
	sk_stream_kill_queues(&cf_sk->sk);
	sk_stream_kill_queues(&cf_sk->sk);
	dbfs_atomic_dec(&cnt.caif_nr_socks);
	dbfs_atomic_dec(&cnt.caif_nr_socks);
	caif_free_client(&cf_sk->layer);
}
}


static int caif_create(struct net *net, struct socket *sock, int protocol,
static int caif_create(struct net *net, struct socket *sock, int protocol,
+26 −2
Original line number Original line Diff line number Diff line
@@ -153,6 +153,18 @@ static void close_work(struct work_struct *work)
}
}
static DECLARE_WORK(close_worker, close_work);
static DECLARE_WORK(close_worker, close_work);


static void chnl_hold(struct cflayer *lyr)
{
	struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl);
	dev_hold(priv->netdev);
}

static void chnl_put(struct cflayer *lyr)
{
	struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl);
	dev_put(priv->netdev);
}

static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
				int phyid)
				int phyid)
{
{
@@ -190,6 +202,7 @@ static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
		netif_wake_queue(priv->netdev);
		netif_wake_queue(priv->netdev);
		break;
		break;
	case CAIF_CTRLCMD_INIT_RSP:
	case CAIF_CTRLCMD_INIT_RSP:
		caif_client_register_refcnt(&priv->chnl, chnl_hold, chnl_put);
		priv->state = CAIF_CONNECTED;
		priv->state = CAIF_CONNECTED;
		priv->flowenabled = true;
		priv->flowenabled = true;
		netif_wake_queue(priv->netdev);
		netif_wake_queue(priv->netdev);
@@ -373,11 +386,18 @@ static const struct net_device_ops netdev_ops = {
	.ndo_start_xmit = chnl_net_start_xmit,
	.ndo_start_xmit = chnl_net_start_xmit,
};
};


static void chnl_net_destructor(struct net_device *dev)
{
	struct chnl_net *priv = netdev_priv(dev);
	caif_free_client(&priv->chnl);
	free_netdev(dev);
}

static void ipcaif_net_setup(struct net_device *dev)
static void ipcaif_net_setup(struct net_device *dev)
{
{
	struct chnl_net *priv;
	struct chnl_net *priv;
	dev->netdev_ops = &netdev_ops;
	dev->netdev_ops = &netdev_ops;
	dev->destructor = free_netdev;
	dev->destructor = chnl_net_destructor;
	dev->flags |= IFF_NOARP;
	dev->flags |= IFF_NOARP;
	dev->flags |= IFF_POINTOPOINT;
	dev->flags |= IFF_POINTOPOINT;
	dev->mtu = GPRS_PDP_MTU;
	dev->mtu = GPRS_PDP_MTU;
@@ -391,7 +411,7 @@ static void ipcaif_net_setup(struct net_device *dev)
	priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW;
	priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW;
	priv->conn_req.priority = CAIF_PRIO_LOW;
	priv->conn_req.priority = CAIF_PRIO_LOW;
	/* Insert illegal value */
	/* Insert illegal value */
	priv->conn_req.sockaddr.u.dgm.connection_id = -1;
	priv->conn_req.sockaddr.u.dgm.connection_id = 0;
	priv->flowenabled = false;
	priv->flowenabled = false;


	init_waitqueue_head(&priv->netmgmt_wq);
	init_waitqueue_head(&priv->netmgmt_wq);
@@ -453,6 +473,10 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
		pr_warn("device rtml registration failed\n");
		pr_warn("device rtml registration failed\n");
	else
	else
		list_add(&caifdev->list_field, &chnl_net_list);
		list_add(&caifdev->list_field, &chnl_net_list);

	/* Take ifindex as connection-id if null */
	if (caifdev->conn_req.sockaddr.u.dgm.connection_id == 0)
		caifdev->conn_req.sockaddr.u.dgm.connection_id = dev->ifindex;
	return ret;
	return ret;
}
}