mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-05 17:30:27 +00:00
Fixed all the issues related to BSD for the implementation of SIGCGIFCONF, SIGCGIFADDR, and SIOCGIFNETMASK ioctls
This commit is contained in:
parent
f6388b2bf6
commit
1b8776dea7
4 changed files with 144 additions and 76 deletions
|
@ -23,10 +23,6 @@
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
#include "libc/sysv/consts/sio.h"
|
#include "libc/sysv/consts/sio.h"
|
||||||
|
|
||||||
|
|
||||||
#include "libc/stdio/stdio.h"
|
|
||||||
#define PRINTF weaken(printf)
|
|
||||||
|
|
||||||
/* SIOCGIFCONF:
|
/* SIOCGIFCONF:
|
||||||
* Takes an struct ifconf object of a given size
|
* Takes an struct ifconf object of a given size
|
||||||
* Modifies the following:
|
* Modifies the following:
|
||||||
|
@ -39,66 +35,122 @@
|
||||||
int ioctl_siocgifconf_nt(int, struct ifconf *) hidden;
|
int ioctl_siocgifconf_nt(int, struct ifconf *) hidden;
|
||||||
|
|
||||||
static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
|
static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
|
||||||
/* Same as the default for now... */
|
|
||||||
if (IsBsd()) {
|
if (IsBsd()) {
|
||||||
|
/* BSD uses a slightly different memory structure where:
|
||||||
|
* - sizeof(struct ifreq) is 32 bytes instead of 40 bytes
|
||||||
|
* - ifc.ifc_len is uint32_t instead of uint64_t
|
||||||
|
* - struct ifconf is #pragma pack(4) (instead of the default pack(8))
|
||||||
|
*/
|
||||||
|
int i;
|
||||||
|
char *buf; /* Temporary buffer to store ifreq */
|
||||||
|
char *pBsdReq; /* Scan through buf records */
|
||||||
|
char *pBsdEnd; /* End of the ifreq */
|
||||||
|
|
||||||
|
struct ifconf_bsd ifc_bsd;
|
||||||
|
struct ifreq_bsd *bsdReq;
|
||||||
|
struct ifreq *req;
|
||||||
|
size_t numReq = ifc->ifc_len / sizeof(struct ifreq);
|
||||||
|
|
||||||
if (!weaken(malloc)) {
|
if (!weaken(malloc)) {
|
||||||
return enomem();
|
return enomem();
|
||||||
} else {
|
}
|
||||||
/* On BSD the size of the struct ifreq is smaller (16 bytes
|
ifc_bsd.ifc_len = numReq * sizeof(struct ifreq_bsd);
|
||||||
* instead of 24 bytes), so buffers need to be adjusted accordingly
|
buf = weaken(malloc)(ifc_bsd.ifc_len);
|
||||||
*
|
if (!buf) {
|
||||||
* TODO: Since BSD requires a SMALLER buffer we don't need to
|
return enomem();
|
||||||
* malloc a temp buffer, insted reuse the same buffer and
|
|
||||||
* safely move overlapping ifrn_name chunks
|
|
||||||
*/
|
|
||||||
int i;
|
|
||||||
struct ifconf ifc_bsd;
|
|
||||||
size_t num_ifreq = ifc->ifc_len / sizeof(struct ifreq);
|
|
||||||
|
|
||||||
PRINTF("Mac version!\n");
|
|
||||||
ifc_bsd.ifc_len = (num_ifreq * sizeof(struct ifreq_bsd)); /* Adjust max buffer */
|
|
||||||
ifc_bsd.ifc_buf = weaken(malloc)(ifc_bsd.ifc_len);
|
|
||||||
PRINTF("numInterf Linux=%lu\n", num_ifreq);
|
|
||||||
PRINTF("BSD size=%lu\n", ifc_bsd.ifc_len);
|
|
||||||
PRINTF("Linux size=%lu\n", ifc->ifc_len);
|
|
||||||
if (!ifc_bsd.ifc_buf) {
|
|
||||||
PRINTF("Malloc failed\n");
|
|
||||||
return enomem();
|
|
||||||
}
|
|
||||||
PRINTF("Calling ioctl()\n");
|
|
||||||
i = sys_ioctl(fd, SIOCGIFCONF, &ifc_bsd);
|
|
||||||
PRINTF("rc=%d\n", i);
|
|
||||||
if (i < 0) {
|
|
||||||
weaken(free)(ifc_bsd.ifc_buf);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Number of interfaces returned */
|
|
||||||
num_ifreq = ifc_bsd.ifc_len / sizeof(struct ifreq_bsd);
|
|
||||||
for (i = 1; i < num_ifreq; ++i) {
|
|
||||||
/* The first interface always match the same position */
|
|
||||||
memcpy(ifc->ifc_req[i].ifr_name, ifc_bsd.ifc_req[i].ifr_name, IFNAMSIZ);
|
|
||||||
}
|
|
||||||
ifc->ifc_len = num_ifreq * sizeof(struct ifreq);
|
|
||||||
weaken(free)(ifc_bsd.ifc_buf);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
ifc_bsd.ifc_buf = buf;
|
||||||
|
|
||||||
|
if ((i = sys_ioctl(fd, SIOCGIFCONF, &ifc_bsd)) < 0) {
|
||||||
|
weaken(free)(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* On BSD the size of the struct ifreq is different than Linux.
|
||||||
|
* On Linux is fixed (40 bytes), but on BSD the struct sockaddr
|
||||||
|
* has variable length, making the whole struct ifreq a variable
|
||||||
|
* sized record.
|
||||||
|
*/
|
||||||
|
for (pBsdReq = buf, pBsdEnd = buf + ifc_bsd.ifc_len, req = ifc->ifc_req;
|
||||||
|
pBsdReq < pBsdEnd;
|
||||||
|
++req) {
|
||||||
|
bsdReq = (struct ifreq_bsd *)pBsdReq;
|
||||||
|
memcpy(req->ifr_name, bsdReq->ifr_name, IFNAMSIZ);
|
||||||
|
memcpy(&req->ifr_addr, &bsdReq->ifr_addr, sizeof(struct sockaddr_bsd));
|
||||||
|
sockaddr2linux(&req->ifr_addr);
|
||||||
|
|
||||||
|
pBsdReq += IFNAMSIZ + bsdReq->ifr_addr.sa_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust len */
|
||||||
|
ifc->ifc_len = (size_t)((char *)req - ifc->ifc_buf);
|
||||||
|
weaken(free)(buf);
|
||||||
|
return 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// 100% compatible with Linux
|
/* 100% compatible with Linux */
|
||||||
return sys_ioctl(fd, SIOCGIFCONF, ifc);
|
return sys_ioctl(fd, SIOCGIFCONF, ifc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ioctl_siocgifaddr_sysv(int fd, struct ifreq *ifr) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (IsBsd()) {
|
||||||
|
sockaddr2bsd(&ifr->ifr_addr);
|
||||||
|
}
|
||||||
|
if ((i = sys_ioctl(fd, SIOCGIFADDR, ifr)) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (IsBsd()) {
|
||||||
|
sockaddr2linux(&ifr->ifr_addr);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioctl_siocgifnetmask_sysv(int fd, struct ifreq *ifr) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (IsBsd()) {
|
||||||
|
sockaddr2bsd(&ifr->ifr_netmask);
|
||||||
|
}
|
||||||
|
if ((i = sys_ioctl(fd, SIOCGIFNETMASK, ifr)) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (IsBsd()) {
|
||||||
|
sockaddr2linux(&ifr->ifr_netmask);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns information about network interfaces.
|
* Returns information about network interfaces.
|
||||||
*
|
*
|
||||||
* @see ioctl(fd, SIOCGIFCONF, tio) dispatches here
|
* @see ioctl(fd, SIOCGIFCONF, tio) dispatches here
|
||||||
*/
|
*/
|
||||||
int ioctl_siocgifconf(int fd, struct ifconf *ifc) {
|
int ioctl_siocgifconf(int fd, void *ifc) {
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
return ioctl_siocgifconf_sysv(fd, ifc);
|
return ioctl_siocgifconf_sysv(fd, (struct ifconf *)ifc);
|
||||||
} else {
|
} else {
|
||||||
return ioctl_siocgifconf_nt(fd, ifc);
|
return enotsup();
|
||||||
|
//return ioctl_siocgifconf_nt(fd, ifc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ioctl_siocgifaddr(int fd, void *ifr) {
|
||||||
|
if (!IsWindows()) {
|
||||||
|
return ioctl_siocgifaddr_sysv(fd, (struct ifreq *)ifr);
|
||||||
|
} else {
|
||||||
|
return enotsup();
|
||||||
|
//return ioctl_siocgifaddr_nt(fd, ifc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioctl_siocgifnetmask(int fd, void *ifr) {
|
||||||
|
if (!IsWindows()) {
|
||||||
|
return ioctl_siocgifnetmask_sysv(fd, (struct ifreq *)ifr);
|
||||||
|
} else {
|
||||||
|
return enotsup();
|
||||||
|
//return ioctl_siocgifaddr_nt(fd, ifc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ int ioctl(int, uint64_t, void *);
|
||||||
if (CMP(request, TCSETSW)) return ioctl_tcsets(FD, REQUEST, MEMORY); \
|
if (CMP(request, TCSETSW)) return ioctl_tcsets(FD, REQUEST, MEMORY); \
|
||||||
if (CMP(request, TCSETSF)) return ioctl_tcsets(FD, REQUEST, MEMORY); \
|
if (CMP(request, TCSETSF)) return ioctl_tcsets(FD, REQUEST, MEMORY); \
|
||||||
if (CMP(request, SIOCGIFCONF)) return ioctl_siocgifconf(FD, MEMORY); \
|
if (CMP(request, SIOCGIFCONF)) return ioctl_siocgifconf(FD, MEMORY); \
|
||||||
|
if (CMP(request, SIOCGIFADDR)) return ioctl_siocgifaddr(FD, MEMORY); \
|
||||||
|
if (CMP(request, SIOCGIFNETMASK)) return ioctl_siocgifnetmask(FD, MEMORY); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -44,6 +46,8 @@ int ioctl_tiocgwinsz_nt(int, void *);
|
||||||
int ioctl_tiocswinsz(int, void *);
|
int ioctl_tiocswinsz(int, void *);
|
||||||
int ioctl_tiocswinsz_nt(int, void *);
|
int ioctl_tiocswinsz_nt(int, void *);
|
||||||
int ioctl_siocgifconf(int, void *);
|
int ioctl_siocgifconf(int, void *);
|
||||||
|
int ioctl_siocgifaddr(int, void *);
|
||||||
|
int ioctl_siocgifnetmask(int, void *);
|
||||||
int ioctl_default(int, uint64_t, void *);
|
int ioctl_default(int, uint64_t, void *);
|
||||||
|
|
||||||
forceinline int ioctl_dispatch(int fd, uint64_t request, void *memory) {
|
forceinline int ioctl_dispatch(int fd, uint64_t request, void *memory) {
|
||||||
|
|
|
@ -53,6 +53,43 @@ struct sockaddr_un_bsd {
|
||||||
char sun_path[108];
|
char sun_path[108];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------------
|
||||||
|
* ioctl SIOCGIFCONF & others:
|
||||||
|
*
|
||||||
|
* BSD has a different structure. All the ioctl will adjust to use
|
||||||
|
* the ifreq with the ifreq_bsd
|
||||||
|
*/
|
||||||
|
struct ifreq_bsd {
|
||||||
|
union {
|
||||||
|
char ifrn_name[IFNAMSIZ];
|
||||||
|
} ifr_ifrn;
|
||||||
|
|
||||||
|
union {
|
||||||
|
/* Right now we only list the structures used by the few ioctl that are
|
||||||
|
* supported by Cosmopolitan. Add your own definition here if you need
|
||||||
|
* a particular ioctl that requires polyfill for BSD
|
||||||
|
*/
|
||||||
|
struct sockaddr_bsd ifru_addr;
|
||||||
|
struct sockaddr_bsd ifru_netmask;
|
||||||
|
short ifru_flags;
|
||||||
|
char ifru_pad[16]; /* used as padding */
|
||||||
|
} ifr_ifru;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(4)
|
||||||
|
struct ifconf_bsd {
|
||||||
|
uint32_t ifc_len; /* size of buffer */
|
||||||
|
union {
|
||||||
|
char *ifcu_buf;
|
||||||
|
struct ifreq_bsd *ifcu_req;
|
||||||
|
} ifc_ifcu;
|
||||||
|
};
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
struct SockFd {
|
struct SockFd {
|
||||||
int family;
|
int family;
|
||||||
int type;
|
int type;
|
||||||
|
|
|
@ -87,7 +87,7 @@ struct msghdr { /* Linux+NT ABI */
|
||||||
* must know all networks accessible).
|
* must know all networks accessible).
|
||||||
*/
|
*/
|
||||||
struct ifconf {
|
struct ifconf {
|
||||||
int ifc_len; /* size of buffer */
|
uint64_t ifc_len; /* size of buffer */
|
||||||
union {
|
union {
|
||||||
char *ifcu_buf;
|
char *ifcu_buf;
|
||||||
struct ifreq *ifcu_req;
|
struct ifreq *ifcu_req;
|
||||||
|
@ -109,41 +109,16 @@ struct ifreq {
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct sockaddr ifru_addr;
|
struct sockaddr ifru_addr;
|
||||||
struct sockaddr ifru_dstaddr;
|
|
||||||
struct sockaddr ifru_broadaddr;
|
|
||||||
struct sockaddr ifru_netmask;
|
struct sockaddr ifru_netmask;
|
||||||
struct sockaddr ifru_hwaddr;
|
|
||||||
short ifru_flags;
|
short ifru_flags;
|
||||||
int ifru_ivalue;
|
char ifru_pad[24]; /* ifru_map is the largest, just pad */
|
||||||
int ifru_mtu;
|
|
||||||
char ifru_pad[24]; /* ifru_map, used as padding */
|
|
||||||
} ifr_ifru;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ifreq_bsd {
|
|
||||||
union {
|
|
||||||
char ifrn_name[IFNAMSIZ];
|
|
||||||
} ifr_ifrn;
|
|
||||||
|
|
||||||
union {
|
|
||||||
char ifru_pad[16];
|
|
||||||
} ifr_ifru;
|
} ifr_ifru;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ifr_name ifr_ifrn.ifrn_name /* interface name */
|
#define ifr_name ifr_ifrn.ifrn_name /* interface name */
|
||||||
#define ifr_addr ifr_ifru.ifru_addr /* address */
|
#define ifr_addr ifr_ifru.ifru_addr /* address */
|
||||||
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
|
#define ifr_netmask ifr_ifru.ifru_netmask /* netmask */
|
||||||
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
|
|
||||||
#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
|
|
||||||
#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
|
|
||||||
|
|
||||||
#define ifr_flags ifr_ifru.ifru_flags /* flags */
|
#define ifr_flags ifr_ifru.ifru_flags /* flags */
|
||||||
#define ifr_metric ifr_ifru.ifru_ivalue /* metric */
|
|
||||||
#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
|
|
||||||
#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
|
|
||||||
#define ifr_qlen ifr_ifru.ifru_ivalue /* queue length */
|
|
||||||
#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
|
|
||||||
/* ifru_map is unsupported */
|
|
||||||
|
|
||||||
#define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
|
#define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
|
||||||
#define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
|
#define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue