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

Commit fb3dbece authored by David S. Miller's avatar David S. Miller
Browse files
parents 12e94471 eaa71b31
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -161,12 +161,30 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, unsigned long l
{
	struct sk_buff *skb;

	release_sock(sk);
	if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) {
		skb_reserve(skb, BT_SKB_RESERVE);
		bt_cb(skb)->incoming  = 0;
	}
	lock_sock(sk);

	if (!skb && *err)
		return NULL;

	*err = sock_error(sk);
	if (*err)
		goto out;

	if (sk->sk_shutdown) {
		*err = -ECONNRESET;
		goto out;
	}

	return skb;

out:
	kfree_skb(skb);
	return NULL;
}

int bt_err(__u16 code);
+29 −33
Original line number Diff line number Diff line
@@ -1441,33 +1441,23 @@ static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb)

static void l2cap_streaming_send(struct sock *sk)
{
	struct sk_buff *skb, *tx_skb;
	struct sk_buff *skb;
	struct l2cap_pinfo *pi = l2cap_pi(sk);
	u16 control, fcs;

	while ((skb = sk->sk_send_head)) {
		tx_skb = skb_clone(skb, GFP_ATOMIC);

		control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
	while ((skb = skb_dequeue(TX_QUEUE(sk)))) {
		control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
		control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
		put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
		put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);

		if (pi->fcs == L2CAP_FCS_CRC16) {
			fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
			put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
			fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
			put_unaligned_le16(fcs, skb->data + skb->len - 2);
		}

		l2cap_do_send(sk, tx_skb);
		l2cap_do_send(sk, skb);

		pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;

		if (skb_queue_is_last(TX_QUEUE(sk), skb))
			sk->sk_send_head = NULL;
		else
			sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);

		skb = skb_dequeue(TX_QUEUE(sk));
		kfree_skb(skb);
	}
}

@@ -1960,6 +1950,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us

	switch (optname) {
	case L2CAP_OPTIONS:
		if (sk->sk_state == BT_CONNECTED) {
			err = -EINVAL;
			break;
		}

		opts.imtu     = l2cap_pi(sk)->imtu;
		opts.omtu     = l2cap_pi(sk)->omtu;
		opts.flush_to = l2cap_pi(sk)->flush_to;
@@ -2771,10 +2766,10 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
		case L2CAP_CONF_MTU:
			if (val < L2CAP_DEFAULT_MIN_MTU) {
				*result = L2CAP_CONF_UNACCEPT;
				pi->omtu = L2CAP_DEFAULT_MIN_MTU;
				pi->imtu = L2CAP_DEFAULT_MIN_MTU;
			} else
				pi->omtu = val;
			l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
				pi->imtu = val;
			l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
			break;

		case L2CAP_CONF_FLUSH_TO:
@@ -3071,6 +3066,17 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
	return 0;
}

static inline void set_default_fcs(struct l2cap_pinfo *pi)
{
	/* FCS is enabled only in ERTM or streaming mode, if one or both
	 * sides request it.
	 */
	if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING)
		pi->fcs = L2CAP_FCS_NONE;
	else if (!(pi->conf_state & L2CAP_CONF_NO_FCS_RECV))
		pi->fcs = L2CAP_FCS_CRC16;
}

static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
{
	struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
@@ -3088,14 +3094,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
	if (!sk)
		return -ENOENT;

	if (sk->sk_state != BT_CONFIG) {
		struct l2cap_cmd_rej rej;

		rej.reason = cpu_to_le16(0x0002);
		l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
				sizeof(rej), &rej);
	if (sk->sk_state == BT_DISCONN)
		goto unlock;
	}

	/* Reject if config buffer is too small. */
	len = cmd_len - sizeof(*req);
@@ -3135,9 +3135,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
		goto unlock;

	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
		if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) ||
		    l2cap_pi(sk)->fcs != L2CAP_FCS_NONE)
			l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16;
		set_default_fcs(l2cap_pi(sk));

		sk->sk_state = BT_CONNECTED;

@@ -3225,9 +3223,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
	l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;

	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
		if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) ||
		    l2cap_pi(sk)->fcs != L2CAP_FCS_NONE)
			l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16;
		set_default_fcs(l2cap_pi(sk));

		sk->sk_state = BT_CONNECTED;
		l2cap_pi(sk)->next_tx_seq = 0;
+4 −0
Original line number Diff line number Diff line
@@ -82,11 +82,14 @@ static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
{
	struct sock *sk = d->owner, *parent;
	unsigned long flags;

	if (!sk)
		return;

	BT_DBG("dlc %p state %ld err %d", d, d->state, err);

	local_irq_save(flags);
	bh_lock_sock(sk);

	if (err)
@@ -108,6 +111,7 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
	}

	bh_unlock_sock(sk);
	local_irq_restore(flags);

	if (parent && sock_flag(sk, SOCK_ZAPPED)) {
		/* We have to drop DLC lock here, otherwise