diff options
Diffstat (limited to 'net/rds/send.c')
-rw-r--r-- | net/rds/send.c | 67 |
1 files changed, 52 insertions, 15 deletions
diff --git a/net/rds/send.c b/net/rds/send.c index 94c7f74909be..6ed2e925c36a 100644 --- a/net/rds/send.c +++ b/net/rds/send.c | |||
@@ -709,7 +709,7 @@ void rds_send_drop_acked(struct rds_connection *conn, u64 ack, | |||
709 | } | 709 | } |
710 | EXPORT_SYMBOL_GPL(rds_send_drop_acked); | 710 | EXPORT_SYMBOL_GPL(rds_send_drop_acked); |
711 | 711 | ||
712 | void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest) | 712 | void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in6 *dest) |
713 | { | 713 | { |
714 | struct rds_message *rm, *tmp; | 714 | struct rds_message *rm, *tmp; |
715 | struct rds_connection *conn; | 715 | struct rds_connection *conn; |
@@ -721,8 +721,9 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest) | |||
721 | spin_lock_irqsave(&rs->rs_lock, flags); | 721 | spin_lock_irqsave(&rs->rs_lock, flags); |
722 | 722 | ||
723 | list_for_each_entry_safe(rm, tmp, &rs->rs_send_queue, m_sock_item) { | 723 | list_for_each_entry_safe(rm, tmp, &rs->rs_send_queue, m_sock_item) { |
724 | if (dest && (dest->sin_addr.s_addr != rm->m_daddr || | 724 | if (dest && |
725 | dest->sin_port != rm->m_inc.i_hdr.h_dport)) | 725 | (!ipv6_addr_equal(&dest->sin6_addr, &rm->m_daddr) || |
726 | dest->sin6_port != rm->m_inc.i_hdr.h_dport)) | ||
726 | continue; | 727 | continue; |
727 | 728 | ||
728 | list_move(&rm->m_sock_item, &list); | 729 | list_move(&rm->m_sock_item, &list); |
@@ -1059,8 +1060,8 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) | |||
1059 | { | 1060 | { |
1060 | struct sock *sk = sock->sk; | 1061 | struct sock *sk = sock->sk; |
1061 | struct rds_sock *rs = rds_sk_to_rs(sk); | 1062 | struct rds_sock *rs = rds_sk_to_rs(sk); |
1063 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); | ||
1062 | DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); | 1064 | DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); |
1063 | __be32 daddr; | ||
1064 | __be16 dport; | 1065 | __be16 dport; |
1065 | struct rds_message *rm = NULL; | 1066 | struct rds_message *rm = NULL; |
1066 | struct rds_connection *conn; | 1067 | struct rds_connection *conn; |
@@ -1069,10 +1070,13 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) | |||
1069 | int nonblock = msg->msg_flags & MSG_DONTWAIT; | 1070 | int nonblock = msg->msg_flags & MSG_DONTWAIT; |
1070 | long timeo = sock_sndtimeo(sk, nonblock); | 1071 | long timeo = sock_sndtimeo(sk, nonblock); |
1071 | struct rds_conn_path *cpath; | 1072 | struct rds_conn_path *cpath; |
1073 | struct in6_addr daddr; | ||
1074 | __u32 scope_id = 0; | ||
1072 | size_t total_payload_len = payload_len, rdma_payload_len = 0; | 1075 | size_t total_payload_len = payload_len, rdma_payload_len = 0; |
1073 | bool zcopy = ((msg->msg_flags & MSG_ZEROCOPY) && | 1076 | bool zcopy = ((msg->msg_flags & MSG_ZEROCOPY) && |
1074 | sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY)); | 1077 | sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY)); |
1075 | int num_sgs = ceil(payload_len, PAGE_SIZE); | 1078 | int num_sgs = ceil(payload_len, PAGE_SIZE); |
1079 | int namelen; | ||
1076 | 1080 | ||
1077 | /* Mirror Linux UDP mirror of BSD error message compatibility */ | 1081 | /* Mirror Linux UDP mirror of BSD error message compatibility */ |
1078 | /* XXX: Perhaps MSG_MORE someday */ | 1082 | /* XXX: Perhaps MSG_MORE someday */ |
@@ -1081,27 +1085,59 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) | |||
1081 | goto out; | 1085 | goto out; |
1082 | } | 1086 | } |
1083 | 1087 | ||
1084 | if (msg->msg_namelen) { | 1088 | namelen = msg->msg_namelen; |
1085 | /* XXX fail non-unicast destination IPs? */ | 1089 | if (namelen != 0) { |
1086 | if (msg->msg_namelen < sizeof(*usin) || usin->sin_family != AF_INET) { | 1090 | if (namelen < sizeof(*usin)) { |
1091 | ret = -EINVAL; | ||
1092 | goto out; | ||
1093 | } | ||
1094 | switch (namelen) { | ||
1095 | case sizeof(*usin): | ||
1096 | if (usin->sin_family != AF_INET || | ||
1097 | usin->sin_addr.s_addr == htonl(INADDR_ANY) || | ||
1098 | usin->sin_addr.s_addr == htonl(INADDR_BROADCAST) || | ||
1099 | IN_MULTICAST(ntohl(usin->sin_addr.s_addr))) { | ||
1100 | ret = -EINVAL; | ||
1101 | goto out; | ||
1102 | } | ||
1103 | ipv6_addr_set_v4mapped(usin->sin_addr.s_addr, &daddr); | ||
1104 | dport = usin->sin_port; | ||
1105 | break; | ||
1106 | |||
1107 | case sizeof(*sin6): { | ||
1108 | ret = -EPROTONOSUPPORT; | ||
1109 | goto out; | ||
1110 | } | ||
1111 | |||
1112 | default: | ||
1087 | ret = -EINVAL; | 1113 | ret = -EINVAL; |
1088 | goto out; | 1114 | goto out; |
1089 | } | 1115 | } |
1090 | daddr = usin->sin_addr.s_addr; | ||
1091 | dport = usin->sin_port; | ||
1092 | } else { | 1116 | } else { |
1093 | /* We only care about consistency with ->connect() */ | 1117 | /* We only care about consistency with ->connect() */ |
1094 | lock_sock(sk); | 1118 | lock_sock(sk); |
1095 | daddr = rs->rs_conn_addr; | 1119 | daddr = rs->rs_conn_addr; |
1096 | dport = rs->rs_conn_port; | 1120 | dport = rs->rs_conn_port; |
1121 | scope_id = rs->rs_bound_scope_id; | ||
1097 | release_sock(sk); | 1122 | release_sock(sk); |
1098 | } | 1123 | } |
1099 | 1124 | ||
1100 | lock_sock(sk); | 1125 | lock_sock(sk); |
1101 | if (daddr == 0 || rs->rs_bound_addr == 0) { | 1126 | if (ipv6_addr_any(&rs->rs_bound_addr) || ipv6_addr_any(&daddr)) { |
1102 | release_sock(sk); | 1127 | release_sock(sk); |
1103 | ret = -ENOTCONN; /* XXX not a great errno */ | 1128 | ret = -ENOTCONN; |
1104 | goto out; | 1129 | goto out; |
1130 | } else if (namelen != 0) { | ||
1131 | /* Cannot send to an IPv4 address using an IPv6 source | ||
1132 | * address and cannot send to an IPv6 address using an | ||
1133 | * IPv4 source address. | ||
1134 | */ | ||
1135 | if (ipv6_addr_v4mapped(&daddr) ^ | ||
1136 | ipv6_addr_v4mapped(&rs->rs_bound_addr)) { | ||
1137 | release_sock(sk); | ||
1138 | ret = -EOPNOTSUPP; | ||
1139 | goto out; | ||
1140 | } | ||
1105 | } | 1141 | } |
1106 | release_sock(sk); | 1142 | release_sock(sk); |
1107 | 1143 | ||
@@ -1155,13 +1191,14 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) | |||
1155 | 1191 | ||
1156 | /* rds_conn_create has a spinlock that runs with IRQ off. | 1192 | /* rds_conn_create has a spinlock that runs with IRQ off. |
1157 | * Caching the conn in the socket helps a lot. */ | 1193 | * Caching the conn in the socket helps a lot. */ |
1158 | if (rs->rs_conn && rs->rs_conn->c_faddr == daddr) | 1194 | if (rs->rs_conn && ipv6_addr_equal(&rs->rs_conn->c_faddr, &daddr)) |
1159 | conn = rs->rs_conn; | 1195 | conn = rs->rs_conn; |
1160 | else { | 1196 | else { |
1161 | conn = rds_conn_create_outgoing(sock_net(sock->sk), | 1197 | conn = rds_conn_create_outgoing(sock_net(sock->sk), |
1162 | rs->rs_bound_addr, daddr, | 1198 | &rs->rs_bound_addr, &daddr, |
1163 | rs->rs_transport, | 1199 | rs->rs_transport, |
1164 | sock->sk->sk_allocation); | 1200 | sock->sk->sk_allocation, |
1201 | scope_id); | ||
1165 | if (IS_ERR(conn)) { | 1202 | if (IS_ERR(conn)) { |
1166 | ret = PTR_ERR(conn); | 1203 | ret = PTR_ERR(conn); |
1167 | goto out; | 1204 | goto out; |