| 1163 | } |
| 1164 | |
| 1165 | static int |
| 1166 | udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) |
| 1167 | { |
| 1168 | #ifdef INET |
| 1169 | struct epoch_tracker et; |
| 1170 | #endif |
| 1171 | struct inpcb *inp; |
| 1172 | struct inpcbinfo *pcbinfo; |
| 1173 | struct sockaddr_in6 *sin6; |
| 1174 | int error; |
| 1175 | u_char vflagsav; |
| 1176 | |
| 1177 | pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol); |
| 1178 | inp = sotoinpcb(so); |
| 1179 | sin6 = (struct sockaddr_in6 *)nam; |
| 1180 | KASSERT(inp != NULL, ("udp6_connect: inp == NULL")); |
| 1181 | |
| 1182 | /* |
| 1183 | * XXXRW: Need to clarify locking of v4/v6 flags. |
| 1184 | */ |
| 1185 | INP_WLOCK(inp); |
| 1186 | #ifdef INET |
| 1187 | if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { |
| 1188 | struct sockaddr_in sin; |
| 1189 | |
| 1190 | if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) { |
| 1191 | error = EINVAL; |
| 1192 | goto out; |
| 1193 | } |
| 1194 | if ((inp->inp_vflag & INP_IPV4) == 0) { |
| 1195 | error = EAFNOSUPPORT; |
| 1196 | goto out; |
| 1197 | } |
| 1198 | if (inp->inp_faddr.s_addr != INADDR_ANY) { |
| 1199 | error = EISCONN; |
| 1200 | goto out; |
| 1201 | } |
| 1202 | in6_sin6_2_sin(&sin, sin6); |
| 1203 | error = prison_remote_ip4(td->td_ucred, &sin.sin_addr); |
| 1204 | if (error != 0) |
| 1205 | goto out; |
| 1206 | vflagsav = inp->inp_vflag; |
| 1207 | inp->inp_vflag |= INP_IPV4; |
| 1208 | inp->inp_vflag &= ~INP_IPV6; |
| 1209 | NET_EPOCH_ENTER(et); |
| 1210 | INP_HASH_WLOCK(pcbinfo); |
| 1211 | error = in_pcbconnect(inp, (struct sockaddr *)&sin, |
| 1212 | td->td_ucred); |
| 1213 | INP_HASH_WUNLOCK(pcbinfo); |
| 1214 | NET_EPOCH_EXIT(et); |
| 1215 | /* |
| 1216 | * If connect succeeds, mark socket as connected. If |
| 1217 | * connect fails and socket is unbound, reset inp_vflag |
| 1218 | * field. |
| 1219 | */ |
| 1220 | if (error == 0) |
| 1221 | soisconnected(so); |
| 1222 | else if (inp->inp_laddr.s_addr == INADDR_ANY && |
nothing calls this directly
no test coverage detected