diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 4712cc41881a..7e042a3e648c 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -915,11 +915,9 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, * check if we sre sending sequence numbers and if not, * configure it so. */ - if (!session->lns_mode && !session->send_seq) { + if (!session->lns_mode && !READ_ONCE(session->send_seq)) { trace_session_seqnum_lns_enable(session); - session->send_seq = 1; - l2tp_session_set_header_len(session, tunnel->version, - tunnel->encap); + WRITE_ONCE(session->send_seq, true); } } else { /* No sequence numbers. @@ -937,12 +935,10 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, * If we're the LNS and we're sending sequence numbers, the * LAC is broken. Discard the frame. */ - if (!session->lns_mode && session->send_seq) { + if (!session->lns_mode && READ_ONCE(session->send_seq)) { trace_session_seqnum_lns_disable(session); - session->send_seq = 0; - l2tp_session_set_header_len(session, tunnel->version, - tunnel->encap); - } else if (session->send_seq) { + WRITE_ONCE(session->send_seq, false); + } else if (READ_ONCE(session->send_seq)) { pr_debug_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n", session->name); atomic_long_inc(&session->stats.rx_seq_discards); @@ -1138,7 +1134,8 @@ static void l2tp_udp_encap_err_recv(struct sock *sk, struct sk_buff *skb, int er /* Build an L2TP header for the session into the buffer provided. */ -static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf) +static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf, + bool send_seq) { struct l2tp_tunnel *tunnel = session->tunnel; __be16 *bufp = buf; @@ -1147,14 +1144,14 @@ static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf) u32 tunnel_id = tunnel->peer_tunnel_id; u32 session_id = session->peer_session_id; - if (session->send_seq) + if (send_seq) flags |= L2TP_HDRFLAG_S; /* Setup L2TP header. */ *bufp++ = htons(flags); *bufp++ = htons(tunnel_id); *bufp++ = htons(session_id); - if (session->send_seq) { + if (send_seq) { *bufp++ = htons(session->ns); *bufp++ = 0; session->ns++; @@ -1165,7 +1162,8 @@ static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf) return bufp - optr; } -static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) +static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf, + bool send_seq) { struct l2tp_tunnel *tunnel = session->tunnel; char *bufp = buf; @@ -1191,7 +1189,7 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) { u32 l2h = 0; - if (session->send_seq) { + if (send_seq) { l2h = 0x40000000 | session->ns; session->ns++; session->ns &= 0xffffff; @@ -1225,19 +1223,24 @@ static int l2tp_xmit_queue(struct l2tp_tunnel *tunnel, struct sk_buff *skb, stru static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, unsigned int *len) { struct l2tp_tunnel *tunnel = session->tunnel; + bool send_seq = READ_ONCE(session->send_seq); unsigned int data_len = skb->len; struct sock *sk = tunnel->sock; + u16 hdr_len = session->hdr_len; int headroom, uhlen, udp_len; int ret = NET_XMIT_SUCCESS; struct inet_sock *inet; struct udphdr *uh; + if (tunnel->version == L2TP_HDR_VER_2 && !send_seq) + hdr_len -= 4; + /* Check that there's enough headroom in the skb to insert IP, * UDP and L2TP headers. If not enough, expand it to * make room. Adjust truesize. */ uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(*uh) : 0; - headroom = NET_SKB_PAD + sizeof(struct iphdr) + uhlen + session->hdr_len; + headroom = NET_SKB_PAD + sizeof(struct iphdr) + uhlen + hdr_len; if (skb_cow_head(skb, headroom)) { kfree_skb(skb); return NET_XMIT_DROP; @@ -1245,9 +1248,9 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, uns /* Setup L2TP header */ if (tunnel->version == L2TP_HDR_VER_2) - l2tp_build_l2tpv2_header(session, __skb_push(skb, session->hdr_len)); + l2tp_build_l2tpv2_header(session, __skb_push(skb, hdr_len), send_seq); else - l2tp_build_l2tpv3_header(session, __skb_push(skb, session->hdr_len)); + l2tp_build_l2tpv3_header(session, __skb_push(skb, hdr_len), send_seq); /* Reset control buffer */ memset(skb->cb, 0, sizeof(skb->cb)); @@ -1290,7 +1293,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, uns uh = udp_hdr(skb); uh->source = inet->inet_sport; uh->dest = inet->inet_dport; - udp_len = uhlen + session->hdr_len + data_len; + udp_len = uhlen + hdr_len + data_len; if (udp_len > U16_MAX) { kfree_skb(skb); ret = NET_XMIT_DROP; @@ -1759,16 +1762,11 @@ static void l2tp_session_del_work(struct work_struct *work) l2tp_session_put(session); } -/* We come here whenever a session's send_seq, cookie_len or - * l2specific_type parameters are set. - */ -void l2tp_session_set_header_len(struct l2tp_session *session, int version, - enum l2tp_encap_type encap) +static void l2tp_session_set_header_len(struct l2tp_session *session, int version, + enum l2tp_encap_type encap) { if (version == L2TP_HDR_VER_2) { - session->hdr_len = 6; - if (session->send_seq) - session->hdr_len += 4; + session->hdr_len = 10; } else { session->hdr_len = 4 + session->cookie_len; session->hdr_len += l2tp_get_l2specific_len(session); @@ -1776,7 +1774,6 @@ void l2tp_session_set_header_len(struct l2tp_session *session, int version, session->hdr_len += 4; } } -EXPORT_SYMBOL_GPL(l2tp_session_set_header_len); struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index ffd8ced3a51f..25ae4c25d3ef 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -76,7 +76,7 @@ struct l2tp_session { u8 peer_cookie[8]; int peer_cookie_len; u16 l2specific_type; - u16 hdr_len; + u16 hdr_len; /* maximum L2TP header length */ u32 nr; /* session NR state (receive) */ u32 ns; /* session NR state (send) */ struct sk_buff_head reorder_q; /* receive reorder queue */ @@ -94,8 +94,8 @@ struct l2tp_session { char name[L2TP_SESSION_NAME_MAX]; /* for logging */ char ifname[IFNAMSIZ]; + bool send_seq; /* send packets with sequence numbers? */ unsigned int recv_seq:1; /* expect receive packets with sequence numbers? */ - unsigned int send_seq:1; /* send packets with sequence numbers? */ unsigned int lns_mode:1; /* behave as LNS? * LAC enables sequence numbers under LNS control. */ @@ -257,8 +257,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb); /* Transmit path helpers for sending packets over the tunnel socket. */ -void l2tp_session_set_header_len(struct l2tp_session *session, int version, - enum l2tp_encap_type encap); int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb); /* Pseudowire management. diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c index c12d5e1ee550..58d1d6a7768e 100644 --- a/net/l2tp/l2tp_debugfs.c +++ b/net/l2tp/l2tp_debugfs.c @@ -182,12 +182,12 @@ static void l2tp_dfs_seq_session_show(struct seq_file *m, void *v) session->pwtype == L2TP_PWTYPE_ETH ? "ETH" : session->pwtype == L2TP_PWTYPE_PPP ? "PPP" : ""); - if (session->send_seq || session->recv_seq) + if (READ_ONCE(session->send_seq) || session->recv_seq) seq_printf(m, " nr %u, ns %u\n", session->nr, session->ns); seq_printf(m, " refcnt %d\n", refcount_read(&session->ref_count)); seq_printf(m, " config 0/0/%c/%c/-/%s %08x %u\n", session->recv_seq ? 'R' : '-', - session->send_seq ? 'S' : '-', + READ_ONCE(session->send_seq) ? 'S' : '-', session->lns_mode ? "LNS" : "LAC", 0, jiffies_to_msecs(session->reorder_timeout)); diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 38aac59d052c..89ef04c78787 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -700,12 +700,9 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf if (info->attrs[L2TP_ATTR_RECV_SEQ]) session->recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]); - if (info->attrs[L2TP_ATTR_SEND_SEQ]) { - struct l2tp_tunnel *tunnel = session->tunnel; - - session->send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]); - l2tp_session_set_header_len(session, tunnel->version, tunnel->encap); - } + if (info->attrs[L2TP_ATTR_SEND_SEQ]) + WRITE_ONCE(session->send_seq, + nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]) & 1); if (info->attrs[L2TP_ATTR_LNS_MODE]) session->lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]); @@ -748,7 +745,7 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl (session->peer_cookie_len && nla_put(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len, session->peer_cookie)) || nla_put_u8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq) || - nla_put_u8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq) || + nla_put_u8(skb, L2TP_ATTR_SEND_SEQ, READ_ONCE(session->send_seq)) || nla_put_u8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode) || (l2tp_tunnel_uses_xfrm(tunnel) && nla_put_u8(skb, L2TP_ATTR_USING_IPSEC, 1)) || diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index ef8fdfaf051d..4f311d473a64 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -1195,9 +1195,7 @@ static int pppol2tp_session_setsockopt(struct sock *sk, err = -EINVAL; break; } - session->send_seq = !!val; - l2tp_session_set_header_len(session, session->tunnel->version, - session->tunnel->encap); + WRITE_ONCE(session->send_seq, !!val); break; case PPPOL2TP_SO_LNSMODE: @@ -1307,7 +1305,7 @@ static int pppol2tp_session_getsockopt(struct sock *sk, break; case PPPOL2TP_SO_SENDSEQ: - *val = session->send_seq; + *val = READ_ONCE(session->send_seq); break; case PPPOL2TP_SO_LNSMODE: @@ -1546,7 +1544,7 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v) state, user_data_ok); seq_printf(m, " 0/0/%c/%c/%s %08x %u\n", session->recv_seq ? 'R' : '-', - session->send_seq ? 'S' : '-', + READ_ONCE(session->send_seq) ? 'S' : '-', session->lns_mode ? "LNS" : "LAC", 0, jiffies_to_msecs(session->reorder_timeout));