diff options
-rw-r--r-- | include/linux/ipv6.h | 2 | ||||
-rw-r--r-- | include/net/inet6_connection_sock.h | 13 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 52 | ||||
-rw-r--r-- | net/ipv6/inet6_connection_sock.c | 103 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 153 |
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 | ||
300 | extern 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) |
301 | static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk) | 303 | static 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 | ||
18 | struct sock; | 18 | struct in6_addr; |
19 | struct inet_bind_bucket; | ||
19 | struct request_sock; | 20 | struct request_sock; |
21 | struct sk_buff; | ||
22 | struct sock; | ||
23 | struct sockaddr; | ||
24 | |||
25 | extern int inet6_csk_bind_conflict(const struct sock *sk, | ||
26 | const struct inet_bind_bucket *tb); | ||
20 | 27 | ||
21 | extern struct request_sock *inet6_csk_search_req(const struct sock *sk, | 28 | extern 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, | |||
28 | extern void inet6_csk_reqsk_queue_hash_add(struct sock *sk, | 35 | extern 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 | |||
39 | extern void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr); | ||
40 | |||
41 | extern 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 | ||
612 | int 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 | |||
662 | EXPORT_SYMBOL_GPL(inet6_sk_rebuild_header); | ||
663 | |||
612 | int | 664 | int |
613 | snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign) | 665 | snmp6_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 | ||
29 | int 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 | |||
50 | EXPORT_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 | ||
96 | EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add); | 122 | EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add); |
123 | |||
124 | void 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 | |||
140 | EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr); | ||
141 | |||
142 | int 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 | |||
199 | EXPORT_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 | ||
74 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); | 74 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); |
75 | static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok); | ||
76 | 75 | ||
77 | static struct inet_connection_sock_af_ops ipv6_mapped; | 76 | static struct inet_connection_sock_af_ops ipv6_mapped; |
78 | static struct inet_connection_sock_af_ops ipv6_specific; | 77 | static struct inet_connection_sock_af_ops ipv6_specific; |
79 | 78 | ||
80 | int 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 | |||
101 | static int tcp_v6_get_port(struct sock *sk, unsigned short snum) | 79 | static 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 | ||
1503 | static 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 | |||
1553 | static 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 | |||
1610 | static 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 | |||
1626 | static int tcp_v6_remember_stamp(struct sock *sk) | 1481 | static 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 | ||
1632 | static struct inet_connection_sock_af_ops ipv6_specific = { | 1487 | static 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 | ||