X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fudp.c;h=ec17e321854cd6f0158f80935d550e0937ba5337;hb=5020cac828f9f6c98a685598599a1dc798712005;hp=23f8f511d5064ded808ef51042bf7082180b2e24;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 23f8f511d..ec17e3218 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -120,6 +120,8 @@ rwlock_t udp_hash_lock = RW_LOCK_UNLOCKED; /* Shared by v4/v6 udp. */ int udp_port_rover; +int tcp_ipv4_addr_conflict(struct sock *sk1, struct sock *sk2); + static int udp_v4_get_port(struct sock *sk, unsigned short snum) { struct hlist_node *node; @@ -179,9 +181,7 @@ gotit: (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && - (!inet2->rcv_saddr || - !inet->rcv_saddr || - inet2->rcv_saddr == inet->rcv_saddr) && + tcp_ipv4_addr_conflict(sk2, sk) && (!sk2->sk_reuse || !sk->sk_reuse)) goto fail; } @@ -216,6 +216,17 @@ static void udp_v4_unhash(struct sock *sk) write_unlock_bh(&udp_hash_lock); } +static inline int udp_in_list(struct nx_info *nx_info, u32 addr) +{ + int n = nx_info->nbipv4; + int i; + + for (i=0; iipv4[i] == addr) + return 1; + return 0; +} + /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ @@ -235,6 +246,11 @@ struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport, u32 daddr, u16 dport, i if (inet->rcv_saddr != daddr) continue; score+=2; + } else if (sk->sk_nx_info) { + if (udp_in_list(sk->sk_nx_info, daddr)) + score+=2; + else + continue; } if (inet->daddr) { if (inet->daddr != saddr) @@ -290,7 +306,8 @@ static inline struct sock *udp_v4_mcast_next(struct sock *sk, if (inet->num != hnum || (inet->daddr && inet->daddr != rmt_addr) || (inet->dport != rmt_port && inet->dport) || - (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || + (inet->rcv_saddr && inet->rcv_saddr != loc_addr && + inet->rcv_saddr2 && inet->rcv_saddr2 != loc_addr) || ipv6_only_sock(s) || (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) continue; @@ -327,7 +344,7 @@ void udp_err(struct sk_buff *skb, u32 info) sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); if (sk == NULL) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(IcmpInErrors); return; /* No socket for error */ } @@ -599,6 +616,15 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, .uli_u = { .ports = { .sport = inet->sport, .dport = dport } } }; + struct nx_info *nxi = sk->sk_nx_info; + + if (nxi) { + err = ip_find_src(nxi, &rt, &fl); + if (err) + goto out; + if (daddr == IPI_LOOPBACK && !vx_check(0, VX_ADMIN)) + daddr = fl.fl4_dst = nxi->ipv4[0]; + } err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); if (err) goto out; @@ -654,7 +680,7 @@ out: if (free) kfree(ipc.opt); if (!err) { - UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); + UDP_INC_STATS_USER(UdpOutDatagrams); return len; } return err; @@ -828,10 +854,7 @@ try_again: } if (inet->cmsg_flags) ip_cmsg_recv(msg, skb); - err = copied; - if (flags & MSG_TRUNC) - err = skb->len - sizeof(struct udphdr); out_free: skb_free_datagram(sk, skb); @@ -839,7 +862,7 @@ out: return err; csum_copy_err: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UdpInErrors); /* Clear queue. */ if (flags&MSG_PEEK) { @@ -861,6 +884,54 @@ csum_copy_err: goto try_again; } +int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ + struct inet_opt *inet = inet_sk(sk); + struct sockaddr_in *usin = (struct sockaddr_in *) uaddr; + struct rtable *rt; + u32 saddr; + int oif; + int err; + + + if (addr_len < sizeof(*usin)) + return -EINVAL; + + if (usin->sin_family != AF_INET) + return -EAFNOSUPPORT; + + sk_dst_reset(sk); + + oif = sk->sk_bound_dev_if; + saddr = inet->saddr; + if (MULTICAST(usin->sin_addr.s_addr)) { + if (!oif) + oif = inet->mc_index; + if (!saddr) + saddr = inet->mc_addr; + } + err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr, + RT_CONN_FLAGS(sk), oif, + IPPROTO_UDP, + inet->sport, usin->sin_port, sk); + if (err) + return err; + if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) { + ip_rt_put(rt); + return -EACCES; + } + if (!inet->saddr) + inet->saddr = rt->rt_src; /* Update source address */ + if (!inet->rcv_saddr) + inet->rcv_saddr = rt->rt_src; + inet->daddr = rt->rt_dst; + inet->dport = usin->sin_port; + sk->sk_state = TCP_ESTABLISHED; + inet->id = jiffies; + + sk_dst_set(sk, &rt->u.dst); + return(0); +} int udp_disconnect(struct sock *sk, int flags) { @@ -930,7 +1001,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) } else /* Must be an IKE packet.. pass it through */ return 1; - break; + case UDP_ENCAP_ESPINUDP_NON_IKE: /* Check if this is a keepalive packet. If so, eat it. */ if (len == 1 && udpdata[0] == 0xff) { @@ -943,7 +1014,6 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) } else /* Must be an IKE packet.. pass it through */ return 1; - break; } /* At this point we are sure that this is an ESPinUDP packet, @@ -1016,7 +1086,7 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) if (ret < 0) { /* process the ESP packet */ ret = xfrm4_rcv_encap(skb, up->encap_type); - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + UDP_INC_STATS_BH(UdpInDatagrams); return -ret; } /* FALLTHROUGH -- it's a UDP Packet */ @@ -1024,7 +1094,7 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { if (__udp_checksum_complete(skb)) { - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return -1; } @@ -1032,11 +1102,11 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) } if (sock_queue_rcv_skb(sk,skb)<0) { - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return -1; } - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); + UDP_INC_STATS_BH(UdpInDatagrams); return 0; } @@ -1164,7 +1234,7 @@ int udp_rcv(struct sk_buff *skb) if (udp_checksum_complete(skb)) goto csum_error; - UDP_INC_STATS_BH(UDP_MIB_NOPORTS); + UDP_INC_STATS_BH(UdpNoPorts); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* @@ -1184,7 +1254,7 @@ short_packet: NIPQUAD(daddr), ntohs(uh->dest))); no_header: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return(0); @@ -1201,7 +1271,7 @@ csum_error: ntohs(uh->dest), ulen)); drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS); + UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return(0); } @@ -1307,7 +1377,7 @@ static int udp_getsockopt(struct sock *sk, int level, int optname, struct proto udp_prot = { .name = "UDP", .close = udp_close, - .connect = ip4_datagram_connect, + .connect = udp_connect, .disconnect = udp_disconnect, .ioctl = udp_ioctl, .destroy = udp_destroy_sock, @@ -1511,6 +1581,7 @@ void udp4_proc_exit(void) } #endif /* CONFIG_PROC_FS */ +EXPORT_SYMBOL(udp_connect); EXPORT_SYMBOL(udp_disconnect); EXPORT_SYMBOL(udp_hash); EXPORT_SYMBOL(udp_hash_lock);