From 6736dc35e9e1b9c8084d5c362a429a3e8189af6b Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 2 Dec 2005 20:30:06 -0800 Subject: [SCTP]: Return socket errors only if the receive queue is empty. This patch fixes an issue where it is possible to get valid data after a ENOTCONN error. It returns socket errors only after data queued on socket receive queue is consumed. Signed-off-by: Neil Horman Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/socket.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index abab81f3818..d890dfa8818 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4743,11 +4743,6 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, struct sk_buff *skb; long timeo; - /* Caller is allowed not to check sk->sk_err before calling. */ - error = sock_error(sk); - if (error) - goto no_packet; - timeo = sock_rcvtimeo(sk, noblock); SCTP_DEBUG_PRINTK("Timeout: timeo: %ld, MAX: %ld.\n", @@ -4774,6 +4769,11 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, if (skb) return skb; + /* Caller is allowed not to check sk->sk_err before calling. */ + error = sock_error(sk); + if (error) + goto no_packet; + if (sk->sk_shutdown & RCV_SHUTDOWN) break; -- cgit v1.2.3 From bf031fff1fac77775b2cd2c72ad8b017f4c0af13 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 2 Dec 2005 20:32:29 -0800 Subject: [SCTP]: Fix getsockname for sctp when an ipv6 socket accepts a connection from an ipv4 socket. Signed-off-by: Neil Horman Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/transport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 6bc27200e6c..268ddaf2dc0 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -261,7 +261,8 @@ void sctp_transport_route(struct sctp_transport *transport, * association's active path for getsockname(). */ if (asoc && (transport == asoc->peer.active_path)) - af->to_sk_saddr(&transport->saddr, asoc->base.sk); + opt->pf->af->to_sk_saddr(&transport->saddr, + asoc->base.sk); } else transport->pmtu = SCTP_DEFAULT_MAXSEGMENT; } -- cgit v1.2.3 From 24c6927505ca77ee4ac25fb31dcd56f6506979ed Mon Sep 17 00:00:00 2001 From: David Stevens Date: Fri, 2 Dec 2005 20:32:59 -0800 Subject: [IGMP]: workaround for IGMP v1/v2 bug From: David Stevens As explained at: http://www.cs.ucsb.edu/~krishna/igmp_dos/ With IGMP version 1 and 2 it is possible to inject a unicast report to a client which will make it ignore multicast reports sent later by the router. The fix is to only accept the report if is was sent to a multicast or unicast address. Signed-off-by: David S. Miller --- net/ipv4/igmp.c | 5 ++++- net/ipv6/mcast.c | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index c04607b4921..4a195c724f0 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -897,7 +897,10 @@ int igmp_rcv(struct sk_buff *skb) /* Is it our report looped back? */ if (((struct rtable*)skb->dst)->fl.iif == 0) break; - igmp_heard_report(in_dev, ih->group); + /* don't rely on MC router hearing unicast reports */ + if (skb->pkt_type == PACKET_MULTICAST || + skb->pkt_type == PACKET_BROADCAST) + igmp_heard_report(in_dev, ih->group); break; case IGMP_PIM: #ifdef CONFIG_IP_PIMSM_V1 diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index f15e04ad026..fd939da090c 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1231,6 +1231,11 @@ int igmp6_event_report(struct sk_buff *skb) if (skb->pkt_type == PACKET_LOOPBACK) return 0; + /* send our report if the MC router may not have heard this report */ + if (skb->pkt_type != PACKET_MULTICAST && + skb->pkt_type != PACKET_BROADCAST) + return 0; + if (!pskb_may_pull(skb, sizeof(struct in6_addr))) return -EINVAL; -- cgit v1.2.3 From 86c8f9d158f68538a971a47206a46a22c7479bac Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 2 Dec 2005 20:43:26 -0800 Subject: [IPV4] Fix EPROTONOSUPPORT error in inet_create There is a coding error in inet_create that causes it to always return ESOCKTNOSUPPORT. It should return EPROTONOSUPPORT when there are protocols registered for a given socket type but none of them match the requested protocol. This is based on a patch by Jayachandran C. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index eaa150c33b0..d368cf24900 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -228,13 +228,14 @@ static int inet_create(struct socket *sock, int protocol) unsigned char answer_flags; char answer_no_check; int try_loading_module = 0; - int err = -ESOCKTNOSUPPORT; + int err; sock->state = SS_UNCONNECTED; /* Look for the requested type/protocol pair. */ answer = NULL; lookup_protocol: + err = -ESOCKTNOSUPPORT; rcu_read_lock(); list_for_each_rcu(p, &inetsw[sock->type]) { answer = list_entry(p, struct inet_protosw, list); @@ -252,6 +253,7 @@ lookup_protocol: if (IPPROTO_IP == answer->protocol) break; } + err = -EPROTONOSUPPORT; answer = NULL; } @@ -280,9 +282,6 @@ lookup_protocol: err = -EPERM; if (answer->capability > 0 && !capable(answer->capability)) goto out_rcu_unlock; - err = -EPROTONOSUPPORT; - if (!protocol) - goto out_rcu_unlock; sock->ops = answer->ops; answer_prot = answer->prot; -- cgit v1.2.3 From af1afe866297448ad8a1da99fa8a6af86c43c909 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 2 Dec 2005 20:56:57 -0800 Subject: [IPV6]: Load protocol module dynamically. [ Modified to match inet_create() bug fix by Herbert Xu -DaveM ] Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index c63b8ce0e1b..d9546380fa0 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -92,10 +92,13 @@ static int inet6_create(struct socket *sock, int protocol) struct proto *answer_prot; unsigned char answer_flags; char answer_no_check; - int rc; + int try_loading_module = 0; + int err; /* Look for the requested type/protocol pair. */ answer = NULL; +lookup_protocol: + err = -ESOCKTNOSUPPORT; rcu_read_lock(); list_for_each_rcu(p, &inetsw6[sock->type]) { answer = list_entry(p, struct inet_protosw, list); @@ -113,21 +116,37 @@ static int inet6_create(struct socket *sock, int protocol) if (IPPROTO_IP == answer->protocol) break; } + err = -EPROTONOSUPPORT; answer = NULL; } - rc = -ESOCKTNOSUPPORT; - if (!answer) - goto out_rcu_unlock; - rc = -EPERM; + if (!answer) { + if (try_loading_module < 2) { + rcu_read_unlock(); + /* + * Be more specific, e.g. net-pf-10-proto-132-type-1 + * (net-pf-PF_INET6-proto-IPPROTO_SCTP-type-SOCK_STREAM) + */ + if (++try_loading_module == 1) + request_module("net-pf-%d-proto-%d-type-%d", + PF_INET6, protocol, sock->type); + /* + * Fall back to generic, e.g. net-pf-10-proto-132 + * (net-pf-PF_INET6-proto-IPPROTO_SCTP) + */ + else + request_module("net-pf-%d-proto-%d", + PF_INET6, protocol); + goto lookup_protocol; + } else + goto out_rcu_unlock; + } + + err = -EPERM; if (answer->capability > 0 && !capable(answer->capability)) goto out_rcu_unlock; - rc = -EPROTONOSUPPORT; - if (!protocol) - goto out_rcu_unlock; sock->ops = answer->ops; - answer_prot = answer->prot; answer_no_check = answer->no_check; answer_flags = answer->flags; @@ -135,14 +154,14 @@ static int inet6_create(struct socket *sock, int protocol) BUG_TRAP(answer_prot->slab != NULL); - rc = -ENOBUFS; + err = -ENOBUFS; sk = sk_alloc(PF_INET6, GFP_KERNEL, answer_prot, 1); if (sk == NULL) goto out; sock_init_data(sock, sk); - rc = 0; + err = 0; sk->sk_no_check = answer_no_check; if (INET_PROTOSW_REUSE & answer_flags) sk->sk_reuse = 1; @@ -202,14 +221,14 @@ static int inet6_create(struct socket *sock, int protocol) sk->sk_prot->hash(sk); } if (sk->sk_prot->init) { - rc = sk->sk_prot->init(sk); - if (rc) { + err = sk->sk_prot->init(sk); + if (err) { sk_common_release(sk); goto out; } } out: - return rc; + return err; out_rcu_unlock: rcu_read_unlock(); goto out; -- cgit v1.2.3