Merge b8fea6fab4 on remote branch

Change-Id: I5cbed2a7df439cbffb10aedb7ea889e2cf9608bc
This commit is contained in:
Linux Build Service Account 2020-11-23 06:50:08 -08:00
commit a697338671
4 changed files with 49 additions and 7 deletions

View file

@ -1253,7 +1253,7 @@ void qmi_rmnet_work_init(void *port)
return;
rmnet_ps_wq = alloc_workqueue("rmnet_powersave_work",
WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
WQ_CPU_INTENSIVE, 1);
if (!rmnet_ps_wq)
return;

View file

@ -849,6 +849,16 @@ skip_frags:
th->seq = frag_desc->tcp_seq;
}
if (frag_desc->tcp_flags_set) {
struct tcphdr *th;
__be16 *flags;
th = (struct tcphdr *)
(rmnet_map_data_ptr(head_skb) + frag_desc->ip_len);
flags = (__be16 *)&tcp_flag_word(th);
*flags = frag_desc->tcp_flags;
}
/* Handle csum offloading */
if (frag_desc->csum_valid && frag_desc->hdrs_valid) {
/* Set the partial checksum information */
@ -984,6 +994,24 @@ static void __rmnet_frag_segment_data(struct rmnet_frag_descriptor *coal_desc,
new_desc->tcp_seq_set = 1;
new_desc->tcp_seq = htonl(ntohl(th->seq) +
coal_desc->data_offset);
/* Don't allow any dangerous flags to appear in any segments
* other than the last.
*/
if (th->fin || th->psh) {
if (offset + dlen < coal_desc->len) {
__be32 flag_word = tcp_flag_word(th);
/* Clear the FIN and PSH flags from this
* segment.
*/
flag_word &= ~TCP_FLAG_FIN;
flag_word &= ~TCP_FLAG_PSH;
new_desc->tcp_flags_set = 1;
new_desc->tcp_flags = *((__be16 *)&flag_word);
}
}
} else if (coal_desc->trans_proto == IPPROTO_UDP) {
struct udphdr *uh, __uh;

View file

@ -40,6 +40,7 @@ struct rmnet_frag_descriptor {
u32 hash;
__be32 tcp_seq;
__be16 ip_id;
__be16 tcp_flags;
u16 data_offset;
u16 gso_size;
u16 gso_segs;
@ -53,7 +54,8 @@ struct rmnet_frag_descriptor {
ip_id_set:1,
tcp_seq_set:1,
flush_shs:1,
reserved:3;
tcp_flags_set:1,
reserved:2;
};
/* Descriptor management */

View file

@ -744,22 +744,23 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
struct rmnet_priv *priv = netdev_priv(coal_skb->dev);
__sum16 *check = NULL;
u32 alloc_len;
u32 dlen = coal_meta->data_len * coal_meta->pkt_count;
u32 hlen = coal_meta->ip_len + coal_meta->trans_len;
bool zero_csum = false;
/* We can avoid copying the data if the SKB we got from the lower-level
* drivers was nonlinear.
*/
if (skb_is_nonlinear(coal_skb))
alloc_len = coal_meta->ip_len + coal_meta->trans_len;
alloc_len = hlen;
else
alloc_len = coal_meta->ip_len + coal_meta->trans_len +
(coal_meta->data_len * coal_meta->pkt_count);
alloc_len = hlen + dlen;
skbn = alloc_skb(alloc_len, GFP_ATOMIC);
if (!skbn)
return;
skb_reserve(skbn, coal_meta->ip_len + coal_meta->trans_len);
skb_reserve(skbn, hlen);
rmnet_map_nonlinear_copy(coal_skb, coal_meta, skbn);
/* Push transport header and update necessary fields */
@ -771,6 +772,17 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
th->seq = htonl(ntohl(th->seq) + coal_meta->data_offset);
check = &th->check;
/* Don't allow dangerous flags to be set in any segment but the
* last one.
*/
if (th->fin || th->psh) {
if (hlen + coal_meta->data_offset + dlen <
coal_skb->len) {
th->fin = 0;
th->psh = 0;
}
}
} else if (coal_meta->trans_proto == IPPROTO_UDP) {
struct udphdr *uh = udp_hdr(skbn);
@ -846,7 +858,7 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
__skb_queue_tail(list, skbn);
/* Update meta information to move past the data we just segmented */
coal_meta->data_offset += coal_meta->data_len * coal_meta->pkt_count;
coal_meta->data_offset += dlen;
coal_meta->pkt_id = pkt_id + 1;
coal_meta->pkt_count = 0;
}