* [PATCH 0/3] IPv6: Add IPV6_RECVPATHMTU, IPV6_PATHMTU and IPV6_DONTFRAG support
@ 2010-04-23 21:26 Brian Haley
2010-04-23 21:26 ` [PATCH 1/3] IPv6: data structure changes for new socket options Brian Haley
2010-04-24 6:36 ` [PATCH 0/3] IPv6: Add IPV6_RECVPATHMTU, IPV6_PATHMTU and " David Miller
0 siblings, 2 replies; 5+ messages in thread
From: Brian Haley @ 2010-04-23 21:26 UTC (permalink / raw)
To: davem, yoshfuji; +Cc: netdev
This series adds support for IPV6_RECVPATHMTU, IPV6_PATHMTU, and
IPV6_DONTFRAG socket options as defined in RFC 3542.
include/linux/in6.h | 2 +-
include/linux/ipv6.h | 15 +++++-
include/net/ipv6.h | 5 ++-
include/net/transp_v6.h | 3 +-
net/ipv6/af_inet6.c | 3 +
net/ipv6/datagram.c | 108 +++++++++++++++++++++++++++++++++++++++++++++-
net/ipv6/icmp.c | 5 +-
net/ipv6/ip6_flowlabel.c | 3 +-
net/ipv6/ip6_output.c | 26 +++++++----
net/ipv6/ipv6_sockglue.c | 49 ++++++++++++++++++++-
net/ipv6/raw.c | 12 ++++-
net/ipv6/udp.c | 12 ++++-
12 files changed, 219 insertions(+), 24 deletions(-)
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] IPv6: data structure changes for new socket options
2010-04-23 21:26 [PATCH 0/3] IPv6: Add IPV6_RECVPATHMTU, IPV6_PATHMTU and IPV6_DONTFRAG support Brian Haley
@ 2010-04-23 21:26 ` Brian Haley
2010-04-23 21:26 ` [PATCH 2/3] IPv6: Add dontfrag argument to relevant functions Brian Haley
2010-04-24 6:36 ` [PATCH 0/3] IPv6: Add IPV6_RECVPATHMTU, IPV6_PATHMTU and " David Miller
1 sibling, 1 reply; 5+ messages in thread
From: Brian Haley @ 2010-04-23 21:26 UTC (permalink / raw)
To: davem, yoshfuji; +Cc: netdev
Add underlying data structure changes and basic setsockopt()
and getsockopt() support for IPV6_RECVPATHMTU, IPV6_PATHMTU,
and IPV6_DONTFRAG. IPV6_PATHMTU is actually fully functional
at this point.
Signed-off-by: Brian Haley <brian.haley@hp.com>
---
include/linux/in6.h | 2 +-
include/linux/ipv6.h | 13 ++++++++++---
net/ipv6/ipv6_sockglue.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/include/linux/in6.h b/include/linux/in6.h
index 9b90cb2..c4bf46f 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -221,10 +221,10 @@ struct in6_flowlabel_req {
#define IPV6_RTHDR 57
#define IPV6_RECVDSTOPTS 58
#define IPV6_DSTOPTS 59
-#if 0 /* not yet */
#define IPV6_RECVPATHMTU 60
#define IPV6_PATHMTU 61
#define IPV6_DONTFRAG 62
+#if 0 /* not yet */
#define IPV6_USE_MIN_MTU 63
#endif
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 1bdbebf..1976942 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -21,6 +21,10 @@ struct in6_pktinfo {
int ipi6_ifindex;
};
+struct ip6_mtuinfo {
+ struct sockaddr_in6 ip6m_addr;
+ __u32 ip6m_mtu;
+};
struct in6_ifreq {
struct in6_addr ifr6_addr;
@@ -334,22 +338,25 @@ struct ipv6_pinfo {
dstopts:1,
odstopts:1,
rxflow:1,
- rxtclass:1;
+ rxtclass:1,
+ rxpmtu:1;
} bits;
__u16 all;
} rxopt;
/* sockopt flags */
- __u8 recverr:1,
+ __u16 recverr:1,
sndflow:1,
pmtudisc:2,
ipv6only:1,
- srcprefs:3; /* 001: prefer temporary address
+ srcprefs:3, /* 001: prefer temporary address
* 010: prefer public address
* 100: prefer care-of address
*/
+ dontfrag:1;
__u8 min_hopcount;
__u8 tclass;
+ __u8 padding;
__u32 dst_cookie;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 92295ad..2bf9eda 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -337,6 +337,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
retv = 0;
break;
+ case IPV6_RECVPATHMTU:
+ if (optlen < sizeof(int))
+ goto e_inval;
+ np->rxopt.bits.rxpmtu = valbool;
+ retv = 0;
+ break;
+
case IPV6_HOPOPTS:
case IPV6_RTHDRDSTOPTS:
case IPV6_RTHDR:
@@ -773,6 +780,9 @@ pref_skip_coa:
if (val < 0 || val > 255)
goto e_inval;
np->min_hopcount = val;
+ break;
+ case IPV6_DONTFRAG:
+ np->dontfrag = valbool;
retv = 0;
break;
}
@@ -1063,6 +1073,38 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
val = np->rxopt.bits.rxflow;
break;
+ case IPV6_RECVPATHMTU:
+ val = np->rxopt.bits.rxpmtu;
+ break;
+
+ case IPV6_PATHMTU:
+ {
+ struct dst_entry *dst;
+ struct ip6_mtuinfo mtuinfo;
+
+ if (len < sizeof(mtuinfo))
+ return -EINVAL;
+
+ len = sizeof(mtuinfo);
+ memset(&mtuinfo, 0, sizeof(mtuinfo));
+
+ rcu_read_lock();
+ dst = __sk_dst_get(sk);
+ if (dst)
+ mtuinfo.ip6m_mtu = dst_mtu(dst);
+ rcu_read_unlock();
+ if (!mtuinfo.ip6m_mtu)
+ return -ENOTCONN;
+
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &mtuinfo, len))
+ return -EFAULT;
+
+ return 0;
+ break;
+ }
+
case IPV6_UNICAST_HOPS:
case IPV6_MULTICAST_HOPS:
{
@@ -1128,6 +1170,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
val = np->min_hopcount;
break;
+ case IPV6_DONTFRAG:
+ val = np->dontfrag;
+ break;
+
default:
return -ENOPROTOOPT;
}
--
1.5.4.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] IPv6: Add dontfrag argument to relevant functions
2010-04-23 21:26 ` [PATCH 1/3] IPv6: data structure changes for new socket options Brian Haley
@ 2010-04-23 21:26 ` Brian Haley
2010-04-23 21:26 ` [PATCH 3/3] IPv6: Complete IPV6_DONTFRAG support Brian Haley
0 siblings, 1 reply; 5+ messages in thread
From: Brian Haley @ 2010-04-23 21:26 UTC (permalink / raw)
To: davem, yoshfuji; +Cc: netdev
Add dontfrag argument to relevant functions for
IPV6_DONTFRAG support, as well as allowing the value
to be passed-in via ancillary cmsg data.
Signed-off-by: Brian Haley <brian.haley@hp.com>
---
include/net/ipv6.h | 3 ++-
include/net/transp_v6.h | 3 ++-
net/ipv6/datagram.c | 21 ++++++++++++++++++++-
net/ipv6/icmp.c | 5 +++--
net/ipv6/ip6_flowlabel.c | 3 ++-
net/ipv6/ip6_output.c | 2 +-
net/ipv6/ipv6_sockglue.c | 3 ++-
net/ipv6/raw.c | 9 +++++++--
net/ipv6/udp.c | 9 +++++++--
9 files changed, 46 insertions(+), 12 deletions(-)
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index b1d8db9..7ab6323 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -503,7 +503,8 @@ extern int ip6_append_data(struct sock *sk,
struct ipv6_txoptions *opt,
struct flowi *fl,
struct rt6_info *rt,
- unsigned int flags);
+ unsigned int flags,
+ int dontfrag);
extern int ip6_push_pending_frames(struct sock *sk);
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index d65381c..42a0eb6 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -44,7 +44,8 @@ extern int datagram_send_ctl(struct net *net,
struct msghdr *msg,
struct flowi *fl,
struct ipv6_txoptions *opt,
- int *hlimit, int *tclass);
+ int *hlimit, int *tclass,
+ int *dontfrag);
#define LOOPBACK4_IPV6 cpu_to_be32(0x7f000006)
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 622dc79..f5076d3 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -497,7 +497,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
int datagram_send_ctl(struct net *net,
struct msghdr *msg, struct flowi *fl,
struct ipv6_txoptions *opt,
- int *hlimit, int *tclass)
+ int *hlimit, int *tclass, int *dontfrag)
{
struct in6_pktinfo *src_info;
struct cmsghdr *cmsg;
@@ -737,6 +737,25 @@ int datagram_send_ctl(struct net *net,
break;
}
+
+ case IPV6_DONTFRAG:
+ {
+ int df;
+
+ err = -EINVAL;
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
+ goto exit_f;
+ }
+
+ df = *(int *)CMSG_DATA(cmsg);
+ if (df < 0 || df > 1)
+ goto exit_f;
+
+ err = 0;
+ *dontfrag = df;
+
+ break;
+ }
default:
LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n",
cmsg->cmsg_type);
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 12d2fa4..ce79929 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -481,7 +481,7 @@ route_done:
len + sizeof(struct icmp6hdr),
sizeof(struct icmp6hdr), hlimit,
np->tclass, NULL, &fl, (struct rt6_info*)dst,
- MSG_DONTWAIT);
+ MSG_DONTWAIT, np->dontfrag);
if (err) {
ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
ip6_flush_pending_frames(sk);
@@ -561,7 +561,8 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl,
- (struct rt6_info*)dst, MSG_DONTWAIT);
+ (struct rt6_info*)dst, MSG_DONTWAIT,
+ np->dontfrag);
if (err) {
ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 14e2321..1365468 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -360,7 +360,8 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval,
msg.msg_control = (void*)(fl->opt+1);
flowi.oif = 0;
- err = datagram_send_ctl(net, &msg, &flowi, fl->opt, &junk, &junk);
+ err = datagram_send_ctl(net, &msg, &flowi, fl->opt, &junk,
+ &junk, &junk);
if (err)
goto done;
err = -EINVAL;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 263d4cf..54d43dd 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1105,7 +1105,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
int offset, int len, int odd, struct sk_buff *skb),
void *from, int length, int transhdrlen,
int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl,
- struct rt6_info *rt, unsigned int flags)
+ struct rt6_info *rt, unsigned int flags, int dontfrag)
{
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 2bf9eda..bd43f01 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -458,7 +458,8 @@ sticky_done:
msg.msg_controllen = optlen;
msg.msg_control = (void*)(opt+1);
- retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk);
+ retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk,
+ &junk);
if (retv)
goto done;
update:
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 8763b1a..44a84ea 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -733,6 +733,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
int addr_len = msg->msg_namelen;
int hlimit = -1;
int tclass = -1;
+ int dontfrag = -1;
u16 proto;
int err;
@@ -811,7 +812,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
memset(opt, 0, sizeof(struct ipv6_txoptions));
opt->tot_len = sizeof(struct ipv6_txoptions);
- err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, &tclass);
+ err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit,
+ &tclass, &dontfrag);
if (err < 0) {
fl6_sock_release(flowlabel);
return err;
@@ -880,6 +882,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (tclass < 0)
tclass = np->tclass;
+ if (dontfrag < 0)
+ dontfrag = np->dontfrag;
+
if (msg->msg_flags&MSG_CONFIRM)
goto do_confirm;
@@ -890,7 +895,7 @@ back_from_confirm:
lock_sock(sk);
err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst,
- msg->msg_flags);
+ msg->msg_flags, dontfrag);
if (err)
ip6_flush_pending_frames(sk);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 92bf903..39e3665 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -919,6 +919,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
int ulen = len;
int hlimit = -1;
int tclass = -1;
+ int dontfrag = -1;
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
int err;
int connected = 0;
@@ -1049,7 +1050,8 @@ do_udp_sendmsg:
memset(opt, 0, sizeof(struct ipv6_txoptions));
opt->tot_len = sizeof(*opt);
- err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, &tclass);
+ err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit,
+ &tclass, &dontfrag);
if (err < 0) {
fl6_sock_release(flowlabel);
return err;
@@ -1120,6 +1122,9 @@ do_udp_sendmsg:
if (tclass < 0)
tclass = np->tclass;
+ if (dontfrag < 0)
+ dontfrag = np->dontfrag;
+
if (msg->msg_flags&MSG_CONFIRM)
goto do_confirm;
back_from_confirm:
@@ -1143,7 +1148,7 @@ do_append_data:
err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen,
sizeof(struct udphdr), hlimit, tclass, opt, &fl,
(struct rt6_info*)dst,
- corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
+ corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag);
if (err)
udp_v6_flush_pending_frames(sk);
else if (!corkreq)
--
1.5.4.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] IPv6: Complete IPV6_DONTFRAG support
2010-04-23 21:26 ` [PATCH 2/3] IPv6: Add dontfrag argument to relevant functions Brian Haley
@ 2010-04-23 21:26 ` Brian Haley
0 siblings, 0 replies; 5+ messages in thread
From: Brian Haley @ 2010-04-23 21:26 UTC (permalink / raw)
To: davem, yoshfuji; +Cc: netdev
Finally add support to detect a local IPV6_DONTFRAG event
and return the relevant data to the user if they've enabled
IPV6_RECVPATHMTU on the socket. The next recvmsg() will
return no data, but have an IPV6_PATHMTU as ancillary data.
Signed-off-by: Brian Haley <brian.haley@hp.com>
---
include/linux/ipv6.h | 2 +
include/net/ipv6.h | 2 +
net/ipv6/af_inet6.c | 3 ++
net/ipv6/datagram.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
net/ipv6/ip6_output.c | 24 +++++++++----
net/ipv6/raw.c | 3 ++
net/ipv6/udp.c | 3 ++
7 files changed, 116 insertions(+), 8 deletions(-)
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 1976942..2ab5509 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -257,6 +257,7 @@ struct inet6_skb_parm {
};
#define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb))
+#define IP6CBMTU(skb) ((struct ip6_mtuinfo *)((skb)->cb))
static inline int inet6_iif(const struct sk_buff *skb)
{
@@ -366,6 +367,7 @@ struct ipv6_pinfo {
struct ipv6_txoptions *opt;
struct sk_buff *pktoptions;
+ struct sk_buff *rxpmtu;
struct {
struct ipv6_txoptions *opt;
u8 hop_limit;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 7ab6323..eba5cc0 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -578,9 +578,11 @@ extern int ip6_datagram_connect(struct sock *sk,
struct sockaddr *addr, int addr_len);
extern int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len);
+extern int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len);
extern void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, __be16 port,
u32 info, u8 *payload);
extern void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info);
+extern void ipv6_local_rxpmtu(struct sock *sk, struct flowi *fl, u32 mtu);
extern int inet6_release(struct socket *sock);
extern int inet6_bind(struct socket *sock, struct sockaddr *uaddr,
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 3192aa0..d2df314 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -417,6 +417,9 @@ void inet6_destroy_sock(struct sock *sk)
if ((skb = xchg(&np->pktoptions, NULL)) != NULL)
kfree_skb(skb);
+ if ((skb = xchg(&np->rxpmtu, NULL)) != NULL)
+ kfree_skb(skb);
+
/* Free flowlabels */
fl6_free_socklist(sk);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index f5076d3..5959230 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -278,6 +278,45 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info)
kfree_skb(skb);
}
+void ipv6_local_rxpmtu(struct sock *sk, struct flowi *fl, u32 mtu)
+{
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct ipv6hdr *iph;
+ struct sk_buff *skb;
+ struct ip6_mtuinfo *mtu_info;
+
+ if (!np->rxopt.bits.rxpmtu)
+ return;
+
+ skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ skb_put(skb, sizeof(struct ipv6hdr));
+ skb_reset_network_header(skb);
+ iph = ipv6_hdr(skb);
+ ipv6_addr_copy(&iph->daddr, &fl->fl6_dst);
+
+ mtu_info = IP6CBMTU(skb);
+ if (!mtu_info) {
+ kfree_skb(skb);
+ return;
+ }
+
+ mtu_info->ip6m_mtu = mtu;
+ mtu_info->ip6m_addr.sin6_family = AF_INET6;
+ mtu_info->ip6m_addr.sin6_port = 0;
+ mtu_info->ip6m_addr.sin6_flowinfo = 0;
+ mtu_info->ip6m_addr.sin6_scope_id = fl->oif;
+ ipv6_addr_copy(&mtu_info->ip6m_addr.sin6_addr, &ipv6_hdr(skb)->daddr);
+
+ __skb_pull(skb, skb_tail_pointer(skb) - skb->data);
+ skb_reset_transport_header(skb);
+
+ skb = xchg(&np->rxpmtu, skb);
+ kfree_skb(skb);
+}
+
/*
* Handle MSG_ERRQUEUE
*/
@@ -381,6 +420,54 @@ out:
return err;
}
+/*
+ * Handle IPV6_RECVPATHMTU
+ */
+int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len)
+{
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct sk_buff *skb;
+ struct sockaddr_in6 *sin;
+ struct ip6_mtuinfo mtu_info;
+ int err;
+ int copied;
+
+ err = -EAGAIN;
+ skb = xchg(&np->rxpmtu, NULL);
+ if (skb == NULL)
+ goto out;
+
+ copied = skb->len;
+ if (copied > len) {
+ msg->msg_flags |= MSG_TRUNC;
+ copied = len;
+ }
+ err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ if (err)
+ goto out_free_skb;
+
+ sock_recv_timestamp(msg, sk, skb);
+
+ memcpy(&mtu_info, IP6CBMTU(skb), sizeof(mtu_info));
+
+ sin = (struct sockaddr_in6 *)msg->msg_name;
+ if (sin) {
+ sin->sin6_family = AF_INET6;
+ sin->sin6_flowinfo = 0;
+ sin->sin6_port = 0;
+ sin->sin6_scope_id = mtu_info.ip6m_addr.sin6_scope_id;
+ ipv6_addr_copy(&sin->sin6_addr, &mtu_info.ip6m_addr.sin6_addr);
+ }
+
+ put_cmsg(msg, SOL_IPV6, IPV6_PATHMTU, sizeof(mtu_info), &mtu_info);
+
+ err = copied;
+
+out_free_skb:
+ kfree_skb(skb);
+out:
+ return err;
+}
int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 54d43dd..61e2bef 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1219,15 +1219,23 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
*/
inet->cork.length += length;
- if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) &&
- (rt->u.dst.dev->features & NETIF_F_UFO)) {
+ if (length > mtu) {
+ int proto = sk->sk_protocol;
+ if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){
+ ipv6_local_rxpmtu(sk, fl, mtu-exthdrlen);
+ return -EMSGSIZE;
+ }
- err = ip6_ufo_append_data(sk, getfrag, from, length, hh_len,
- fragheaderlen, transhdrlen, mtu,
- flags);
- if (err)
- goto error;
- return 0;
+ if (proto == IPPROTO_UDP &&
+ (rt->u.dst.dev->features & NETIF_F_UFO)) {
+
+ err = ip6_ufo_append_data(sk, getfrag, from, length,
+ hh_len, fragheaderlen,
+ transhdrlen, mtu, flags);
+ if (err)
+ goto error;
+ return 0;
+ }
}
if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL)
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 44a84ea..8562738 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -461,6 +461,9 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
if (flags & MSG_ERRQUEUE)
return ipv6_recv_error(sk, msg, len);
+ if (np->rxpmtu && np->rxopt.bits.rxpmtu)
+ return ipv6_recv_rxpmtu(sk, msg, len);
+
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb)
goto out;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 39e3665..2850e35 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -335,6 +335,9 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
if (flags & MSG_ERRQUEUE)
return ipv6_recv_error(sk, msg, len);
+ if (np->rxpmtu && np->rxopt.bits.rxpmtu)
+ return ipv6_recv_rxpmtu(sk, msg, len);
+
try_again:
skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
&peeked, &err);
--
1.5.4.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 0/3] IPv6: Add IPV6_RECVPATHMTU, IPV6_PATHMTU and IPV6_DONTFRAG support
2010-04-23 21:26 [PATCH 0/3] IPv6: Add IPV6_RECVPATHMTU, IPV6_PATHMTU and IPV6_DONTFRAG support Brian Haley
2010-04-23 21:26 ` [PATCH 1/3] IPv6: data structure changes for new socket options Brian Haley
@ 2010-04-24 6:36 ` David Miller
1 sibling, 0 replies; 5+ messages in thread
From: David Miller @ 2010-04-24 6:36 UTC (permalink / raw)
To: brian.haley; +Cc: yoshfuji, netdev
From: Brian Haley <brian.haley@hp.com>
Date: Fri, 23 Apr 2010 17:26:06 -0400
> This series adds support for IPV6_RECVPATHMTU, IPV6_PATHMTU, and
> IPV6_DONTFRAG socket options as defined in RFC 3542.
Nice work, applied to net-next-2.6, thanks Brian!
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2010-04-24 6:36 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-23 21:26 [PATCH 0/3] IPv6: Add IPV6_RECVPATHMTU, IPV6_PATHMTU and IPV6_DONTFRAG support Brian Haley
2010-04-23 21:26 ` [PATCH 1/3] IPv6: data structure changes for new socket options Brian Haley
2010-04-23 21:26 ` [PATCH 2/3] IPv6: Add dontfrag argument to relevant functions Brian Haley
2010-04-23 21:26 ` [PATCH 3/3] IPv6: Complete IPV6_DONTFRAG support Brian Haley
2010-04-24 6:36 ` [PATCH 0/3] IPv6: Add IPV6_RECVPATHMTU, IPV6_PATHMTU and " David Miller
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.