Skip to content

Commit 9e47df0

Browse files
lxindavem330
authored andcommitted
sctp: process sctp over udp icmp err on sctp side
Previously, sctp over udp was using udp tunnel's icmp err process, which only does sk lookup on sctp side. However for sctp's icmp error process, there are more things to do, like syncing assoc pmtu/retransmit packets for toobig type err, and starting proto_unreach_timer for unreach type err etc. Now after adding PLPMTUD, which also requires to process toobig type err on sctp side. This patch is to process icmp err on sctp side by parsing the type/code/info in .encap_err_lookup and call sctp's icmp processing functions. Note as the 'redirect' err process needs to know the outer ip(v6) header's, we have to leave it to udp(v6)_err to handle it. Signed-off-by: Xin Long <[email protected]> Acked-by: Marcelo Ricardo Leitner <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d830607 commit 9e47df0

File tree

4 files changed

+64
-19
lines changed

4 files changed

+64
-19
lines changed

include/net/sctp/sctp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
145145
struct sctphdr *, struct sctp_association **,
146146
struct sctp_transport **);
147147
void sctp_err_finish(struct sock *, struct sctp_transport *);
148+
int sctp_udp_v4_err(struct sock *sk, struct sk_buff *skb);
149+
int sctp_udp_v6_err(struct sock *sk, struct sk_buff *skb);
148150
void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
149151
struct sctp_transport *t, __u32 pmtu);
150152
void sctp_icmp_redirect(struct sock *, struct sctp_transport *,

net/sctp/input.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,36 @@ int sctp_v4_err(struct sk_buff *skb, __u32 info)
645645
return 0;
646646
}
647647

648+
int sctp_udp_v4_err(struct sock *sk, struct sk_buff *skb)
649+
{
650+
struct net *net = dev_net(skb->dev);
651+
struct sctp_association *asoc;
652+
struct sctp_transport *t;
653+
struct icmphdr *hdr;
654+
__u32 info = 0;
655+
656+
skb->transport_header += sizeof(struct udphdr);
657+
sk = sctp_err_lookup(net, AF_INET, skb, sctp_hdr(skb), &asoc, &t);
658+
if (!sk) {
659+
__ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
660+
return -ENOENT;
661+
}
662+
663+
skb->transport_header -= sizeof(struct udphdr);
664+
hdr = (struct icmphdr *)(skb_network_header(skb) - sizeof(struct icmphdr));
665+
if (hdr->type == ICMP_REDIRECT) {
666+
/* can't be handled without outer iphdr known, leave it to udp_err */
667+
sctp_err_finish(sk, t);
668+
return 0;
669+
}
670+
if (hdr->type == ICMP_DEST_UNREACH && hdr->code == ICMP_FRAG_NEEDED)
671+
info = ntohs(hdr->un.frag.mtu);
672+
sctp_v4_err_handle(t, skb, hdr->type, hdr->code, info);
673+
674+
sctp_err_finish(sk, t);
675+
return 1;
676+
}
677+
648678
/*
649679
* RFC 2960, 8.4 - Handle "Out of the blue" Packets.
650680
*

net/sctp/ipv6.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,36 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
188188
return 0;
189189
}
190190

191+
int sctp_udp_v6_err(struct sock *sk, struct sk_buff *skb)
192+
{
193+
struct net *net = dev_net(skb->dev);
194+
struct sctp_association *asoc;
195+
struct sctp_transport *t;
196+
struct icmp6hdr *hdr;
197+
__u32 info = 0;
198+
199+
skb->transport_header += sizeof(struct udphdr);
200+
sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &t);
201+
if (!sk) {
202+
__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
203+
return -ENOENT;
204+
}
205+
206+
skb->transport_header -= sizeof(struct udphdr);
207+
hdr = (struct icmp6hdr *)(skb_network_header(skb) - sizeof(struct icmp6hdr));
208+
if (hdr->icmp6_type == NDISC_REDIRECT) {
209+
/* can't be handled without outer ip6hdr known, leave it to udpv6_err */
210+
sctp_err_finish(sk, t);
211+
return 0;
212+
}
213+
if (hdr->icmp6_type == ICMPV6_PKT_TOOBIG)
214+
info = ntohl(hdr->icmp6_mtu);
215+
sctp_v6_err_handle(t, skb, hdr->icmp6_type, hdr->icmp6_code, info);
216+
217+
sctp_err_finish(sk, t);
218+
return 1;
219+
}
220+
191221
static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)
192222
{
193223
struct dst_entry *dst = dst_clone(t->dst);

net/sctp/protocol.c

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -850,23 +850,6 @@ static int sctp_udp_rcv(struct sock *sk, struct sk_buff *skb)
850850
return 0;
851851
}
852852

853-
static int sctp_udp_err_lookup(struct sock *sk, struct sk_buff *skb)
854-
{
855-
struct sctp_association *asoc;
856-
struct sctp_transport *t;
857-
int family;
858-
859-
skb->transport_header += sizeof(struct udphdr);
860-
family = (ip_hdr(skb)->version == 4) ? AF_INET : AF_INET6;
861-
sk = sctp_err_lookup(dev_net(skb->dev), family, skb, sctp_hdr(skb),
862-
&asoc, &t);
863-
if (!sk)
864-
return -ENOENT;
865-
866-
sctp_err_finish(sk, t);
867-
return 0;
868-
}
869-
870853
int sctp_udp_sock_start(struct net *net)
871854
{
872855
struct udp_tunnel_sock_cfg tuncfg = {NULL};
@@ -885,7 +868,7 @@ int sctp_udp_sock_start(struct net *net)
885868

886869
tuncfg.encap_type = 1;
887870
tuncfg.encap_rcv = sctp_udp_rcv;
888-
tuncfg.encap_err_lookup = sctp_udp_err_lookup;
871+
tuncfg.encap_err_lookup = sctp_udp_v4_err;
889872
setup_udp_tunnel_sock(net, sock, &tuncfg);
890873
net->sctp.udp4_sock = sock->sk;
891874

@@ -907,7 +890,7 @@ int sctp_udp_sock_start(struct net *net)
907890

908891
tuncfg.encap_type = 1;
909892
tuncfg.encap_rcv = sctp_udp_rcv;
910-
tuncfg.encap_err_lookup = sctp_udp_err_lookup;
893+
tuncfg.encap_err_lookup = sctp_udp_v6_err;
911894
setup_udp_tunnel_sock(net, sock, &tuncfg);
912895
net->sctp.udp6_sock = sock->sk;
913896
#endif

0 commit comments

Comments
 (0)