aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ipv6.h2
-rw-r--r--include/net/inet6_connection_sock.h13
-rw-r--r--net/ipv6/af_inet6.c52
-rw-r--r--net/ipv6/inet6_connection_sock.c103
-rw-r--r--net/ipv6/tcp_ipv6.c153
5 files changed, 173 insertions, 150 deletions
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 7d3e86d9576e..69a0decfbdf4 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -297,6 +297,8 @@ struct tcp6_sock {
297 struct ipv6_pinfo inet6; 297 struct ipv6_pinfo inet6;
298}; 298};
299 299
300extern int inet6_sk_rebuild_header(struct sock *sk);
301
300#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 302#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
301static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk) 303static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk)
302{ 304{
diff --git a/include/net/inet6_connection_sock.h b/include/net/inet6_connection_sock.h
index aa30ebde70dc..b33b438bffcc 100644
--- a/include/net/inet6_connection_sock.h
+++ b/include/net/inet6_connection_sock.h
@@ -15,8 +15,15 @@
15 15
16#include <linux/types.h> 16#include <linux/types.h>
17 17
18struct sock; 18struct in6_addr;
19struct inet_bind_bucket;
19struct request_sock; 20struct request_sock;
21struct sk_buff;
22struct sock;
23struct sockaddr;
24
25extern int inet6_csk_bind_conflict(const struct sock *sk,
26 const struct inet_bind_bucket *tb);
20 27
21extern struct request_sock *inet6_csk_search_req(const struct sock *sk, 28extern struct request_sock *inet6_csk_search_req(const struct sock *sk,
22 struct request_sock ***prevp, 29 struct request_sock ***prevp,
@@ -28,4 +35,8 @@ extern struct request_sock *inet6_csk_search_req(const struct sock *sk,
28extern void inet6_csk_reqsk_queue_hash_add(struct sock *sk, 35extern void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
29 struct request_sock *req, 36 struct request_sock *req,
30 const unsigned long timeout); 37 const unsigned long timeout);
38
39extern void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr);
40
41extern int inet6_csk_xmit(struct sk_buff *skb, int ipfragok);
31#endif /* _INET6_CONNECTION_SOCK_H */ 42#endif /* _INET6_CONNECTION_SOCK_H */
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index d9546380fa04..fd040e9a1f47 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -609,6 +609,58 @@ inet6_unregister_protosw(struct inet_protosw *p)
609 } 609 }
610} 610}
611 611
612int inet6_sk_rebuild_header(struct sock *sk)
613{
614 int err;
615 struct dst_entry *dst;
616 struct ipv6_pinfo *np = inet6_sk(sk);
617
618 dst = __sk_dst_check(sk, np->dst_cookie);
619
620 if (dst == NULL) {
621 struct inet_sock *inet = inet_sk(sk);
622 struct in6_addr *final_p = NULL, final;
623 struct flowi fl;
624
625 memset(&fl, 0, sizeof(fl));
626 fl.proto = sk->sk_protocol;
627 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
628 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
629 fl.fl6_flowlabel = np->flow_label;
630 fl.oif = sk->sk_bound_dev_if;
631 fl.fl_ip_dport = inet->dport;
632 fl.fl_ip_sport = inet->sport;
633
634 if (np->opt && np->opt->srcrt) {
635 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
636 ipv6_addr_copy(&final, &fl.fl6_dst);
637 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
638 final_p = &final;
639 }
640
641 err = ip6_dst_lookup(sk, &dst, &fl);
642 if (err) {
643 sk->sk_route_caps = 0;
644 return err;
645 }
646 if (final_p)
647 ipv6_addr_copy(&fl.fl6_dst, final_p);
648
649 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
650 sk->sk_err_soft = -err;
651 return err;
652 }
653
654 ip6_dst_store(sk, dst, NULL);
655 sk->sk_route_caps = dst->dev->features &
656 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
657 }
658
659 return 0;
660}
661
662EXPORT_SYMBOL_GPL(inet6_sk_rebuild_header);
663
612int 664int
613snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign) 665snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign)
614{ 666{
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index fe874eeaa40c..792f90f0f9ec 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -21,8 +21,34 @@
21 21
22#include <net/addrconf.h> 22#include <net/addrconf.h>
23#include <net/inet_connection_sock.h> 23#include <net/inet_connection_sock.h>
24#include <net/inet_ecn.h>
25#include <net/inet_hashtables.h>
26#include <net/ip6_route.h>
24#include <net/sock.h> 27#include <net/sock.h>
25 28
29int inet6_csk_bind_conflict(const struct sock *sk,
30 const struct inet_bind_bucket *tb)
31{
32 const struct sock *sk2;
33 const struct hlist_node *node;
34
35 /* We must walk the whole port owner list in this case. -DaveM */
36 sk_for_each_bound(sk2, node, &tb->owners) {
37 if (sk != sk2 &&
38 (!sk->sk_bound_dev_if ||
39 !sk2->sk_bound_dev_if ||
40 sk->sk_bound_dev_if == sk2->sk_bound_dev_if) &&
41 (!sk->sk_reuse || !sk2->sk_reuse ||
42 sk2->sk_state == TCP_LISTEN) &&
43 ipv6_rcv_saddr_equal(sk, sk2))
44 break;
45 }
46
47 return node != NULL;
48}
49
50EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict);
51
26/* 52/*
27 * request_sock (formerly open request) hash tables. 53 * request_sock (formerly open request) hash tables.
28 */ 54 */
@@ -94,3 +120,80 @@ void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
94} 120}
95 121
96EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add); 122EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add);
123
124void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
125{
126 struct ipv6_pinfo *np = inet6_sk(sk);
127 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
128
129 sin6->sin6_family = AF_INET6;
130 ipv6_addr_copy(&sin6->sin6_addr, &np->daddr);
131 sin6->sin6_port = inet_sk(sk)->dport;
132 /* We do not store received flowlabel for TCP */
133 sin6->sin6_flowinfo = 0;
134 sin6->sin6_scope_id = 0;
135 if (sk->sk_bound_dev_if &&
136 ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
137 sin6->sin6_scope_id = sk->sk_bound_dev_if;
138}
139
140EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
141
142int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
143{
144 struct sock *sk = skb->sk;
145 struct inet_sock *inet = inet_sk(sk);
146 struct ipv6_pinfo *np = inet6_sk(sk);
147 struct flowi fl;
148 struct dst_entry *dst;
149 struct in6_addr *final_p = NULL, final;
150
151 memset(&fl, 0, sizeof(fl));
152 fl.proto = sk->sk_protocol;
153 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
154 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
155 fl.fl6_flowlabel = np->flow_label;
156 IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);
157 fl.oif = sk->sk_bound_dev_if;
158 fl.fl_ip_sport = inet->sport;
159 fl.fl_ip_dport = inet->dport;
160
161 if (np->opt && np->opt->srcrt) {
162 struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
163 ipv6_addr_copy(&final, &fl.fl6_dst);
164 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
165 final_p = &final;
166 }
167
168 dst = __sk_dst_check(sk, np->dst_cookie);
169
170 if (dst == NULL) {
171 int err = ip6_dst_lookup(sk, &dst, &fl);
172
173 if (err) {
174 sk->sk_err_soft = -err;
175 return err;
176 }
177
178 if (final_p)
179 ipv6_addr_copy(&fl.fl6_dst, final_p);
180
181 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
182 sk->sk_route_caps = 0;
183 return err;
184 }
185
186 ip6_dst_store(sk, dst, NULL);
187 sk->sk_route_caps = dst->dev->features &
188 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
189 }
190
191 skb->dst = dst_clone(dst);
192
193 /* Restore final destination back after routing done */
194 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
195
196 return ip6_xmit(sk, skb, &fl, np->opt, 0);
197}
198
199EXPORT_SYMBOL_GPL(inet6_csk_xmit);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 8ce8a1359d2b..2f932ce72610 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -72,32 +72,10 @@ static void tcp_v6_send_check(struct sock *sk, int len,
72 struct sk_buff *skb); 72 struct sk_buff *skb);
73 73
74static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); 74static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
75static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok);
76 75
77static struct inet_connection_sock_af_ops ipv6_mapped; 76static struct inet_connection_sock_af_ops ipv6_mapped;
78static struct inet_connection_sock_af_ops ipv6_specific; 77static struct inet_connection_sock_af_ops ipv6_specific;
79 78
80int inet6_csk_bind_conflict(const struct sock *sk,
81 const struct inet_bind_bucket *tb)
82{
83 const struct sock *sk2;
84 const struct hlist_node *node;
85
86 /* We must walk the whole port owner list in this case. -DaveM */
87 sk_for_each_bound(sk2, node, &tb->owners) {
88 if (sk != sk2 &&
89 (!sk->sk_bound_dev_if ||
90 !sk2->sk_bound_dev_if ||
91 sk->sk_bound_dev_if == sk2->sk_bound_dev_if) &&
92 (!sk->sk_reuse || !sk2->sk_reuse ||
93 sk2->sk_state == TCP_LISTEN) &&
94 ipv6_rcv_saddr_equal(sk, sk2))
95 break;
96 }
97
98 return node != NULL;
99}
100
101static int tcp_v6_get_port(struct sock *sk, unsigned short snum) 79static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
102{ 80{
103 return inet_csk_get_port(&tcp_hashinfo, sk, snum, 81 return inet_csk_get_port(&tcp_hashinfo, sk, snum,
@@ -1500,129 +1478,6 @@ do_time_wait:
1500 goto discard_it; 1478 goto discard_it;
1501} 1479}
1502 1480
1503static int tcp_v6_rebuild_header(struct sock *sk)
1504{
1505 int err;
1506 struct dst_entry *dst;
1507 struct ipv6_pinfo *np = inet6_sk(sk);
1508
1509 dst = __sk_dst_check(sk, np->dst_cookie);
1510
1511 if (dst == NULL) {
1512 struct inet_sock *inet = inet_sk(sk);
1513 struct in6_addr *final_p = NULL, final;
1514 struct flowi fl;
1515
1516 memset(&fl, 0, sizeof(fl));
1517 fl.proto = IPPROTO_TCP;
1518 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
1519 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
1520 fl.fl6_flowlabel = np->flow_label;
1521 fl.oif = sk->sk_bound_dev_if;
1522 fl.fl_ip_dport = inet->dport;
1523 fl.fl_ip_sport = inet->sport;
1524
1525 if (np->opt && np->opt->srcrt) {
1526 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
1527 ipv6_addr_copy(&final, &fl.fl6_dst);
1528 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1529 final_p = &final;
1530 }
1531
1532 err = ip6_dst_lookup(sk, &dst, &fl);
1533 if (err) {
1534 sk->sk_route_caps = 0;
1535 return err;
1536 }
1537 if (final_p)
1538 ipv6_addr_copy(&fl.fl6_dst, final_p);
1539
1540 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
1541 sk->sk_err_soft = -err;
1542 return err;
1543 }
1544
1545 ip6_dst_store(sk, dst, NULL);
1546 sk->sk_route_caps = dst->dev->features &
1547 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
1548 }
1549
1550 return 0;
1551}
1552
1553static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
1554{
1555 struct sock *sk = skb->sk;
1556 struct inet_sock *inet = inet_sk(sk);
1557 struct ipv6_pinfo *np = inet6_sk(sk);
1558 struct flowi fl;
1559 struct dst_entry *dst;
1560 struct in6_addr *final_p = NULL, final;
1561
1562 memset(&fl, 0, sizeof(fl));
1563 fl.proto = IPPROTO_TCP;
1564 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
1565 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
1566 fl.fl6_flowlabel = np->flow_label;
1567 IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);
1568 fl.oif = sk->sk_bound_dev_if;
1569 fl.fl_ip_sport = inet->sport;
1570 fl.fl_ip_dport = inet->dport;
1571
1572 if (np->opt && np->opt->srcrt) {
1573 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
1574 ipv6_addr_copy(&final, &fl.fl6_dst);
1575 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1576 final_p = &final;
1577 }
1578
1579 dst = __sk_dst_check(sk, np->dst_cookie);
1580
1581 if (dst == NULL) {
1582 int err = ip6_dst_lookup(sk, &dst, &fl);
1583
1584 if (err) {
1585 sk->sk_err_soft = -err;
1586 return err;
1587 }
1588
1589 if (final_p)
1590 ipv6_addr_copy(&fl.fl6_dst, final_p);
1591
1592 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
1593 sk->sk_route_caps = 0;
1594 return err;
1595 }
1596
1597 ip6_dst_store(sk, dst, NULL);
1598 sk->sk_route_caps = dst->dev->features &
1599 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
1600 }
1601
1602 skb->dst = dst_clone(dst);
1603
1604 /* Restore final destination back after routing done */
1605 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
1606
1607 return ip6_xmit(sk, skb, &fl, np->opt, 0);
1608}
1609
1610static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
1611{
1612 struct ipv6_pinfo *np = inet6_sk(sk);
1613 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
1614
1615 sin6->sin6_family = AF_INET6;
1616 ipv6_addr_copy(&sin6->sin6_addr, &np->daddr);
1617 sin6->sin6_port = inet_sk(sk)->dport;
1618 /* We do not store received flowlabel for TCP */
1619 sin6->sin6_flowinfo = 0;
1620 sin6->sin6_scope_id = 0;
1621 if (sk->sk_bound_dev_if &&
1622 ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
1623 sin6->sin6_scope_id = sk->sk_bound_dev_if;
1624}
1625
1626static int tcp_v6_remember_stamp(struct sock *sk) 1481static int tcp_v6_remember_stamp(struct sock *sk)
1627{ 1482{
1628 /* Alas, not yet... */ 1483 /* Alas, not yet... */
@@ -1630,9 +1485,9 @@ static int tcp_v6_remember_stamp(struct sock *sk)
1630} 1485}
1631 1486
1632static struct inet_connection_sock_af_ops ipv6_specific = { 1487static struct inet_connection_sock_af_ops ipv6_specific = {
1633 .queue_xmit = tcp_v6_xmit, 1488 .queue_xmit = inet6_csk_xmit,
1634 .send_check = tcp_v6_send_check, 1489 .send_check = tcp_v6_send_check,
1635 .rebuild_header = tcp_v6_rebuild_header, 1490 .rebuild_header = inet6_sk_rebuild_header,
1636 .conn_request = tcp_v6_conn_request, 1491 .conn_request = tcp_v6_conn_request,
1637 .syn_recv_sock = tcp_v6_syn_recv_sock, 1492 .syn_recv_sock = tcp_v6_syn_recv_sock,
1638 .remember_stamp = tcp_v6_remember_stamp, 1493 .remember_stamp = tcp_v6_remember_stamp,
@@ -1640,7 +1495,7 @@ static struct inet_connection_sock_af_ops ipv6_specific = {
1640 1495
1641 .setsockopt = ipv6_setsockopt, 1496 .setsockopt = ipv6_setsockopt,
1642 .getsockopt = ipv6_getsockopt, 1497 .getsockopt = ipv6_getsockopt,
1643 .addr2sockaddr = v6_addr2sockaddr, 1498 .addr2sockaddr = inet6_csk_addr2sockaddr,
1644 .sockaddr_len = sizeof(struct sockaddr_in6) 1499 .sockaddr_len = sizeof(struct sockaddr_in6)
1645}; 1500};
1646 1501
@@ -1659,7 +1514,7 @@ static struct inet_connection_sock_af_ops ipv6_mapped = {
1659 1514
1660 .setsockopt = ipv6_setsockopt, 1515 .setsockopt = ipv6_setsockopt,
1661 .getsockopt = ipv6_getsockopt, 1516 .getsockopt = ipv6_getsockopt,
1662 .addr2sockaddr = v6_addr2sockaddr, 1517 .addr2sockaddr = inet6_csk_addr2sockaddr,
1663 .sockaddr_len = sizeof(struct sockaddr_in6) 1518 .sockaddr_len = sizeof(struct sockaddr_in6)
1664}; 1519};
1665 1520