mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-03 16:30:29 +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/sysv/consts/sio.h"
|
||||
|
||||
|
||||
#include "libc/stdio/stdio.h"
|
||||
#define PRINTF weaken(printf)
|
||||
|
||||
/* SIOCGIFCONF:
|
||||
* Takes an struct ifconf object of a given size
|
||||
* Modifies the following:
|
||||
|
@ -39,66 +35,122 @@
|
|||
int ioctl_siocgifconf_nt(int, struct ifconf *) hidden;
|
||||
|
||||
static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
|
||||
/* Same as the default for now... */
|
||||
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)) {
|
||||
return enomem();
|
||||
} else {
|
||||
/* On BSD the size of the struct ifreq is smaller (16 bytes
|
||||
* instead of 24 bytes), so buffers need to be adjusted accordingly
|
||||
*
|
||||
* TODO: Since BSD requires a SMALLER buffer we don't need to
|
||||
* 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_len = numReq * sizeof(struct ifreq_bsd);
|
||||
buf = weaken(malloc)(ifc_bsd.ifc_len);
|
||||
if (!buf) {
|
||||
return enomem();
|
||||
}
|
||||
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 {
|
||||
// 100% compatible with Linux
|
||||
/* 100% compatible with Linux */
|
||||
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.
|
||||
*
|
||||
* @see ioctl(fd, SIOCGIFCONF, tio) dispatches here
|
||||
*/
|
||||
int ioctl_siocgifconf(int fd, struct ifconf *ifc) {
|
||||
int ioctl_siocgifconf(int fd, void *ifc) {
|
||||
if (!IsWindows()) {
|
||||
return ioctl_siocgifconf_sysv(fd, ifc);
|
||||
return ioctl_siocgifconf_sysv(fd, (struct ifconf *)ifc);
|
||||
} 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, TCSETSF)) return ioctl_tcsets(FD, REQUEST, 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)
|
||||
|
||||
/*
|
||||
|
@ -44,6 +46,8 @@ int ioctl_tiocgwinsz_nt(int, void *);
|
|||
int ioctl_tiocswinsz(int, void *);
|
||||
int ioctl_tiocswinsz_nt(int, void *);
|
||||
int ioctl_siocgifconf(int, void *);
|
||||
int ioctl_siocgifaddr(int, void *);
|
||||
int ioctl_siocgifnetmask(int, void *);
|
||||
int ioctl_default(int, uint64_t, void *);
|
||||
|
||||
forceinline int ioctl_dispatch(int fd, uint64_t request, void *memory) {
|
||||
|
|
|
@ -53,6 +53,43 @@ struct sockaddr_un_bsd {
|
|||
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 {
|
||||
int family;
|
||||
int type;
|
||||
|
|
|
@ -87,7 +87,7 @@ struct msghdr { /* Linux+NT ABI */
|
|||
* must know all networks accessible).
|
||||
*/
|
||||
struct ifconf {
|
||||
int ifc_len; /* size of buffer */
|
||||
uint64_t ifc_len; /* size of buffer */
|
||||
union {
|
||||
char *ifcu_buf;
|
||||
struct ifreq *ifcu_req;
|
||||
|
@ -109,41 +109,16 @@ struct ifreq {
|
|||
|
||||
union {
|
||||
struct sockaddr ifru_addr;
|
||||
struct sockaddr ifru_dstaddr;
|
||||
struct sockaddr ifru_broadaddr;
|
||||
struct sockaddr ifru_netmask;
|
||||
struct sockaddr ifru_hwaddr;
|
||||
short ifru_flags;
|
||||
int ifru_ivalue;
|
||||
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];
|
||||
char ifru_pad[24]; /* ifru_map is the largest, just pad */
|
||||
} ifr_ifru;
|
||||
};
|
||||
|
||||
#define ifr_name ifr_ifrn.ifrn_name /* interface name */
|
||||
#define ifr_addr ifr_ifru.ifru_addr /* address */
|
||||
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
|
||||
#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_netmask ifr_ifru.ifru_netmask /* netmask */
|
||||
#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_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue