Re: [PATCH 1/4] Bluetooth: Add initial support for ERTM packets transfers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jul 27, 2009 at 6:59 AM, Marcel Holtmann<marcel@xxxxxxxxxxxx> wrote:
> Hi Gustavo,
>

>> +static struct sk_buff *l2cap_create_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 *control)
>
> Why does control have to be a pointer here. You are not modifying its
> content anyway.

Because control could be 0 too. So I pass the control = NULL when we
don't  want control field.

>
>> +{
>> +     struct l2cap_conn *conn = l2cap_pi(sk)->conn;
>> +     struct sk_buff *skb;
>> +     int err, count, hlen = L2CAP_HDR_SIZE;
>> +     struct l2cap_hdr *lh;
>> +
>> +     BT_DBG("sk %p len %d", sk, (int)len);
>> +
>> +     if (control)
>> +             hlen += 2;
>> +     else if (sk->sk_type == SOCK_DGRAM)
>> +             hlen += 2;
>
> An if (control || sk->sk_type == ...) would do the same here. I know
> wanna make it the same as below, but it is confusing.
>
>> +
>> +     count = min_t(unsigned int, (conn->mtu - hlen), len);
>> +     skb = bt_skb_send_alloc(sk, count + hlen,
>> +                     msg->msg_flags & MSG_DONTWAIT, &err);
>> +     if (!skb)
>> +             return ERR_PTR(-ENOMEM);
>> +
>> +     /* Create L2CAP header */
>> +     lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
>> +     lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
>> +     lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
>> +
>> +     if (control)
>> +             put_unaligned_le16(*control, skb_put(skb, 2));
>> +     else if (sk->sk_type == SOCK_DGRAM)
>> +             put_unaligned_le16(l2cap_pi(sk)->psm, skb_put(skb, 2));
>> +
>> +     err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
>> +     if (unlikely(err < 0)) {
>> +             kfree_skb(skb);
>> +             return ERR_PTR(err);
>> +     }
>> +
>> +     return skb;
>>  }
>>
>>  static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
>>  {
>>       struct sock *sk = sock->sk;
>> -     int err = 0;
>> +     struct l2cap_pinfo *pi = l2cap_pi(sk);
>> +     struct sk_buff *skb;
>> +     u16 control;
>> +     int err;
>>
>>       BT_DBG("sock %p, sk %p", sock, sk);
>>
>> @@ -1238,16 +1339,61 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
>>               return -EOPNOTSUPP;
>>
>>       /* Check outgoing MTU */
>> -     if (sk->sk_type != SOCK_RAW && len > l2cap_pi(sk)->omtu)
>> +     if ((sk->sk_type != SOCK_RAW || pi->mode == L2CAP_MODE_BASIC)
>> +                     && len > pi->omtu)
>>               return -EINVAL;
>
> I am confused now. Wouldn't it be better to check for == SOCK_SEQPACKET
> and that it is basic mode and that the len in smaller than the MTU.

So do we need to add a new check? One for SOCK_RAW (the old) and for
the other you told?

>
>>       lock_sock(sk);
>>
>> -     if (sk->sk_state == BT_CONNECTED)
>> -             err = l2cap_do_send(sk, msg, len);
>> -     else
>> +     if (sk->sk_state != BT_CONNECTED) {
>>               err = -ENOTCONN;
>> +             goto done;
>> +     }
>> +
>> +     switch (pi->mode) {
>> +     case L2CAP_MODE_BASIC:
>> +             /* Create a basic PDU */
>> +             skb = l2cap_create_pdu(sk, msg, len, NULL);
>> +             if (IS_ERR(skb)) {
>> +                     err = PTR_ERR(skb);
>> +                     goto done;
>> +             }
>> +
>> +             err = l2cap_do_send(sk, skb);
>> +             if (!err)
>> +                     err = len;
>> +             break;
>> +
>> +     case L2CAP_MODE_ERTM:
>> +             /* Entire SDU fits into one PDU */
>> +             if (len <= pi->omtu) {
>> +                     control = L2CAP_SDU_UNSEGMENTED;
>> +                     skb = l2cap_create_pdu(sk, msg, len, &control);
>> +                     if (IS_ERR(skb)) {
>> +                             err = PTR_ERR(skb);
>> +                             goto done;
>> +                     }
>> +             }
>> +             else {
>> +                     /* FIXME: Segmentation will be added later */
>> +                     err = -EINVAL;
>> +                     goto done;
>> +             }
>> +             __skb_queue_tail(TX_QUEUE(sk), skb);
>> +             if (sk->sk_send_head == NULL)
>> +                     sk->sk_send_head = skb;
>>
>> +             err = l2cap_ertm_send(sk);
>> +             if (!err)
>> +                     err = len;
>> +             break;
>> +
>> +     default:
>> +             BT_DBG("bad state %1.1x", pi->mode);
>> +             err = -EINVAL;
>> +     }
>> +
>> +done:
>>       release_sock(sk);
>>       return err;
>>  }
>> @@ -2302,6 +2448,10 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
>>
>>       if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
>>               sk->sk_state = BT_CONNECTED;
>> +             l2cap_pi(sk)->next_tx_seq = 0;
>> +             l2cap_pi(sk)->expected_ack_seq = 0;
>> +             l2cap_pi(sk)->unacked_frames = 0;
>> +             __skb_queue_head_init(TX_QUEUE(sk));
>>               l2cap_chan_ready(sk);
>>               goto unlock;
>>       }
>> @@ -2376,6 +2526,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
>>
>>       if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
>>               sk->sk_state = BT_CONNECTED;
>> +             l2cap_pi(sk)->expected_tx_seq = 0;
>> +             l2cap_pi(sk)->num_to_ack = 0;
>> +             __skb_queue_head_init(TX_QUEUE(sk));
>>               l2cap_chan_ready(sk);
>>       }
>>
>> @@ -2406,6 +2559,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
>>
>>       sk->sk_shutdown = SHUTDOWN_MASK;
>>
>> +     skb_queue_purge(TX_QUEUE(sk));
>> +
>>       l2cap_chan_del(sk, ECONNRESET);
>>       bh_unlock_sock(sk);
>>
>> @@ -2428,6 +2583,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
>>       if (!sk)
>>               return 0;
>>
>> +     skb_queue_purge(TX_QUEUE(sk));
>> +
>>       l2cap_chan_del(sk, 0);
>>       bh_unlock_sock(sk);
>>
>> @@ -2603,9 +2760,63 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
>>       kfree_skb(skb);
>>  }
>>
>> +static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
>> +{
>> +     struct l2cap_pinfo *pi = l2cap_pi(sk);
>> +     u8 tx_seq = __get_txseq(rx_control);
>> +     u16 tx_control = 0;
>> +     int err;
>> +
>> +     BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
>> +
>> +     if (tx_seq != pi->expected_tx_seq)
>> +             return -EINVAL;
>> +
>> +     L2CAP_SEQ_NUM_INC(pi->expected_tx_seq);
>> +     err = sock_queue_rcv_skb(sk, skb);
>> +     if (err)
>> +             return err;
>> +
>> +     L2CAP_NUM_TO_ACK_INC(pi->num_to_ack);
>> +     if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) {
>> +             tx_control |= L2CAP_CTRL_FRAME_TYPE;
>> +             tx_control |= L2CAP_SUPER_RCV_READY;
>> +             tx_control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
>> +
>> +             err = l2cap_send_sframe(pi, tx_control);
>> +             if (unlikely(err))
>> +                     return err;
>
> Drop this unlikely, too. Just return err. Actually at this point in the
> flow there is no need to check it at all.
>
>> +     }
>> +     return 0;
>> +}
>> +
>> +static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
>> +{
>> +     struct l2cap_pinfo *pi = l2cap_pi(sk);
>> +
>> +     BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
>> +
>> +     switch (rx_control & L2CAP_CTRL_SUPERVISE) {
>> +     case L2CAP_SUPER_RCV_READY:
>> +             pi->expected_ack_seq = __get_reqseq(rx_control);
>> +             l2cap_drop_acked_frames(sk);
>> +             l2cap_ertm_send(sk);
>> +             break;
>> +
>> +     case L2CAP_SUPER_RCV_NOT_READY:
>> +     case L2CAP_SUPER_REJECT:
>> +     case L2CAP_SUPER_SELECT_REJECT:
>> +             break;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>>  static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
>>  {
>>       struct sock *sk;
>> +     u16 control;
>> +     int err;
>>
>>       sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
>>       if (!sk) {
>> @@ -2618,16 +2829,40 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
>>       if (sk->sk_state != BT_CONNECTED)
>>               goto drop;
>>
>> -     if (l2cap_pi(sk)->imtu < skb->len)
>> -             goto drop;
>> +     switch (l2cap_pi(sk)->mode) {
>> +     case L2CAP_MODE_BASIC:
>> +             /* If socket recv buffers overflows we drop data here
>> +              * which is *bad* because L2CAP has to be reliable.
>> +              * But we don't have any other choice. L2CAP doesn't
>> +              * provide flow control mechanism. */
>>
>> -     /* If socket recv buffers overflows we drop data here
>> -      * which is *bad* because L2CAP has to be reliable.
>> -      * But we don't have any other choice. L2CAP doesn't
>> -      * provide flow control mechanism. */
>> +             if (l2cap_pi(sk)->imtu < skb->len)
>> +                     goto drop;
>>
>> -     if (!sock_queue_rcv_skb(sk, skb))
>> -             goto done;
>> +             if (!sock_queue_rcv_skb(sk, skb))
>> +                     goto done;
>> +             break;
>> +
>> +     case L2CAP_MODE_ERTM:
>> +             control = get_unaligned_le16(skb->data);
>> +             skb_pull(skb, 2);
>> +
>> +             if (l2cap_pi(sk)->imtu < skb->len)
>> +                     goto drop;
>> +
>> +             if (__is_iframe(control))
>> +                     err = l2cap_data_channel_iframe(sk, control, skb);
>> +             else
>> +                     err = l2cap_data_channel_sframe(sk, control, skb);
>> +
>> +             if (!err)
>> +                     goto done;
>> +             break;
>> +
>> +     default:
>> +             BT_DBG("sk %p: bad mode 0x%2.2x", sk, l2cap_pi(sk)->mode);
>> +             break;
>> +     }
>>
>>  drop:
>>       kfree_skb(skb);
>> @@ -2677,6 +2912,9 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
>>       cid = __le16_to_cpu(lh->cid);
>>       len = __le16_to_cpu(lh->len);
>>
>> +     if (len != skb->len)
>> +             goto drop;
>> +
>>       BT_DBG("len %d, cid 0x%4.4x", len, cid);
>>
>>       switch (cid) {
>> @@ -2694,6 +2932,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
>>               l2cap_data_channel(conn, cid, skb);
>>               break;
>>       }
>> +     return;
>> +
>> +drop:
>> +     kfree_skb(skb);
>
> So this change is pointless. Just free the skb and return from the
> actual length check. There is no benefit to go to the end of the
> function here.
>
> Regards
>
> Marcel
>
>
>



-- 
Gustavo F. Padovan
http://padovan.org
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux