mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-06 05:13:18 +00:00
ipv4: processing ancillary IP_TOS or IP_TTL
If IP_TOS or IP_TTL are specified as ancillary data, then sendmsg() sends out packets with the specified TTL or TOS overriding the socket values specified with the traditional setsockopt(). The struct inet_cork stores the values of TOS, TTL and priority that are passed through the struct ipcm_cookie. If there are user-specified TOS (tos != -1) or TTL (ttl != 0) in the struct ipcm_cookie, these values are used to override the per-socket values. In case of TOS also the priority is changed accordingly. Two helper functions get_rttos and get_rtconn_flags are defined to take into account the presence of a user specified TOS value when computing RT_TOS and RT_CONN_FLAGS. Signed-off-by: Francesco Fusco <ffusco@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f02db315b8
commit
aa66158145
@ -103,6 +103,9 @@ struct inet_cork {
|
|||||||
int length; /* Total length of all frames */
|
int length; /* Total length of all frames */
|
||||||
struct dst_entry *dst;
|
struct dst_entry *dst;
|
||||||
u8 tx_flags;
|
u8 tx_flags;
|
||||||
|
__u8 ttl;
|
||||||
|
__s16 tos;
|
||||||
|
char priority;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct inet_cork_full {
|
struct inet_cork_full {
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
|
|
||||||
#include <net/inet_sock.h>
|
#include <net/inet_sock.h>
|
||||||
|
#include <net/route.h>
|
||||||
#include <net/snmp.h>
|
#include <net/snmp.h>
|
||||||
#include <net/flow.h>
|
#include <net/flow.h>
|
||||||
|
|
||||||
@ -140,6 +141,16 @@ static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4)
|
|||||||
return __ip_make_skb(sk, fl4, &sk->sk_write_queue, &inet_sk(sk)->cork.base);
|
return __ip_make_skb(sk, fl4, &sk->sk_write_queue, &inet_sk(sk)->cork.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline __u8 get_rttos(struct ipcm_cookie* ipc, struct inet_sock *inet)
|
||||||
|
{
|
||||||
|
return (ipc->tos != -1) ? RT_TOS(ipc->tos) : RT_TOS(inet->tos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u8 get_rtconn_flags(struct ipcm_cookie* ipc, struct sock* sk)
|
||||||
|
{
|
||||||
|
return (ipc->tos != -1) ? RT_CONN_FLAGS_TOS(sk, ipc->tos) : RT_CONN_FLAGS(sk);
|
||||||
|
}
|
||||||
|
|
||||||
/* datagram.c */
|
/* datagram.c */
|
||||||
int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
|
int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#define RTO_ONLINK 0x01
|
#define RTO_ONLINK 0x01
|
||||||
|
|
||||||
#define RT_CONN_FLAGS(sk) (RT_TOS(inet_sk(sk)->tos) | sock_flag(sk, SOCK_LOCALROUTE))
|
#define RT_CONN_FLAGS(sk) (RT_TOS(inet_sk(sk)->tos) | sock_flag(sk, SOCK_LOCALROUTE))
|
||||||
|
#define RT_CONN_FLAGS_TOS(sk,tos) (RT_TOS(tos) | sock_flag(sk, SOCK_LOCALROUTE))
|
||||||
|
|
||||||
struct fib_nh;
|
struct fib_nh;
|
||||||
struct fib_info;
|
struct fib_info;
|
||||||
|
@ -353,6 +353,9 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
|||||||
saddr = fib_compute_spec_dst(skb);
|
saddr = fib_compute_spec_dst(skb);
|
||||||
ipc.opt = NULL;
|
ipc.opt = NULL;
|
||||||
ipc.tx_flags = 0;
|
ipc.tx_flags = 0;
|
||||||
|
ipc.ttl = 0;
|
||||||
|
ipc.tos = -1;
|
||||||
|
|
||||||
if (icmp_param->replyopts.opt.opt.optlen) {
|
if (icmp_param->replyopts.opt.opt.optlen) {
|
||||||
ipc.opt = &icmp_param->replyopts.opt;
|
ipc.opt = &icmp_param->replyopts.opt;
|
||||||
if (ipc.opt->opt.srr)
|
if (ipc.opt->opt.srr)
|
||||||
@ -608,6 +611,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
|
|||||||
ipc.addr = iph->saddr;
|
ipc.addr = iph->saddr;
|
||||||
ipc.opt = &icmp_param->replyopts.opt;
|
ipc.opt = &icmp_param->replyopts.opt;
|
||||||
ipc.tx_flags = 0;
|
ipc.tx_flags = 0;
|
||||||
|
ipc.ttl = 0;
|
||||||
|
ipc.tos = -1;
|
||||||
|
|
||||||
rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos,
|
rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos,
|
||||||
type, code, icmp_param);
|
type, code, icmp_param);
|
||||||
|
@ -1060,6 +1060,9 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
|
|||||||
rt->dst.dev->mtu : dst_mtu(&rt->dst);
|
rt->dst.dev->mtu : dst_mtu(&rt->dst);
|
||||||
cork->dst = &rt->dst;
|
cork->dst = &rt->dst;
|
||||||
cork->length = 0;
|
cork->length = 0;
|
||||||
|
cork->ttl = ipc->ttl;
|
||||||
|
cork->tos = ipc->tos;
|
||||||
|
cork->priority = ipc->priority;
|
||||||
cork->tx_flags = ipc->tx_flags;
|
cork->tx_flags = ipc->tx_flags;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1311,7 +1314,9 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
|
|||||||
if (cork->flags & IPCORK_OPT)
|
if (cork->flags & IPCORK_OPT)
|
||||||
opt = cork->opt;
|
opt = cork->opt;
|
||||||
|
|
||||||
if (rt->rt_type == RTN_MULTICAST)
|
if (cork->ttl != 0)
|
||||||
|
ttl = cork->ttl;
|
||||||
|
else if (rt->rt_type == RTN_MULTICAST)
|
||||||
ttl = inet->mc_ttl;
|
ttl = inet->mc_ttl;
|
||||||
else
|
else
|
||||||
ttl = ip_select_ttl(inet, &rt->dst);
|
ttl = ip_select_ttl(inet, &rt->dst);
|
||||||
@ -1319,7 +1324,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
|
|||||||
iph = ip_hdr(skb);
|
iph = ip_hdr(skb);
|
||||||
iph->version = 4;
|
iph->version = 4;
|
||||||
iph->ihl = 5;
|
iph->ihl = 5;
|
||||||
iph->tos = inet->tos;
|
iph->tos = (cork->tos != -1) ? cork->tos : inet->tos;
|
||||||
iph->frag_off = df;
|
iph->frag_off = df;
|
||||||
iph->ttl = ttl;
|
iph->ttl = ttl;
|
||||||
iph->protocol = sk->sk_protocol;
|
iph->protocol = sk->sk_protocol;
|
||||||
@ -1331,7 +1336,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
|
|||||||
ip_options_build(skb, opt, cork->addr, rt, 0);
|
ip_options_build(skb, opt, cork->addr, rt, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
skb->priority = sk->sk_priority;
|
skb->priority = (cork->tos != -1) ? cork->priority: sk->sk_priority;
|
||||||
skb->mark = sk->sk_mark;
|
skb->mark = sk->sk_mark;
|
||||||
/*
|
/*
|
||||||
* Steal rt from cork.dst to avoid a pair of atomic_inc/atomic_dec
|
* Steal rt from cork.dst to avoid a pair of atomic_inc/atomic_dec
|
||||||
@ -1481,6 +1486,8 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
|
|||||||
ipc.addr = daddr;
|
ipc.addr = daddr;
|
||||||
ipc.opt = NULL;
|
ipc.opt = NULL;
|
||||||
ipc.tx_flags = 0;
|
ipc.tx_flags = 0;
|
||||||
|
ipc.ttl = 0;
|
||||||
|
ipc.tos = -1;
|
||||||
|
|
||||||
if (replyopts.opt.opt.optlen) {
|
if (replyopts.opt.opt.optlen) {
|
||||||
ipc.opt = &replyopts.opt;
|
ipc.opt = &replyopts.opt;
|
||||||
|
@ -713,6 +713,8 @@ int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
|||||||
ipc.opt = NULL;
|
ipc.opt = NULL;
|
||||||
ipc.oif = sk->sk_bound_dev_if;
|
ipc.oif = sk->sk_bound_dev_if;
|
||||||
ipc.tx_flags = 0;
|
ipc.tx_flags = 0;
|
||||||
|
ipc.ttl = 0;
|
||||||
|
ipc.tos = -1;
|
||||||
|
|
||||||
sock_tx_timestamp(sk, &ipc.tx_flags);
|
sock_tx_timestamp(sk, &ipc.tx_flags);
|
||||||
|
|
||||||
@ -744,7 +746,7 @@ int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
faddr = ipc.opt->opt.faddr;
|
faddr = ipc.opt->opt.faddr;
|
||||||
}
|
}
|
||||||
tos = RT_TOS(inet->tos);
|
tos = get_rttos(&ipc, inet);
|
||||||
if (sock_flag(sk, SOCK_LOCALROUTE) ||
|
if (sock_flag(sk, SOCK_LOCALROUTE) ||
|
||||||
(msg->msg_flags & MSG_DONTROUTE) ||
|
(msg->msg_flags & MSG_DONTROUTE) ||
|
||||||
(ipc.opt && ipc.opt->opt.is_strictroute)) {
|
(ipc.opt && ipc.opt->opt.is_strictroute)) {
|
||||||
|
@ -517,6 +517,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
|||||||
ipc.addr = inet->inet_saddr;
|
ipc.addr = inet->inet_saddr;
|
||||||
ipc.opt = NULL;
|
ipc.opt = NULL;
|
||||||
ipc.tx_flags = 0;
|
ipc.tx_flags = 0;
|
||||||
|
ipc.ttl = 0;
|
||||||
|
ipc.tos = -1;
|
||||||
ipc.oif = sk->sk_bound_dev_if;
|
ipc.oif = sk->sk_bound_dev_if;
|
||||||
|
|
||||||
if (msg->msg_controllen) {
|
if (msg->msg_controllen) {
|
||||||
@ -556,7 +558,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
|||||||
daddr = ipc.opt->opt.faddr;
|
daddr = ipc.opt->opt.faddr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tos = RT_CONN_FLAGS(sk);
|
tos = get_rtconn_flags(&ipc, sk);
|
||||||
if (msg->msg_flags & MSG_DONTROUTE)
|
if (msg->msg_flags & MSG_DONTROUTE)
|
||||||
tos |= RTO_ONLINK;
|
tos |= RTO_ONLINK;
|
||||||
|
|
||||||
|
@ -855,6 +855,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
|||||||
|
|
||||||
ipc.opt = NULL;
|
ipc.opt = NULL;
|
||||||
ipc.tx_flags = 0;
|
ipc.tx_flags = 0;
|
||||||
|
ipc.ttl = 0;
|
||||||
|
ipc.tos = -1;
|
||||||
|
|
||||||
getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
|
getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
|
||||||
|
|
||||||
@ -938,7 +940,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
|||||||
faddr = ipc.opt->opt.faddr;
|
faddr = ipc.opt->opt.faddr;
|
||||||
connected = 0;
|
connected = 0;
|
||||||
}
|
}
|
||||||
tos = RT_TOS(inet->tos);
|
tos = get_rttos(&ipc, inet);
|
||||||
if (sock_flag(sk, SOCK_LOCALROUTE) ||
|
if (sock_flag(sk, SOCK_LOCALROUTE) ||
|
||||||
(msg->msg_flags & MSG_DONTROUTE) ||
|
(msg->msg_flags & MSG_DONTROUTE) ||
|
||||||
(ipc.opt && ipc.opt->opt.is_strictroute)) {
|
(ipc.opt && ipc.opt->opt.is_strictroute)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user