Commit 48e24acb authored by David S. Miller's avatar David S. Miller

Merge davem@nuts.davemloft.net:/disk1/BK/net-2.6

into kernel.bkbits.net:/home/davem/net-2.6
parents 0092e993 4f6aeb92
#ifndef _IP6T_REJECT_H
#define _IP6T_REJECT_H
enum ip6t_reject_with {
IP6T_ICMP_NET_UNREACHABLE,
IP6T_ICMP_HOST_UNREACHABLE,
IP6T_ICMP_PROT_UNREACHABLE,
IP6T_ICMP_PORT_UNREACHABLE,
IP6T_ICMP_ECHOREPLY
};
struct ip6t_reject_info {
enum ip6t_reject_with with; /* reject type */
};
#endif /*_IPT_REJECT_H*/
...@@ -134,13 +134,6 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t ...@@ -134,13 +134,6 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t
void netlink_detachskb(struct sock *sk, struct sk_buff *skb); void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol); int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
/* finegrained unicast helpers: */
struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid);
struct sock *netlink_getsockbyfilp(struct file *filp);
int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long timeo);
void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
/* /*
* skb should fit one page. This choice is good for headerless malloc. * skb should fit one page. This choice is good for headerless malloc.
* *
......
...@@ -402,6 +402,16 @@ enum { ...@@ -402,6 +402,16 @@ enum {
#define TCA_ATM_MAX TCA_ATM_STATE #define TCA_ATM_MAX TCA_ATM_STATE
/* Network emulator */ /* Network emulator */
enum
{
TCA_NETEM_UNSPEC,
TCA_NETEM_CORR,
TCA_NETEM_DELAY_DIST,
};
#define TCA_NETEM_MAX TCA_NETEM_DELAY_DIST
struct tc_netem_qopt struct tc_netem_qopt
{ {
__u32 latency; /* added delay (us) */ __u32 latency; /* added delay (us) */
...@@ -411,4 +421,19 @@ struct tc_netem_qopt ...@@ -411,4 +421,19 @@ struct tc_netem_qopt
__u32 duplicate; /* random packet dup (0=none ~0=100%) */ __u32 duplicate; /* random packet dup (0=none ~0=100%) */
__u32 jitter; /* random jitter in latency (us) */ __u32 jitter; /* random jitter in latency (us) */
}; };
struct tc_netem_corr
{
__u32 delay_corr; /* delay correlation */
__u32 loss_corr; /* packet loss correlation */
__u32 dup_corr; /* duplicate correlation */
};
struct tc_netem_dist
{
__u32 size; /* table size */
__u32 factor; /* table scaling factor */
__s16 data[0]; /* distribution table values */
};
#endif #endif
...@@ -106,7 +106,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr, ...@@ -106,7 +106,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
{ {
char *arpptr = (char *)(arphdr + 1); char *arpptr = (char *)(arphdr + 1);
char *src_devaddr, *tgt_devaddr; char *src_devaddr, *tgt_devaddr;
u32 *src_ipaddr, *tgt_ipaddr; u32 src_ipaddr, tgt_ipaddr;
int i, ret; int i, ret;
#define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg)) #define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg))
...@@ -145,11 +145,11 @@ static inline int arp_packet_match(const struct arphdr *arphdr, ...@@ -145,11 +145,11 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
src_devaddr = arpptr; src_devaddr = arpptr;
arpptr += dev->addr_len; arpptr += dev->addr_len;
src_ipaddr = (u32 *) arpptr; memcpy(&src_ipaddr, arpptr, sizeof(u32));
arpptr += sizeof(u32); arpptr += sizeof(u32);
tgt_devaddr = arpptr; tgt_devaddr = arpptr;
arpptr += dev->addr_len; arpptr += dev->addr_len;
tgt_ipaddr = (u32 *) arpptr; memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len), if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len),
ARPT_INV_SRCDEVADDR) || ARPT_INV_SRCDEVADDR) ||
...@@ -160,19 +160,19 @@ static inline int arp_packet_match(const struct arphdr *arphdr, ...@@ -160,19 +160,19 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
return 0; return 0;
} }
if (FWINV(((*src_ipaddr) & arpinfo->smsk.s_addr) != arpinfo->src.s_addr, if (FWINV((src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr,
ARPT_INV_SRCIP) || ARPT_INV_SRCIP) ||
FWINV((((*tgt_ipaddr) & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr), FWINV(((tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr),
ARPT_INV_TGTIP)) { ARPT_INV_TGTIP)) {
dprintf("Source or target IP address mismatch.\n"); dprintf("Source or target IP address mismatch.\n");
dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n", dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
NIPQUAD(*src_ipaddr), NIPQUAD(src_ipaddr),
NIPQUAD(arpinfo->smsk.s_addr), NIPQUAD(arpinfo->smsk.s_addr),
NIPQUAD(arpinfo->src.s_addr), NIPQUAD(arpinfo->src.s_addr),
arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : ""); arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : "");
dprintf("TGT: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n", dprintf("TGT: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
NIPQUAD(*tgt_ipaddr), NIPQUAD(tgt_ipaddr),
NIPQUAD(arpinfo->tmsk.s_addr), NIPQUAD(arpinfo->tmsk.s_addr),
NIPQUAD(arpinfo->tgt.s_addr), NIPQUAD(arpinfo->tgt.s_addr),
arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : ""); arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : "");
......
...@@ -38,7 +38,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -38,7 +38,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct in6_addr *daddr; struct in6_addr *daddr, *final_p = NULL, final;
struct dst_entry *dst; struct dst_entry *dst;
struct flowi fl; struct flowi fl;
struct ip6_flowlabel *flowlabel = NULL; struct ip6_flowlabel *flowlabel = NULL;
...@@ -157,16 +157,27 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -157,16 +157,27 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (flowlabel) { if (flowlabel) {
if (flowlabel->opt && flowlabel->opt->srcrt) { if (flowlabel->opt && flowlabel->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
} else if (np->opt && np->opt->srcrt) { } else if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
err = ip6_dst_lookup(sk, &dst, &fl); err = ip6_dst_lookup(sk, &dst, &fl);
if (err) if (err)
goto out; goto out;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
dst_release(dst);
goto out;
}
/* source address lookup done in ip6_dst_lookup */ /* source address lookup done in ip6_dst_lookup */
......
...@@ -796,10 +796,6 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) ...@@ -796,10 +796,6 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
goto out_err_release; goto out_err_release;
} }
} }
if ((err = xfrm_lookup(dst, fl, sk, 0)) < 0) {
err = -ENETUNREACH;
goto out_err_release;
}
return 0; return 0;
......
...@@ -606,7 +606,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -606,7 +606,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
{ {
struct ipv6_txoptions opt_space; struct ipv6_txoptions opt_space;
struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name; struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
struct in6_addr *daddr; struct in6_addr *daddr, *final_p = NULL, final;
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct raw6_opt *raw_opt = raw6_sk(sk); struct raw6_opt *raw_opt = raw6_sk(sk);
...@@ -729,7 +729,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -729,7 +729,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
/* merge ip6_build_xmit from ip6_output */ /* merge ip6_build_xmit from ip6_output */
if (opt && opt->srcrt) { if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
...@@ -738,6 +740,13 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -738,6 +740,13 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
err = ip6_dst_lookup(sk, &dst, &fl); err = ip6_dst_lookup(sk, &dst, &fl);
if (err) if (err)
goto out; goto out;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
dst_release(dst);
goto out;
}
if (hlimit < 0) { if (hlimit < 0) {
if (ipv6_addr_is_multicast(&fl.fl6_dst)) if (ipv6_addr_is_multicast(&fl.fl6_dst))
......
...@@ -549,7 +549,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -549,7 +549,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct tcp_opt *tp = tcp_sk(sk); struct tcp_opt *tp = tcp_sk(sk);
struct in6_addr *saddr = NULL; struct in6_addr *saddr = NULL, *final_p = NULL, final;
struct flowi fl; struct flowi fl;
struct dst_entry *dst; struct dst_entry *dst;
int addr_type; int addr_type;
...@@ -666,13 +666,21 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -666,13 +666,21 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
if (np->opt && np->opt->srcrt) { if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
err = ip6_dst_lookup(sk, &dst, &fl); err = ip6_dst_lookup(sk, &dst, &fl);
if (err) if (err)
goto failure; goto failure;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
dst_release(dst);
goto failure;
}
if (saddr == NULL) { if (saddr == NULL) {
saddr = &fl.fl6_src; saddr = &fl.fl6_src;
...@@ -793,6 +801,12 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -793,6 +801,12 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
sk->sk_err_soft = -err; sk->sk_err_soft = -err;
goto out; goto out;
} }
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
sk->sk_err_soft = -err;
goto out;
}
} else } else
dst_hold(dst); dst_hold(dst);
...@@ -863,6 +877,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req, ...@@ -863,6 +877,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req,
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct sk_buff * skb; struct sk_buff * skb;
struct ipv6_txoptions *opt = NULL; struct ipv6_txoptions *opt = NULL;
struct in6_addr * final_p = NULL, final;
struct flowi fl; struct flowi fl;
int err = -1; int err = -1;
...@@ -888,12 +903,18 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req, ...@@ -888,12 +903,18 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req,
if (opt && opt->srcrt) { if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
err = ip6_dst_lookup(sk, &dst, &fl); err = ip6_dst_lookup(sk, &dst, &fl);
if (err) if (err)
goto done; goto done;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
goto done;
} }
skb = tcp_make_synack(sk, dst, req); skb = tcp_make_synack(sk, dst, req);
...@@ -1021,6 +1042,12 @@ static void tcp_v6_send_reset(struct sk_buff *skb) ...@@ -1021,6 +1042,12 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
/* sk = NULL, but it is safe for now. RST socket required. */ /* sk = NULL, but it is safe for now. RST socket required. */
if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
dst_release(buff->dst);
return;
}
ip6_xmit(NULL, buff, &fl, NULL, 0); ip6_xmit(NULL, buff, &fl, NULL, 0);
TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
...@@ -1082,6 +1109,10 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ...@@ -1082,6 +1109,10 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
fl.fl_ip_sport = t1->source; fl.fl_ip_sport = t1->source;
if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
dst_release(buff->dst);
return;
}
ip6_xmit(NULL, buff, &fl, NULL, 0); ip6_xmit(NULL, buff, &fl, NULL, 0);
TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
return; return;
...@@ -1313,6 +1344,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1313,6 +1344,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
} }
if (dst == NULL) { if (dst == NULL) {
struct in6_addr *final_p = NULL, final;
struct flowi fl; struct flowi fl;
memset(&fl, 0, sizeof(fl)); memset(&fl, 0, sizeof(fl));
...@@ -1320,7 +1352,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1320,7 +1352,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
ipv6_addr_copy(&fl.fl6_dst, &req->af.v6_req.rmt_addr); ipv6_addr_copy(&fl.fl6_dst, &req->af.v6_req.rmt_addr);
if (opt && opt->srcrt) { if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
ipv6_addr_copy(&fl.fl6_src, &req->af.v6_req.loc_addr); ipv6_addr_copy(&fl.fl6_src, &req->af.v6_req.loc_addr);
fl.oif = sk->sk_bound_dev_if; fl.oif = sk->sk_bound_dev_if;
...@@ -1329,6 +1363,12 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1329,6 +1363,12 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
if (ip6_dst_lookup(sk, &dst, &fl)) if (ip6_dst_lookup(sk, &dst, &fl))
goto out; goto out;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
goto out;
} }
newsk = tcp_create_openreq_child(sk, req, skb); newsk = tcp_create_openreq_child(sk, req, skb);
...@@ -1710,6 +1750,7 @@ static int tcp_v6_rebuild_header(struct sock *sk) ...@@ -1710,6 +1750,7 @@ static int tcp_v6_rebuild_header(struct sock *sk)
if (dst == NULL) { if (dst == NULL) {
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct in6_addr *final_p = NULL, final;
struct flowi fl; struct flowi fl;
memset(&fl, 0, sizeof(fl)); memset(&fl, 0, sizeof(fl));
...@@ -1723,15 +1764,24 @@ static int tcp_v6_rebuild_header(struct sock *sk) ...@@ -1723,15 +1764,24 @@ static int tcp_v6_rebuild_header(struct sock *sk)
if (np->opt && np->opt->srcrt) { if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
err = ip6_dst_lookup(sk, &dst, &fl); err = ip6_dst_lookup(sk, &dst, &fl);
if (err) { if (err) {
sk->sk_route_caps = 0; sk->sk_route_caps = 0;
return err; return err;
} }
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
sk->sk_err_soft = -err;
dst_release(dst);
return err;
}
ip6_dst_store(sk, dst, NULL); ip6_dst_store(sk, dst, NULL);
sk->sk_route_caps = dst->dev->features & sk->sk_route_caps = dst->dev->features &
...@@ -1775,6 +1825,12 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok) ...@@ -1775,6 +1825,12 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
return err; return err;
} }
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
sk->sk_route_caps = 0;
dst_release(dst);
return err;
}
ip6_dst_store(sk, dst, NULL); ip6_dst_store(sk, dst, NULL);
sk->sk_route_caps = dst->dev->features & sk->sk_route_caps = dst->dev->features &
~(NETIF_F_IP_CSUM | NETIF_F_TSO); ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
......
...@@ -627,7 +627,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -627,7 +627,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
struct in6_addr *daddr; struct in6_addr *daddr, *final_p = NULL, final;
struct ipv6_txoptions *opt = NULL; struct ipv6_txoptions *opt = NULL;
struct ip6_flowlabel *flowlabel = NULL; struct ip6_flowlabel *flowlabel = NULL;
struct flowi *fl = &inet->cork.fl; struct flowi *fl = &inet->cork.fl;
...@@ -783,7 +783,9 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -783,7 +783,9 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
/* merge ip6_build_xmit from ip6_output */ /* merge ip6_build_xmit from ip6_output */
if (opt && opt->srcrt) { if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
ipv6_addr_copy(&final, &fl->fl6_dst);
ipv6_addr_copy(&fl->fl6_dst, rt0->addr); ipv6_addr_copy(&fl->fl6_dst, rt0->addr);
final_p = &final;
} }
if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst))
...@@ -792,6 +794,13 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -792,6 +794,13 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
err = ip6_dst_lookup(sk, &dst, fl); err = ip6_dst_lookup(sk, &dst, fl);
if (err) if (err)
goto out; goto out;
if (final_p)
ipv6_addr_copy(&fl->fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) {
dst_release(dst);
goto out;
}
if (hlimit < 0) { if (hlimit < 0) {
if (ipv6_addr_is_multicast(&fl->fl6_dst)) if (ipv6_addr_is_multicast(&fl->fl6_dst))
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <linux/security.h> #include <linux/security.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/scm.h> #include <net/scm.h>
#include <linux/workqueue.h>
#define Nprintk(a...) #define Nprintk(a...)
...@@ -69,6 +70,14 @@ struct netlink_opt ...@@ -69,6 +70,14 @@ struct netlink_opt
#define nlk_sk(__sk) ((struct netlink_opt *)(__sk)->sk_protinfo) #define nlk_sk(__sk) ((struct netlink_opt *)(__sk)->sk_protinfo)
struct netlink_work
{
struct sock *sk;
int len;
struct work_struct work;
};
static struct workqueue_struct *netlink_wq;
static struct hlist_head nl_table[MAX_LINKS]; static struct hlist_head nl_table[MAX_LINKS];
static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
static unsigned nl_nonroot[MAX_LINKS]; static unsigned nl_nonroot[MAX_LINKS];
...@@ -87,6 +96,16 @@ static atomic_t nl_table_users = ATOMIC_INIT(0); ...@@ -87,6 +96,16 @@ static atomic_t nl_table_users = ATOMIC_INIT(0);
static struct notifier_block *netlink_chain; static struct notifier_block *netlink_chain;
/* netlink workqueue handler */
static void netlink_wq_handler(void *data)
{
struct netlink_work *work = data;
work->sk->sk_data_ready(work->sk, work->len);
sock_put(work->sk);
kfree(work);
}
static void netlink_sock_destruct(struct sock *sk) static void netlink_sock_destruct(struct sock *sk)
{ {
skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_receive_queue);
...@@ -478,6 +497,8 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t ...@@ -478,6 +497,8 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t
if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
test_bit(0, &nlk->state)) { test_bit(0, &nlk->state)) {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
task_t *client;
if (!timeo) { if (!timeo) {
if (!nlk->pid) if (!nlk->pid)
netlink_overrun(sk); netlink_overrun(sk);
...@@ -486,6 +507,19 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t ...@@ -486,6 +507,19 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t
return -EAGAIN; return -EAGAIN;
} }
if (nlk->pid) {
/* Kernel is sending information to user space
* and socket buffer is full: Wake up user
* process */
client = find_task_by_pid(nlk->pid);
if (!client) {
sock_put(sk);
kfree_skb(skb);
return -EAGAIN;
}
wake_up_process(client);
}
__set_current_state(TASK_INTERRUPTIBLE); __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&nlk->wait, &wait); add_wait_queue(&nlk->wait, &wait);
...@@ -525,8 +559,24 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol) ...@@ -525,8 +559,24 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol)
#endif #endif
skb_queue_tail(&sk->sk_receive_queue, skb); skb_queue_tail(&sk->sk_receive_queue, skb);
sk->sk_data_ready(sk, len); if (!nlk->pid) {
sock_put(sk); struct netlink_work *nlwork =
kmalloc(sizeof(struct netlink_work), GFP_KERNEL);
if (!nlwork) {
sock_put(sk);
return -EAGAIN;
}
INIT_WORK(&nlwork->work, netlink_wq_handler, nlwork);
nlwork->sk = sk;
nlwork->len = len;
queue_work(netlink_wq, &nlwork->work);
} else {
sk->sk_data_ready(sk, len);
sock_put(sk);
}
return len; return len;
} }
...@@ -573,7 +623,21 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff ...@@ -573,7 +623,21 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff
skb_orphan(skb); skb_orphan(skb);
skb_set_owner_r(skb, sk); skb_set_owner_r(skb, sk);
skb_queue_tail(&sk->sk_receive_queue, skb); skb_queue_tail(&sk->sk_receive_queue, skb);
sk->sk_data_ready(sk, skb->len);
if (!nlk->pid) {
struct netlink_work *nlwork =
kmalloc(sizeof(struct netlink_work), GFP_KERNEL);
if (!nlwork)
return -1;
INIT_WORK(&nlwork->work, netlink_wq_handler, nlwork);
nlwork->sk = sk;
nlwork->len = skb->len;
queue_work(netlink_wq, &nlwork->work);
} else
sk->sk_data_ready(sk, skb->len);
return 0; return 0;
} }
return -1; return -1;
...@@ -619,13 +683,14 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, ...@@ -619,13 +683,14 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
netlink_overrun(sk); netlink_overrun(sk);
/* Clone failed. Notify ALL listeners. */ /* Clone failed. Notify ALL listeners. */
failure = 1; failure = 1;
sock_put(sk);
} else if (netlink_broadcast_deliver(sk, skb2)) { } else if (netlink_broadcast_deliver(sk, skb2)) {
netlink_overrun(sk); netlink_overrun(sk);
sock_put(sk);
} else { } else {
delivered = 1; delivered = 1;
skb2 = NULL; skb2 = NULL;
} }
sock_put(sk);
} }
netlink_unlock_table(); netlink_unlock_table();
...@@ -1202,6 +1267,9 @@ static int __init netlink_proto_init(void) ...@@ -1202,6 +1267,9 @@ static int __init netlink_proto_init(void)
#endif #endif
/* The netlink device handler may be needed early. */ /* The netlink device handler may be needed early. */
rtnetlink_init(); rtnetlink_init();
/* Create a work queue to handle callbacks to modules */
netlink_wq = create_workqueue("netlink");
return 0; return 0;
} }
...@@ -1209,6 +1277,7 @@ static void __exit netlink_proto_exit(void) ...@@ -1209,6 +1277,7 @@ static void __exit netlink_proto_exit(void)
{ {
sock_unregister(PF_NETLINK); sock_unregister(PF_NETLINK);
proc_net_remove("netlink"); proc_net_remove("netlink");
destroy_workqueue(netlink_wq);
} }
core_initcall(netlink_proto_init); core_initcall(netlink_proto_init);
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ioctls.h> #include <asm/ioctls.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/io.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/poll.h> #include <linux/poll.h>
...@@ -173,7 +174,7 @@ struct packet_opt ...@@ -173,7 +174,7 @@ struct packet_opt
{ {
struct tpacket_stats stats; struct tpacket_stats stats;
#ifdef CONFIG_PACKET_MMAP #ifdef CONFIG_PACKET_MMAP
unsigned long *pg_vec; char * *pg_vec;
unsigned int head; unsigned int head;
unsigned int frames_per_block; unsigned int frames_per_block;
unsigned int frame_size; unsigned int frame_size;
...@@ -198,15 +199,15 @@ struct packet_opt ...@@ -198,15 +199,15 @@ struct packet_opt
#ifdef CONFIG_PACKET_MMAP #ifdef CONFIG_PACKET_MMAP
static inline unsigned long packet_lookup_frame(struct packet_opt *po, unsigned int position) static inline char *packet_lookup_frame(struct packet_opt *po, unsigned int position)
{ {
unsigned int pg_vec_pos, frame_offset; unsigned int pg_vec_pos, frame_offset;
unsigned long frame; char *frame;
pg_vec_pos = position / po->frames_per_block; pg_vec_pos = position / po->frames_per_block;
frame_offset = position % po->frames_per_block; frame_offset = position % po->frames_per_block;
frame = (unsigned long) (po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size)); frame = po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size);
return frame; return frame;
} }
...@@ -1549,7 +1550,12 @@ static struct vm_operations_struct packet_mmap_ops = { ...@@ -1549,7 +1550,12 @@ static struct vm_operations_struct packet_mmap_ops = {
.close =packet_mm_close, .close =packet_mm_close,
}; };
static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len) static inline struct page *pg_vec_endpage(char *one_pg_vec, unsigned int order)
{
return virt_to_page(one_pg_vec + (PAGE_SIZE << order) - 1);
}
static void free_pg_vec(char **pg_vec, unsigned order, unsigned len)
{ {
int i; int i;
...@@ -1557,10 +1563,10 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len) ...@@ -1557,10 +1563,10 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len)
if (pg_vec[i]) { if (pg_vec[i]) {
struct page *page, *pend; struct page *page, *pend;
pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1); pend = pg_vec_endpage(pg_vec[i], order);
for (page = virt_to_page(pg_vec[i]); page <= pend; page++) for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
ClearPageReserved(page); ClearPageReserved(page);
free_pages(pg_vec[i], order); free_pages((unsigned long)pg_vec[i], order);
} }
} }
kfree(pg_vec); kfree(pg_vec);
...@@ -1569,7 +1575,7 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len) ...@@ -1569,7 +1575,7 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len)
static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing) static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing)
{ {
unsigned long *pg_vec = NULL; char **pg_vec = NULL;
struct packet_opt *po = pkt_sk(sk); struct packet_opt *po = pkt_sk(sk);
int was_running, num, order = 0; int was_running, num, order = 0;
int err = 0; int err = 0;
...@@ -1604,18 +1610,18 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing ...@@ -1604,18 +1610,18 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
err = -ENOMEM; err = -ENOMEM;
pg_vec = kmalloc(req->tp_block_nr*sizeof(unsigned long*), GFP_KERNEL); pg_vec = kmalloc(req->tp_block_nr*sizeof(char *), GFP_KERNEL);
if (pg_vec == NULL) if (pg_vec == NULL)
goto out; goto out;
memset(pg_vec, 0, req->tp_block_nr*sizeof(unsigned long*)); memset(pg_vec, 0, req->tp_block_nr*sizeof(char **));
for (i=0; i<req->tp_block_nr; i++) { for (i=0; i<req->tp_block_nr; i++) {
struct page *page, *pend; struct page *page, *pend;
pg_vec[i] = __get_free_pages(GFP_KERNEL, order); pg_vec[i] = (char *)__get_free_pages(GFP_KERNEL, order);
if (!pg_vec[i]) if (!pg_vec[i])
goto out_free_pgvec; goto out_free_pgvec;
pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1); pend = pg_vec_endpage(pg_vec[i], order);
for (page = virt_to_page(pg_vec[i]); page <= pend; page++) for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
SetPageReserved(page); SetPageReserved(page);
} }
...@@ -1623,7 +1629,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing ...@@ -1623,7 +1629,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
l = 0; l = 0;
for (i=0; i<req->tp_block_nr; i++) { for (i=0; i<req->tp_block_nr; i++) {
unsigned long ptr = pg_vec[i]; char *ptr = pg_vec[i];
struct tpacket_hdr *header; struct tpacket_hdr *header;
int k; int k;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment