|
27 | 27 |
|
28 | 28 | #include <linux/export.h> |
29 | 29 | #include <linux/debugfs.h> |
| 30 | +#include <linux/errqueue.h> |
30 | 31 |
|
31 | 32 | #include <net/bluetooth/bluetooth.h> |
32 | 33 | #include <net/bluetooth/hci_core.h> |
@@ -1002,6 +1003,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t |
1002 | 1003 | } |
1003 | 1004 |
|
1004 | 1005 | skb_queue_head_init(&conn->data_q); |
| 1006 | + skb_queue_head_init(&conn->tx_q.queue); |
1005 | 1007 |
|
1006 | 1008 | INIT_LIST_HEAD(&conn->chan_list); |
1007 | 1009 | INIT_LIST_HEAD(&conn->link_list); |
@@ -1155,6 +1157,7 @@ void hci_conn_del(struct hci_conn *conn) |
1155 | 1157 | } |
1156 | 1158 |
|
1157 | 1159 | skb_queue_purge(&conn->data_q); |
| 1160 | + skb_queue_purge(&conn->tx_q.queue); |
1158 | 1161 |
|
1159 | 1162 | /* Remove the connection from the list and cleanup its remaining |
1160 | 1163 | * state. This is a separate function since for some cases like |
@@ -3064,3 +3067,122 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason) |
3064 | 3067 | */ |
3065 | 3068 | return hci_cmd_sync_run_once(hdev, abort_conn_sync, conn, NULL); |
3066 | 3069 | } |
| 3070 | + |
| 3071 | +void hci_setup_tx_timestamp(struct sk_buff *skb, size_t key_offset, |
| 3072 | + const struct sockcm_cookie *sockc) |
| 3073 | +{ |
| 3074 | + struct sock *sk = skb ? skb->sk : NULL; |
| 3075 | + |
| 3076 | + /* This shall be called on a single skb of those generated by user |
| 3077 | + * sendmsg(), and only when the sendmsg() does not return error to |
| 3078 | + * user. This is required for keeping the tskey that increments here in |
| 3079 | + * sync with possible sendmsg() counting by user. |
| 3080 | + * |
| 3081 | + * Stream sockets shall set key_offset to sendmsg() length in bytes |
| 3082 | + * and call with the last fragment, others to 1 and first fragment. |
| 3083 | + */ |
| 3084 | + |
| 3085 | + if (!skb || !sockc || !sk || !key_offset) |
| 3086 | + return; |
| 3087 | + |
| 3088 | + sock_tx_timestamp(sk, sockc, &skb_shinfo(skb)->tx_flags); |
| 3089 | + |
| 3090 | + if (sockc->tsflags & SOF_TIMESTAMPING_OPT_ID && |
| 3091 | + sockc->tsflags & SOF_TIMESTAMPING_TX_RECORD_MASK) { |
| 3092 | + if (sockc->tsflags & SOCKCM_FLAG_TS_OPT_ID) { |
| 3093 | + skb_shinfo(skb)->tskey = sockc->ts_opt_id; |
| 3094 | + } else { |
| 3095 | + int key = atomic_add_return(key_offset, &sk->sk_tskey); |
| 3096 | + |
| 3097 | + skb_shinfo(skb)->tskey = key - 1; |
| 3098 | + } |
| 3099 | + } |
| 3100 | +} |
| 3101 | + |
| 3102 | +void hci_conn_tx_queue(struct hci_conn *conn, struct sk_buff *skb) |
| 3103 | +{ |
| 3104 | + struct tx_queue *comp = &conn->tx_q; |
| 3105 | + bool track = false; |
| 3106 | + |
| 3107 | + /* Emit SND now, ie. just before sending to driver */ |
| 3108 | + if (skb_shinfo(skb)->tx_flags & SKBTX_SW_TSTAMP) |
| 3109 | + __skb_tstamp_tx(skb, NULL, NULL, skb->sk, SCM_TSTAMP_SND); |
| 3110 | + |
| 3111 | + /* COMPLETION tstamp is emitted for tracked skb later in Number of |
| 3112 | + * Completed Packets event. Available only for flow controlled cases. |
| 3113 | + * |
| 3114 | + * TODO: SCO support without flowctl (needs to be done in drivers) |
| 3115 | + */ |
| 3116 | + switch (conn->type) { |
| 3117 | + case ISO_LINK: |
| 3118 | + case ACL_LINK: |
| 3119 | + case LE_LINK: |
| 3120 | + break; |
| 3121 | + case SCO_LINK: |
| 3122 | + case ESCO_LINK: |
| 3123 | + if (!hci_dev_test_flag(conn->hdev, HCI_SCO_FLOWCTL)) |
| 3124 | + return; |
| 3125 | + break; |
| 3126 | + default: |
| 3127 | + return; |
| 3128 | + } |
| 3129 | + |
| 3130 | + if (skb->sk && (skb_shinfo(skb)->tx_flags & SKBTX_COMPLETION_TSTAMP)) |
| 3131 | + track = true; |
| 3132 | + |
| 3133 | + /* If nothing is tracked, just count extra skbs at the queue head */ |
| 3134 | + if (!track && !comp->tracked) { |
| 3135 | + comp->extra++; |
| 3136 | + return; |
| 3137 | + } |
| 3138 | + |
| 3139 | + if (track) { |
| 3140 | + skb = skb_clone_sk(skb); |
| 3141 | + if (!skb) |
| 3142 | + goto count_only; |
| 3143 | + |
| 3144 | + comp->tracked++; |
| 3145 | + } else { |
| 3146 | + skb = skb_clone(skb, GFP_KERNEL); |
| 3147 | + if (!skb) |
| 3148 | + goto count_only; |
| 3149 | + } |
| 3150 | + |
| 3151 | + skb_queue_tail(&comp->queue, skb); |
| 3152 | + return; |
| 3153 | + |
| 3154 | +count_only: |
| 3155 | + /* Stop tracking skbs, and only count. This will not emit timestamps for |
| 3156 | + * the packets, but if we get here something is more seriously wrong. |
| 3157 | + */ |
| 3158 | + comp->tracked = 0; |
| 3159 | + comp->extra += skb_queue_len(&comp->queue) + 1; |
| 3160 | + skb_queue_purge(&comp->queue); |
| 3161 | +} |
| 3162 | + |
| 3163 | +void hci_conn_tx_dequeue(struct hci_conn *conn) |
| 3164 | +{ |
| 3165 | + struct tx_queue *comp = &conn->tx_q; |
| 3166 | + struct sk_buff *skb; |
| 3167 | + |
| 3168 | + /* If there are tracked skbs, the counted extra go before dequeuing real |
| 3169 | + * skbs, to keep ordering. When nothing is tracked, the ordering doesn't |
| 3170 | + * matter so dequeue real skbs first to get rid of them ASAP. |
| 3171 | + */ |
| 3172 | + if (comp->extra && (comp->tracked || skb_queue_empty(&comp->queue))) { |
| 3173 | + comp->extra--; |
| 3174 | + return; |
| 3175 | + } |
| 3176 | + |
| 3177 | + skb = skb_dequeue(&comp->queue); |
| 3178 | + if (!skb) |
| 3179 | + return; |
| 3180 | + |
| 3181 | + if (skb->sk) { |
| 3182 | + comp->tracked--; |
| 3183 | + __skb_tstamp_tx(skb, NULL, NULL, skb->sk, |
| 3184 | + SCM_TSTAMP_COMPLETION); |
| 3185 | + } |
| 3186 | + |
| 3187 | + kfree_skb(skb); |
| 3188 | +} |
0 commit comments