net: Use helpers to get/set UDP len tree-wide

Since BIG TCP for UDP tunnels will start using len=0 in the UDP header
as an indicator of a GSO packet bigger than 65535 bytes, this commit
introduces the following getter and setters to use tree-wide, in order
to explicitly mark places where len=0 may be expected, and handle them
properly:

1. udp_set_len() sets uh->len to its real value if it's not bigger than
65535, and to 0 otherwise: to be used in GSO context with aggregated
packets.

2. udp_set_len_short() is to be used when the length is known to fit 16
bits. It WARNs when the caller tries to assign a bigger value if
CONFIG_DEBUG_NET=y.

3. udp_get_len_short() returns len in host byte order: to be used on the
RX side to deal with non-aggregated packets, or to access the raw value
of the len field.

4. udp_get_len() decodes uh->len set by udp_set_len(). It checks whether
the packet is GSO to guard from malformed packets.

At the moment udp_set_len() is not used, a following commit will start
using it after enabling len>65535 for GSO.

Raw uh->len (in network byte order) is still accessed in a few places
for checksum calculation purposes, and to decode len=0 in udpv6_rcv for
jumbograms. udp_rcv and udpv6_rcv will be addressed by the commit that
starts using udp_set_len() to set UDP len=0 for BIG TCP packets in UDP
tunnels.

Signed-off-by: Alice Mikityanska <alice@isovalent.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Acked-by: Jason A. Donenfeld <Jason@zx2c4.com>
Link: https://patch.msgid.link/20260710134242.216538-2-alice.kernel@fastmail.im
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Alice Mikityanska 2026-07-10 16:42:34 +03:00 committed by Paolo Abeni
parent ba520084dc
commit 5329647dad
49 changed files with 131 additions and 88 deletions

View File

@ -36,7 +36,7 @@ static struct sk_buff *rdma_build_skb(struct net_device *netdev,
uh->source =
htons(rdma_flow_label_to_udp_sport(ah_attr->grh.flow_label));
uh->dest = htons(ROCE_V2_UDP_DPORT);
uh->len = htons(sizeof(struct udphdr));
udp_set_len_short(uh, sizeof(struct udphdr));
if (is_ipv4) {
skb_push(skb, sizeof(struct iphdr));

View File

@ -242,7 +242,7 @@ static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
pkt->port_num = 1;
pkt->hdr = (u8 *)(udph + 1);
pkt->mask = RXE_GRH_MASK;
pkt->paylen = be16_to_cpu(udph->len) - sizeof(*udph);
pkt->paylen = udp_get_len_short(udph) - sizeof(*udph);
/* remove udp header */
skb_pull(skb, sizeof(struct udphdr));
@ -305,7 +305,7 @@ static void prepare_udp_hdr(struct sk_buff *skb, __be16 src_port,
udph->dest = dst_port;
udph->source = src_port;
udph->len = htons(skb->len);
udp_set_len_short(udph, skb->len);
udph->check = 0;
}

View File

@ -667,7 +667,7 @@ static void amt_send_discovery(struct amt_dev *amt)
udph = udp_hdr(skb);
udph->source = amt->gw_port;
udph->dest = amt->relay_port;
udph->len = htons(sizeof(*udph) + sizeof(*amtd));
udp_set_len_short(udph, sizeof(*udph) + sizeof(*amtd));
udph->check = 0;
offset = skb_transport_offset(skb);
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
@ -760,7 +760,7 @@ static void amt_send_request(struct amt_dev *amt, bool v6)
udph = udp_hdr(skb);
udph->source = amt->gw_port;
udph->dest = amt->relay_port;
udph->len = htons(sizeof(*amtrh) + sizeof(*udph));
udp_set_len_short(udph, sizeof(*amtrh) + sizeof(*udph));
udph->check = 0;
offset = skb_transport_offset(skb);
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
@ -2611,7 +2611,7 @@ static void amt_send_advertisement(struct amt_dev *amt, __be32 nonce,
udph = udp_hdr(skb);
udph->source = amt->relay_port;
udph->dest = dport;
udph->len = htons(sizeof(*amta) + sizeof(*udph));
udp_set_len_short(udph, sizeof(*amta) + sizeof(*udph));
udph->check = 0;
offset = skb_transport_offset(skb);
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);

View File

@ -3129,7 +3129,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
SKB_GSO_UDP_TUNNEL_CSUM)) {
if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
l4.udp->len = 0;
udp_set_len_short(l4.udp, 0);
/* determine offset of outer transport header */
l4_offset = l4.hdr - skb->data;

View File

@ -1774,7 +1774,7 @@ static int iavf_tso(struct iavf_tx_buffer *first, u8 *hdr_len,
SKB_GSO_UDP_TUNNEL_CSUM)) {
if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
l4.udp->len = 0;
udp_set_len_short(l4.udp, 0);
/* determine offset of outer transport header */
l4_offset = l4.hdr - skb->data;

View File

@ -1893,7 +1893,7 @@ int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
SKB_GSO_UDP_TUNNEL_CSUM)) {
if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
l4.udp->len = 0;
udp_set_len_short(l4.udp, 0);
/* determine offset of outer transport header */
l4_start = (u8)(l4.hdr - skb->data);

View File

@ -2871,7 +2871,7 @@ int idpf_tso(struct sk_buff *skb, struct idpf_tx_offload_params *off)
(__force __wsum)htonl(paylen));
/* compute length of segmentation header */
off->tso_hdr_len = sizeof(struct udphdr) + l4_start;
l4.udp->len = htons(shinfo->gso_size + sizeof(struct udphdr));
udp_set_len_short(l4.udp, shinfo->gso_size + sizeof(struct udphdr));
break;
default:
return -EINVAL;

