if passed sockaddr has family AF_UNSPEC, use socket family of the socket

the sockaddr is used for

this fixes bind() problem in Linux version of Theocracy, testing
by Thomas Klausner
This commit is contained in:
jdolecek 2004-09-12 15:32:55 +00:00
parent 4d38f47519
commit 9cc50db4c5
1 changed files with 40 additions and 11 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_socket.c,v 1.52 2004/09/05 09:38:17 jdolecek Exp $ */
/* $NetBSD: linux_socket.c,v 1.53 2004/09/12 15:32:55 jdolecek Exp $ */
/*-
* Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.52 2004/09/05 09:38:17 jdolecek Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.53 2004/09/12 15:32:55 jdolecek Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@ -60,6 +60,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.52 2004/09/05 09:38:17 jdolecek E
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/domain.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
@ -114,8 +115,8 @@ int linux_to_bsd_ip_sockopt __P((int));
int linux_to_bsd_tcp_sockopt __P((int));
int linux_to_bsd_udp_sockopt __P((int));
int linux_getifhwaddr __P((struct proc *, register_t *, u_int, void *));
static int linux_sa_get __P((struct proc *, caddr_t *sgp, struct sockaddr **sap,
const struct osockaddr *osa, int *osalen));
static int linux_sa_get __P((struct proc *, int, caddr_t *, struct sockaddr **,
const struct osockaddr *, int *));
static int linux_sa_put __P((struct osockaddr *osa));
static int linux_to_bsd_msg_flags __P((int));
static int bsd_to_linux_msg_flags __P((int));
@ -386,7 +387,9 @@ linux_sys_sendto(l, v, retval)
int error;
caddr_t sg = stackgap_init(p, 0);
if ((error = linux_sa_get(p, &sg, &sa, SCARG(uap, to), &tolen)))
error = linux_sa_get(p, SCARG(uap, s), &sg, &sa,
SCARG(uap, to), &tolen);
if (error)
return (error);
SCARG(&bsa, to) = sa;
@ -440,7 +443,7 @@ linux_sys_sendmsg(l, v, retval)
struct sockaddr *sa;
sg = stackgap_init(p, 0);
error = linux_sa_get(p, &sg, &sa,
error = linux_sa_get(p, SCARG(uap, s), &sg, &sa,
(struct osockaddr *) msg.msg_name, &msg.msg_namelen);
if (error)
goto done;
@ -1322,7 +1325,8 @@ linux_sys_connect(l, v, retval)
int namlen;
namlen = SCARG(uap, namelen);
error = linux_sa_get(p, &sg, &sa, SCARG(uap, name), &namlen);
error = linux_sa_get(p, SCARG(uap, s), &sg, &sa,
SCARG(uap, name), &namlen);
if (error)
return (error);
@ -1381,7 +1385,8 @@ linux_sys_bind(l, v, retval)
struct sockaddr *sa;
caddr_t sg = stackgap_init(p, 0);
error = linux_sa_get(p, &sg, &sa, SCARG(uap, name), &namlen);
error = linux_sa_get(p, SCARG(uap, s), &sg, &sa,
SCARG(uap, name), &namlen);
if (error)
return (error);
@ -1443,8 +1448,9 @@ linux_sys_getpeername(l, v, retval)
* the converted structure there, address on stackgap returned in sap.
*/
static int
linux_sa_get(p, sgp, sap, osa, osalen)
linux_sa_get(p, s, sgp, sap, osa, osalen)
struct proc *p;
int s;
caddr_t *sgp;
struct sockaddr **sap;
const struct osockaddr *osa;
@ -1520,8 +1526,31 @@ linux_sa_get(p, sgp, sap, osa, osalen)
error = EINVAL;
goto out;
}
} else
#endif
}
#endif
/*
* If the family is unspecified, use address family of the
* socket. This avoid triggering COMPAT_43 struct socket family check
* in sockargs() on little-endian machines, and strict family checks
* in netinet/in_pcb.c et.al.
*/
if (bdom == AF_UNSPEC) {
struct file *fp;
struct socket *so;
/* getsock() will use the descriptor for us */
if ((error = getsock(p->p_fd, s, &fp)) != 0)
goto out;
so = (struct socket *)fp->f_data;
bdom = so->so_proto->pr_domain->dom_family;
FILE_UNUSE(fp, p);
DPRINTF(("AF_UNSPEC family adjusted to %d\n", bdom));
}
if (bdom == AF_INET) {
alloclen = sizeof(struct sockaddr_in);
}