Changeset View
Changeset View
Standalone View
Standalone View
linsysfs.c
/*- | /*- | ||||
* Copyright (c) 2006 IronPort Systems | * Copyright (c) 2006 IronPort Systems | ||||
* Copyright (c) 2017 Carlos Neira cneirabustos@gmail.com | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
Context not available. | |||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD: releng/11.1/sys/compat/linsysfs/linsysfs.c 317318 2017-04-23 06:45:21Z dchagin $"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
Context not available. | |||||
#include <dev/pci/pcivar.h> | #include <dev/pci/pcivar.h> | ||||
#include <dev/pci/pcireg.h> | #include <dev/pci/pcireg.h> | ||||
#include <sys/ctype.h> | |||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_types.h> | |||||
#include <net/if_var.h> | |||||
#include <net/if_dl.h> | |||||
#include <net/vnet.h> | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
Context not available. | |||||
#include <compat/linux/linux_mib.h> | #include <compat/linux/linux_mib.h> | ||||
#include <compat/linux/linux_util.h> | #include <compat/linux/linux_util.h> | ||||
#include <fs/pseudofs/pseudofs.h> | #include <fs/pseudofs/pseudofs.h> | ||||
#include <sys/jail.h> | |||||
#define LINUX_IFNAMSIZ 16 | |||||
struct scsi_host_queue { | struct scsi_host_queue { | ||||
TAILQ_ENTRY(scsi_host_queue) scsi_host_next; | TAILQ_ENTRY(scsi_host_queue) scsi_host_next; | ||||
Context not available. | |||||
static int host_number = 0; | static int host_number = 0; | ||||
static int | static int | ||||
atoi(const char *str) | atoi(const char *str) | ||||
{ | { | ||||
Context not available. | |||||
} | } | ||||
/* | /* | ||||
* Filler function for sys/class/net/<iface> | |||||
* Used as reference | |||||
* https://grok.elemental.org/source/xref/illumos-joyent/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c | |||||
* and Linux kernel documentation for /sys/class/net | |||||
* Only 2 interfaces are created eth0 and lo and they expose the following files | |||||
* to make applications work: | |||||
* address, addr_len, flags, ifindex, mty, tx_queue_len and type | |||||
*/ | |||||
#define ETHERADDRL 6 | |||||
#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER) | |||||
static struct ifnet * | |||||
ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname) | |||||
{ | |||||
struct ifnet *ifp; | |||||
int len, unit; | |||||
char *ep; | |||||
int is_eth, index; | |||||
for (len = 0; len < LINUX_IFNAMSIZ; ++len) | |||||
if (!isalpha(lxname[len])) | |||||
break; | |||||
if (len == 0 || len == LINUX_IFNAMSIZ) | |||||
return (NULL); | |||||
unit = (int)strtoul(lxname + len, &ep, 10); | |||||
if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) | |||||
return (NULL); | |||||
index = 0; | |||||
is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0; | |||||
CURVNET_SET(TD_TO_VNET(td)); | |||||
IFNET_RLOCK(); | |||||
TAILQ_FOREACH(ifp, &V_ifnet, if_link) { | |||||
/* | |||||
* Allow Linux programs to use FreeBSD names. Don't presume | |||||
* we never have an interface named "eth", so don't make | |||||
* the test optional based on is_eth. | |||||
*/ | |||||
if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0) | |||||
break; | |||||
if (is_eth && IFP_IS_ETH(ifp) && unit == index++) | |||||
break; | |||||
} | |||||
IFNET_RUNLOCK(); | |||||
CURVNET_RESTORE(); | |||||
if (ifp != NULL) | |||||
strlcpy(bsdname, ifp->if_xname, IFNAMSIZ); | |||||
return (ifp); | |||||
} | |||||
static int | |||||
linsysfs_ifnet_addr (PFS_FILL_ARGS) { | |||||
struct ifnet* ifp; | |||||
char bsdname[IFNAMSIZ+1]; | |||||
uint8_t* address; | |||||
if (!memcmp((const char*)pn->pn_parent->pn_name,"lo",2)) { | |||||
sbuf_printf (sb, "00:00:00:00:00:00\n"); | |||||
return (0); | |||||
} else { | |||||
ifp = ifname_linux_to_bsd(curthread,(const char*)pn->pn_parent->pn_name,bsdname); | |||||
if (!ifp) { | |||||
sbuf_printf (sb, "00:00:00:00:00:00\n"); | |||||
return (0); | |||||
} | |||||
address = IF_LLADDR(ifp); | |||||
sbuf_printf (sb,"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", | |||||
address[0], address[1], address[2], | |||||
address[3], address[4], address[5]); | |||||
return (0); | |||||
} | |||||
} | |||||
//https://grok.elemental.org/source/xref/illumos-joyent/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c#LXSYS_ENDP_NET_ADDRLEN | |||||
static int | |||||
linsysfs_ifnet_addrlen (PFS_FILL_ARGS) { | |||||
sbuf_printf(sb,"6\n"); | |||||
return (0); | |||||
} | |||||
//;https://grok.elemental.org/source/xref/illumos-joyent/usr/src/uts/common/brand/lx/os/lx_misc.c#859 | |||||
static int | |||||
linsysfs_ifnet_flags (PFS_FILL_ARGS) { | |||||
int buf; | |||||
struct ifnet* ifp; | |||||
char bsdname[IFNAMSIZ+1]; | |||||
if (!memcmp((const char*)pn->pn_parent->pn_name,"eth",3)) { | |||||
ifp = ifname_linux_to_bsd(curthread,(const char*)pn->pn_parent->pn_name,bsdname); | |||||
buf = ifp->if_flags & (IFF_UP | IFF_BROADCAST | IFF_DEBUG | | |||||
IFF_LOOPBACK | IFF_POINTOPOINT | | |||||
IFF_DRV_RUNNING | IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI); | |||||
buf |= 0x1000; | |||||
sbuf_printf(sb,"0x%x\n",buf); | |||||
} else { | |||||
sbuf_printf(sb,"0x9\n"); | |||||
} | |||||
return (0); | |||||
} | |||||
static int | |||||
linsysfs_ifnet_ifindex (PFS_FILL_ARGS) { | |||||
struct ifnet* ifp; | |||||
char bsdname[IFNAMSIZ+1]; | |||||
if (!memcmp((const char*)pn->pn_parent->pn_name,"eth",3)) { | |||||
ifp = ifname_linux_to_bsd(curthread,(const char*)pn->pn_parent->pn_name,bsdname); | |||||
sbuf_printf(sb,"%u\n",ifp->if_index); | |||||
} else { | |||||
sbuf_printf(sb,"1\n"); | |||||
} | |||||
return (0); | |||||
} | |||||
static int | |||||
linsysfs_ifnet_mtu (PFS_FILL_ARGS) { | |||||
struct ifnet* ifp; | |||||
char bsdname[IFNAMSIZ+1]; | |||||
if (!memcmp((const char*)pn->pn_parent->pn_name,"lo",2)) { | |||||
sbuf_printf(sb,"65536\n"); | |||||
} else { | |||||
ifp = ifname_linux_to_bsd(curthread,(const char*)pn->pn_parent->pn_name,bsdname); | |||||
sbuf_printf(sb,"%u\n",ifp->if_mtu); | |||||
} | |||||
return (0); | |||||
} | |||||
static int | |||||
linsysfs_ifnet_tx_queue_len (PFS_FILL_ARGS) { | |||||
sbuf_printf(sb,"1000\n"); | |||||
return (0); | |||||
} | |||||
static int | |||||
linsysfs_ifnet_type (PFS_FILL_ARGS) { | |||||
if (!memcmp((const char*)pn->pn_parent->pn_name,"lo",2)) | |||||
sbuf_printf(sb,"772\n"); | |||||
else | |||||
sbuf_printf(sb,"2\n"); | |||||
return (0); | |||||
} | |||||
static void | |||||
linsysfs_listnics (struct pfs_node *dir) | |||||
{ | |||||
struct pfs_node *nic; | |||||
struct pfs_node *lo; | |||||
nic = pfs_create_dir (dir, "eth0", NULL, NULL, NULL, 0); | |||||
pfs_create_file (nic, "address", &linsysfs_ifnet_addr, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (nic, "addr_len", &linsysfs_ifnet_addrlen, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (nic, "flags", &linsysfs_ifnet_flags, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (nic, "ifindex", &linsysfs_ifnet_ifindex, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (nic, "mtu", &linsysfs_ifnet_mtu, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (nic, "tx_queue_len", &linsysfs_ifnet_tx_queue_len, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (nic, "type", &linsysfs_ifnet_type, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
lo = pfs_create_dir (dir, "lo", NULL, NULL, NULL, 0); | |||||
pfs_create_file (lo, "address", &linsysfs_ifnet_addr, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (lo, "addr_len", &linsysfs_ifnet_addrlen, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (lo, "flags", &linsysfs_ifnet_flags, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (lo, "ifindex", &linsysfs_ifnet_ifindex, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (lo, "mtu", &linsysfs_ifnet_mtu, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (lo, "tx_queue_len", &linsysfs_ifnet_tx_queue_len, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
pfs_create_file (lo, "type", &linsysfs_ifnet_type, | |||||
NULL, NULL, NULL, PFS_RD); | |||||
} | |||||
/* | |||||
* Constructor | * Constructor | ||||
*/ | */ | ||||
static int | static int | ||||
Context not available. | |||||
struct pfs_node *dir, *sys, *cpu; | struct pfs_node *dir, *sys, *cpu; | ||||
struct pfs_node *pci; | struct pfs_node *pci; | ||||
struct pfs_node *scsi; | struct pfs_node *scsi; | ||||
struct pfs_node *net; | |||||
devclass_t devclass; | devclass_t devclass; | ||||
device_t dev; | device_t dev; | ||||
Context not available. | |||||
/* /sys/class/... */ | /* /sys/class/... */ | ||||
scsi = pfs_create_dir(root, "class", NULL, NULL, NULL, 0); | scsi = pfs_create_dir(root, "class", NULL, NULL, NULL, 0); | ||||
/* /sys/class/net/.. */ | |||||
net = pfs_create_dir(scsi, "net", NULL, NULL, NULL, 0); | |||||
scsi = pfs_create_dir(scsi, "scsi_host", NULL, NULL, NULL, 0); | scsi = pfs_create_dir(scsi, "scsi_host", NULL, NULL, NULL, 0); | ||||
/* /sys/devices */ | /* /sys/devices */ | ||||
Context not available. | |||||
NULL, NULL, NULL, PFS_RD); | NULL, NULL, NULL, PFS_RD); | ||||
linsysfs_listcpus(cpu); | linsysfs_listcpus(cpu); | ||||
linsysfs_listnics(net); | |||||
return (0); | return (0); | ||||
} | } | ||||
Context not available. | |||||
return (0); | return (0); | ||||
} | } | ||||
PSEUDOFS(linsysfs, 1, PR_ALLOW_MOUNT_LINSYSFS); | PSEUDOFS(linsysfs, 1, PR_ALLOW_MOUNT_LINSYSFS); | ||||
#if defined(__amd64__) | #if defined(__amd64__) | ||||
MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1); | MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1); | ||||
Context not available. |