View File

@ -750,7 +750,7 @@ static void otx2_sqe_add_ext(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
ext->lso_format = pfvf->hw.lso_udpv6_idx;
}
udph->len = htons(sizeof(struct udphdr));
udp_set_len_short(udph, sizeof(struct udphdr));
}
} else if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
ext->tstmp = 1;

View File

@ -1081,7 +1081,7 @@ static void mlx5e_shampo_update_ipv4_udp_hdr(struct mlx5e_rq *rq, struct iphdr *
struct udphdr *uh;
uh = (struct udphdr *)(skb->data + udp_off);
uh->len = htons(skb->len - udp_off);
udp_set_len_short(uh, skb->len - udp_off);
if (uh->check)
uh->check = ~udp_v4_check(skb->len - udp_off, ipv4->saddr,
@ -1100,7 +1100,7 @@ static void mlx5e_shampo_update_ipv6_udp_hdr(struct mlx5e_rq *rq, struct ipv6hdr
struct udphdr *uh;
uh = (struct udphdr *)(skb->data + udp_off);
uh->len = htons(skb->len - udp_off);
udp_set_len_short(uh, skb->len - udp_off);
if (uh->check)
uh->check = ~udp_v6_check(skb->len - udp_off, &ipv6->saddr,

View File

@ -113,7 +113,7 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
/* Fill UDP header */
udph->source = htons(9);
udph->dest = htons(9); /* Discard Protocol */
udph->len = htons(sizeof(struct mlx5ehdr) + sizeof(struct udphdr));
udp_set_len_short(udph, sizeof(struct mlx5ehdr) + sizeof(struct udphdr));
udph->check = 0;
/* Fill IP header */

View File

@ -401,8 +401,8 @@ static void ef4_iterate_state(struct ef4_nic *efx)
/* Initialise udp header */
payload->udp.source = 0;
payload->udp.len = htons(sizeof(*payload) -
offsetof(struct ef4_loopback_payload, udp));
udp_set_len_short(&payload->udp, sizeof(*payload) -
offsetof(struct ef4_loopback_payload, udp));
payload->udp.check = 0; /* checksum ignored */
/* Fill out payload */

View File

@ -398,8 +398,8 @@ static void efx_iterate_state(struct efx_nic *efx)
/* Initialise udp header */
payload->udp.source = 0;
payload->udp.len = htons(sizeof(*payload) -
offsetof(struct efx_loopback_payload, udp));
udp_set_len_short(&payload->udp, sizeof(*payload) -
offsetof(struct efx_loopback_payload, udp));
payload->udp.check = 0; /* checksum ignored */
/* Fill out payload */

View File

@ -399,8 +399,8 @@ static void efx_iterate_state(struct efx_nic *efx)
/* Initialise udp header */
payload->udp.source = 0;
payload->udp.len = htons(sizeof(*payload) -
offsetof(struct efx_loopback_payload, udp));
udp_set_len_short(&payload->udp, sizeof(*payload) -
offsetof(struct efx_loopback_payload, udp));
payload->udp.check = 0; /* checksum ignored */
/* Fill out payload */

View File

@ -311,7 +311,7 @@ static void efx_gen_tun_header_udp(struct efx_tc_encap_action *encap, u8 len)
encap->encap_hdr_len += sizeof(*udp);
udp->dest = key->tp_dst;
udp->len = cpu_to_be16(sizeof(*udp) + len);
udp_set_len_short(udp, sizeof(*udp) + len);
}
static void efx_gen_tun_header_vxlan(struct efx_tc_encap_action *encap)

View File

@ -154,9 +154,9 @@ static struct sk_buff *stmmac_test_get_udp_skb(struct stmmac_priv *priv,
} else {
uhdr->source = htons(attr->sport);
uhdr->dest = htons(attr->dport);
uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size);
udp_set_len_short(uhdr, sizeof(*shdr) + sizeof(*uhdr) + attr->size);
if (attr->max_size)
uhdr->len = htons(attr->max_size -
udp_set_len_short(uhdr, attr->max_size -
(sizeof(*ihdr) + sizeof(*ehdr)));
uhdr->check = 0;
}

View File

@ -631,7 +631,7 @@ static int geneve_post_decap_hint(const struct sock *sk, struct sk_buff *skb,
/* Adjust the nested UDP header len and checksum. */
uh = udp_hdr(skb);
uh->len = htons(skb->len - gro_hint->nested_tp_offset);
udp_set_len_short(uh, skb->len - gro_hint->nested_tp_offset);
if (uh->check) {
len = skb->len - gro_hint->nested_tp_offset;
skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM;

View File

@ -1876,7 +1876,7 @@ static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)
udph = udp_hdr(skb);
udph->source = htons(np->local_port);
udph->dest = htons(np->remote_port);
udph->len = htons(udp_len);
udp_set_len_short(udph, udp_len);
netpoll_udp_checksum(np, skb, len);
}

View File

@ -845,7 +845,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void)
udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len);
get_random_bytes(&udph->source, sizeof(u16));
get_random_bytes(&udph->dest, sizeof(u16));
udph->len = htons(sizeof(struct udphdr) + data_len);
udp_set_len_short(udph, sizeof(struct udphdr) + data_len);
return skb;
}

View File

@ -73,7 +73,7 @@ static struct sk_buff *nsim_dev_psample_skb_build(void)
udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len);
get_random_bytes(&udph->source, sizeof(u16));
get_random_bytes(&udph->dest, sizeof(u16));
udph->len = htons(sizeof(struct udphdr) + data_len);
udp_set_len_short(udph, sizeof(struct udphdr) + data_len);
return skb;
}

View File

@ -84,6 +84,7 @@ nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
struct iphdr *iph;
struct udphdr *uh;
__wsum csum;
int udplen;
/* Do not decapsulate. Receive the skb with the udp and psp
* headers still there as if this is a normal udp packet.
@ -91,19 +92,20 @@ nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
* provide a valid checksum here, so the skb isn't dropped.
*/
uh = udp_hdr(skb);
udplen = udp_get_len(skb, uh, skb_transport_offset(skb));
csum = skb_checksum(skb, skb_transport_offset(skb),
ntohs(uh->len), 0);
udplen, 0);
switch (skb->protocol) {
case htons(ETH_P_IP):
iph = ip_hdr(skb);
uh->check = udp_v4_check(ntohs(uh->len), iph->saddr,
uh->check = udp_v4_check(udplen, iph->saddr,
iph->daddr, csum);
break;
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
ip6h = ipv6_hdr(skb);
uh->check = udp_v6_check(ntohs(uh->len), &ip6h->saddr,
uh->check = udp_v6_check(udplen, &ip6h->saddr,
&ip6h->daddr, csum);
break;
#endif

View File

@ -62,7 +62,7 @@ static int prepare_skb_header(struct sk_buff *skb, struct wg_device *wg)
* to have UDP fields.
*/
return -EINVAL;
data_len = ntohs(udp->len);
data_len = udp_get_len_short(udp);
if (unlikely(data_len < sizeof(struct udphdr) ||
data_len > skb->len - data_offset))
/* UDP packet is reporting too small of a size or lying about

View File

@ -23,6 +23,33 @@ static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
return (struct udphdr *)skb_transport_header(skb);
}
static inline unsigned int udp_get_len(const struct sk_buff *skb,
const struct udphdr *uh,
unsigned int dataoff)
{
if (uh->len)
return ntohs(uh->len);
if (skb_is_gso(skb)) /* BIG TCP */
return skb->len - dataoff;
return 0;
}
static inline unsigned int udp_get_len_short(const struct udphdr *uh)
{
return ntohs(uh->len);
}
static inline void udp_set_len(struct udphdr *uh, unsigned int len)
{
uh->len = len < GRO_LEGACY_MAX_SIZE ? htons(len) : 0;
}
static inline void udp_set_len_short(struct udphdr *uh, unsigned int len)
{
DEBUG_NET_WARN_ON_ONCE(len >= GRO_LEGACY_MAX_SIZE);
uh->len = htons(len);
}
#define UDP_HTABLE_SIZE_MIN_PERNET 128
#define UDP_HTABLE_SIZE_MIN (IS_ENABLED(CONFIG_BASE_SMALL) ? 128 : 256)
#define UDP_HTABLE_SIZE_MAX 65536

View File

@ -44,7 +44,7 @@ TRACE_EVENT(icmp_send,
} else {
__entry->sport = ntohs(uh->source);
__entry->dport = ntohs(uh->dest);
__entry->ulen = ntohs(uh->len);
__entry->ulen = udp_get_len_short(uh);
}
p32 = (__be32 *) __entry->saddr;

View File

@ -46,7 +46,7 @@ static void test_blackholedev(struct kunit *test)
uh = (struct udphdr *)skb_push(skb, sizeof(struct udphdr));
skb_set_transport_header(skb, 0);
uh->source = uh->dest = htons(UDP_PORT);
uh->len = htons(data_len);
udp_set_len_short(uh, data_len);
uh->check = 0;
/* (Network) IPv6 */
ip6h = (struct ipv6hdr *)skb_push(skb, sizeof(struct ipv6hdr));

View File

@ -88,16 +88,16 @@ static int udp_uncompress(struct sk_buff *skb, size_t needed)
switch (lowpan_dev(skb->dev)->lltype) {
case LOWPAN_LLTYPE_IEEE802154:
if (lowpan_802154_cb(skb)->d_size)
uh.len = htons(lowpan_802154_cb(skb)->d_size -
sizeof(struct ipv6hdr));
udp_set_len_short(&uh, lowpan_802154_cb(skb)->d_size -
sizeof(struct ipv6hdr));
else
uh.len = htons(skb->len + sizeof(struct udphdr));
udp_set_len_short(&uh, skb->len + sizeof(struct udphdr));
break;
default:
uh.len = htons(skb->len + sizeof(struct udphdr));
udp_set_len_short(&uh, skb->len + sizeof(struct udphdr));
break;
}
pr_debug("uncompressed UDP length: src = %d", ntohs(uh.len));
pr_debug("uncompressed UDP length: src = %d", udp_get_len_short(&uh));
/* replace the compressed UDP head by the uncompressed UDP
* header

View File

@ -3005,7 +3005,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
udph->source = htons(pkt_dev->cur_udp_src);
udph->dest = htons(pkt_dev->cur_udp_dst);
udph->len = htons(datalen + 8); /* DATA + udphdr */
udp_set_len_short(udph, datalen + 8); /* DATA + udphdr */
udph->check = 0;
iph->ihl = 5;
@ -3138,7 +3138,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
udplen = datalen + sizeof(struct udphdr);
udph->source = htons(pkt_dev->cur_udp_src);
udph->dest = htons(pkt_dev->cur_udp_dst);
udph->len = htons(udplen);
udp_set_len_short(udph, udplen);
udph->check = 0;
*(__be32 *) iph = htonl(0x60000000); /* Version + flow */

View File

@ -72,9 +72,9 @@ struct sk_buff *net_test_get_skb(struct net_device *ndev, u8 id,
} else {
uhdr->source = htons(attr->sport);
uhdr->dest = htons(attr->dport);
uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size);
udp_set_len_short(uhdr, sizeof(*shdr) + sizeof(*uhdr) + attr->size);
if (attr->max_size)
uhdr->len = htons(attr->max_size -
udp_set_len_short(uhdr, attr->max_size -
(sizeof(*ihdr) + sizeof(*ehdr)));
uhdr->check = 0;
}

View File

@ -39,7 +39,8 @@ void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
} else {
struct udphdr *uh = (struct udphdr *)hdr;
uh->len = htons(sizeof(*uh) + size);
/* size is after segmentation. */
udp_set_len_short(uh, sizeof(*uh) + size);
}
}
EXPORT_SYMBOL(tso_build_hdr);

View File

@ -323,7 +323,7 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
uh = (struct udphdr *)esp->esph;
uh->source = sport;
uh->dest = dport;
uh->len = htons(len);
udp_set_len_short(uh, len);
uh->check = 0;
/* For IPv4 ESP with UDP encapsulation, if xo is not null, the skb is in the crypto offload

View File

@ -1040,7 +1040,7 @@ static void fou_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e,
uh->dest = e->dport;
uh->source = sport;
uh->len = htons(skb->len);
udp_set_len_short(uh, skb->len);
udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb,
fl4->saddr, fl4->daddr, skb->len);

View File

@ -847,7 +847,7 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d
/* Construct UDP header */
b->udph.source = htons(68);
b->udph.dest = htons(67);
b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr));
udp_set_len_short(&b->udph, sizeof(struct bootp_pkt) - sizeof(struct iphdr));
/* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */
/* Construct DHCP/BOOTP header */
@ -1025,10 +1025,10 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
if (b->udph.source != htons(67) || b->udph.dest != htons(68))
goto drop;
if (ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr))
if (ntohs(h->tot_len) < udp_get_len_short(&b->udph) + sizeof(struct iphdr))
goto drop;
len = ntohs(b->udph.len) - sizeof(struct udphdr);
len = udp_get_len_short(&b->udph) - sizeof(struct udphdr);
ext_len = len - (sizeof(*b) -
sizeof(struct iphdr) -
sizeof(struct udphdr) -

View File

@ -127,7 +127,7 @@ static int snmp_translate(struct nf_conn *ct, int dir, struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl);
u16 datalen = ntohs(udph->len) - sizeof(struct udphdr);
u16 datalen = udp_get_len_short(udph) - sizeof(struct udphdr);
char *data = (unsigned char *)udph + sizeof(struct udphdr);
struct snmp_ctx ctx;
int ret;
@ -181,7 +181,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
* enough room for a UDP header. Just verify the UDP length field so we
* can mess around with the payload.
*/
if (ntohs(udph->len) != skb->len - (iph->ihl << 2)) {
if (udp_get_len_short(udph) != skb->len - (iph->ihl << 2)) {
nf_ct_helper_log(skb, ct, "dropping malformed packet\n");
return NF_DROP;
}

View File

@ -3187,7 +3187,7 @@ static struct sk_buff *inet_rtm_getroute_build_skb(__be32 src, __be32 dst,
udph = skb_put_zero(skb, sizeof(struct udphdr));
udph->source = sport;
udph->dest = dport;
udph->len = htons(sizeof(struct udphdr));
udp_set_len_short(udph, sizeof(struct udphdr));
udph->check = 0;
break;
}

View File

@ -1108,7 +1108,8 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4,
uh = udp_hdr(skb);
uh->source = inet_sk(sk)->inet_sport;
uh->dest = fl4->fl4_dport;
uh->len = htons(len);
/* Datagram length checked in udp_sendmsg. */
udp_set_len_short(uh, len);
uh->check = 0;
if (cork->gso_size) {

View File

@ -279,11 +279,11 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
* segment instead of the entire frame.
*/
if (gso_partial && skb_is_gso(skb)) {
uh->len = htons(skb_shinfo(skb)->gso_size +
SKB_GSO_CB(skb)->data_offset +
skb->head - (unsigned char *)uh);
udp_set_len_short(uh, skb_shinfo(skb)->gso_size +
SKB_GSO_CB(skb)->data_offset +
skb->head - (unsigned char *)uh);
} else {
uh->len = htons(len);
udp_set_len_short(uh, len);
}
if (!need_csum)
@ -468,7 +468,7 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
if (IS_ERR(skb))
return skb;
udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss);
udp_set_len_short(udp_hdr(skb), sizeof(struct udphdr) + mss);
if (is_ipv6)
return __udpv6_gso_segment_list_csum(skb);
@ -486,8 +486,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
unsigned int mss;
bool copy_dtor;
__sum16 check;
__be16 newlen;
int ret = 0;
u16 newlen;
mss = skb_shinfo(gso_skb)->gso_size;
if (gso_skb->len <= sizeof(*uh) + mss)
@ -564,8 +564,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
(skb_shinfo(gso_skb)->tx_flags & SKBTX_ANY_TSTAMP);
/* compute checksum adjustment based on old length versus new */
newlen = htons(sizeof(*uh) + mss);
check = csum16_add(csum16_sub(uh->check, uh->len), newlen);
newlen = sizeof(*uh) + mss;
check = csum16_add(csum16_sub(uh->check, uh->len), htons(newlen));
for (;;) {
if (copy_dtor) {
@ -577,7 +577,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
if (!seg->next)
break;
uh->len = newlen;
udp_set_len_short(uh, newlen);
uh->check = check;
if (seg->ip_summed == CHECKSUM_PARTIAL)
@ -594,11 +594,10 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
* segment may not be full MSS, account for that in the checksum
*/
if (!skb_is_gso(seg))
newlen = htons(skb_tail_pointer(seg) -
skb_transport_header(seg) + seg->data_len);
check = csum16_add(csum16_sub(uh->check, uh->len), newlen);
newlen = skb_tail_pointer(seg) - skb_transport_header(seg) + seg->data_len;
check = csum16_add(csum16_sub(uh->check, uh->len), htons(newlen));
uh->len = newlen;
udp_set_len_short(uh, newlen);
uh->check = check;
if (seg->ip_summed == CHECKSUM_PARTIAL)
@ -709,7 +708,7 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
}
/* Do not deal with padded or malicious packets, sorry ! */
ulen = ntohs(uh->len);
ulen = udp_get_len_short(uh);
if (ulen <= sizeof(*uh) || ulen != skb_gro_len(skb)) {
NAPI_GRO_CB(skb)->flush = 1;
return NULL;
@ -742,7 +741,7 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
* On len mismatch merge the first packet shorter than gso_size,
* otherwise complete the GRO packet.
*/
if (ulen > ntohs(uh2->len) || flush) {
if (ulen > udp_get_len_short(uh2) || flush) {
pp = p;
} else {
if (NAPI_GRO_CB(skb)->is_flist) {
@ -765,7 +764,7 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
}
}
if (ret || ulen != ntohs(uh2->len) ||
if (ret || ulen != udp_get_len_short(uh2) ||
NAPI_GRO_CB(p)->count >= UDP_GRO_CNT_MAX)
pp = p;
@ -915,12 +914,12 @@ static int udp_gro_complete_segment(struct sk_buff *skb)
int udp_gro_complete(struct sk_buff *skb, int nhoff,
udp_lookup_t lookup)
{
__be16 newlen = htons(skb->len - nhoff);
struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
unsigned int newlen = skb->len - nhoff;
struct sock *sk;
int err;
uh->len = newlen;
udp_set_len_short(uh, newlen);
sk = INDIRECT_CALL_INET(lookup, udp6_lib_lookup_skb,
udp4_lib_lookup_skb, skb, uh->source, uh->dest);
@ -957,7 +956,7 @@ INDIRECT_CALLABLE_SCOPE int udp4_gro_complete(struct sk_buff *skb, int nhoff)
/* do fraglist only if there is no outer UDP encap (or we already processed it) */
if (NAPI_GRO_CB(skb)->is_flist && !NAPI_GRO_CB(skb)->encap_mark) {
uh->len = htons(skb->len - nhoff);
udp_set_len_short(uh, skb->len - nhoff);
skb_shinfo(skb)->gso_type |= (SKB_GSO_FRAGLIST|SKB_GSO_UDP_L4);
skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;

View File

@ -178,7 +178,7 @@ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb
uh->dest = dst_port;
uh->source = src_port;
uh->len = htons(skb->len);
udp_set_len_short(uh, skb->len);
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));

View File

@ -230,7 +230,8 @@ static void esp_output_encap_csum(struct sk_buff *skb)
if (*skb_mac_header(skb) == IPPROTO_UDP) {
struct udphdr *uh = udp_hdr(skb);
struct ipv6hdr *ip6h = ipv6_hdr(skb);
int len = ntohs(uh->len);
/* esp6_output_udp_encap limits len to U16_MAX. */
int len = udp_get_len_short(uh);
unsigned int offset = skb_transport_offset(skb);
__wsum csum = skb_checksum(skb, offset, skb->len - offset, 0);
@ -358,7 +359,7 @@ static struct ip_esp_hdr *esp6_output_udp_encap(struct sk_buff *skb,
uh = (struct udphdr *)esp->esph;
uh->source = sport;
uh->dest = dport;
uh->len = htons(len);
udp_set_len_short(uh, len);
uh->check = 0;
*skb_mac_header(skb) = IPPROTO_UDP;

View File

@ -30,7 +30,7 @@ static void fou6_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e,
uh->dest = e->dport;
uh->source = sport;
uh->len = htons(skb->len);
udp_set_len_short(uh, skb->len);
udp6_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM6), skb,
&fl6->saddr, &fl6->daddr, skb->len);

View File

@ -93,7 +93,7 @@ void udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
uh->dest = dst_port;
uh->source = src_port;
uh->len = htons(skb->len);
udp_set_len_short(uh, skb->len);
skb_dst_set(skb, dst);

View File

@ -1369,7 +1369,8 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6,
uh = udp_hdr(skb);
uh->source = fl6->fl6_sport;
uh->dest = fl6->fl6_dport;
uh->len = htons(len);
/* Datagram length checked in udpv6_sendmsg. */
udp_set_len_short(uh, len);
uh->check = 0;
if (cork->gso_size) {

View File

@ -171,7 +171,7 @@ int udp6_gro_complete(struct sk_buff *skb, int nhoff)
/* do fraglist only if there is no outer UDP encap (or we already processed it) */
if (NAPI_GRO_CB(skb)->is_flist && !NAPI_GRO_CB(skb)->encap_mark) {
uh->len = htons(skb->len - nhoff);
udp_set_len_short(uh, skb->len - nhoff);
skb_shinfo(skb)->gso_type |= (SKB_GSO_FRAGLIST|SKB_GSO_UDP_L4);
skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;

View File

@ -1296,7 +1296,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, uns
ret = NET_XMIT_DROP;
goto out_unlock;
}
uh->len = htons(udp_len);
udp_set_len_short(uh, udp_len);
/* Calculate UDP checksum if configured to do so */
#if IS_ENABLED(CONFIG_IPV6)

View File

@ -1100,7 +1100,7 @@ ipvs_gue_encap(struct net *net, struct sk_buff *skb,
dport = cp->dest->tun_port;
udph->dest = dport;
udph->source = sport;
udph->len = htons(skb->len);
udp_set_len_short(udph, skb->len);
udph->check = 0;
*next_protocol = IPPROTO_UDP;

View File

@ -41,11 +41,22 @@ static void udp_error_log(const struct sk_buff *skb,
nf_l4proto_log_invalid(skb, state, IPPROTO_UDP, "%s", msg);
}
static bool udp_validate_len(struct sk_buff *skb,
const struct udphdr *hdr,
unsigned int dataoff)
{
unsigned int udplen = udp_get_len_short(hdr);
unsigned int skblen = skb->len - dataoff;
if (udplen > skblen || udplen < sizeof(*hdr))
return false;
return true;
}
static bool udp_error(struct sk_buff *skb,
unsigned int dataoff,
const struct nf_hook_state *state)
{
unsigned int udplen = skb->len - dataoff;
const struct udphdr *hdr;
struct udphdr _hdr;
@ -57,7 +68,7 @@ static bool udp_error(struct sk_buff *skb,
}
/* Truncated/malformed packets */
if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
if (!udp_validate_len(skb, hdr, dataoff)) {
udp_error_log(skb, state, "truncated/malformed packet");
return true;
}

View File

@ -301,7 +301,7 @@ nf_log_dump_udp_header(struct nf_log_buf *m,
/* Max length: 20 "SPT=65535 DPT=65535 " */
nf_log_buf_add(m, "SPT=%u DPT=%u LEN=%u ",
ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len));
ntohs(uh->source), ntohs(uh->dest), udp_get_len_short(uh));
out:
return 0;

View File

@ -161,7 +161,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
/* update the length of the UDP packet */
datalen = skb->len - protoff;
udph->len = htons(datalen);
udp_set_len_short(udph, datalen);
/* fix udp checksum if udp checksum was previously calculated */
if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)

View File

@ -231,7 +231,7 @@ static void psp_write_headers(struct net *net, struct sk_buff *skb, __be32 spi,
uh->source = udp_flow_src_port(net, skb, 0, 0, false);
}
uh->check = 0;
uh->len = htons(udp_len);
udp_set_len_short(uh, udp_len);
psph->nexthdr = IPPROTO_TCP;
psph->hdrlen = PSP_HDRLEN_NOOPT;

View File

@ -276,7 +276,7 @@ static int tcf_csum_ipv4_udp(struct sk_buff *skb, unsigned int ihl,
return 0;
iph = ip_hdr(skb);
ul = ntohs(udph->len);
ul = udp_get_len_short(udph);
if (udplite || udph->check) {
@ -334,7 +334,7 @@ static int tcf_csum_ipv6_udp(struct sk_buff *skb, unsigned int ihl,
return 0;
ip6h = ipv6_hdr(skb);
ul = ntohs(udph->len);
ul = udp_get_len_short(udph);
udph->check = 0;

View File

@ -133,7 +133,7 @@ static void nat_keepalive_send(struct nat_keepalive *ka)
uh = skb_push(skb, sizeof(*uh));
uh->source = ka->encap_sport;
uh->dest = ka->encap_dport;
uh->len = htons(skb->len);
udp_set_len_short(uh, skb->len);
uh->check = 0;
skb->mark = ka->smark;