--- a/vmnet/Makefile +++ b/vmnet/Makefile @@ -43,7 +43,11 @@ endif +ifdef KVERSION +VM_UNAME = $(KVERSION) +else VM_UNAME = $(shell uname -r) +endif # Header directory for the running kernel ifdef LINUXINCLUDE @@ -98,6 +102,13 @@ auto-build: $(DRIVER_KO) $(DRIVER): $(DRIVER_KO) if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi +# Use SUBDIRS on 2.x, 3.x, 4.x. Use M on newer kernels. +ifeq ($(filter-out 2 3 4,$(firstword $(subst ., ,$(VM_UNAME)))),) +DIRVAR := SUBDIRS +else +DIRVAR := M +endif + # # Define a setup target that gets built before the actual driver. # This target may not be used at all, but if it is then it will be defined @@ -107,7 +118,7 @@ prebuild:: ; postbuild:: ; $(DRIVER_KO): prebuild - $(MAKE) -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) \ + $(MAKE) -C $(BUILD_DIR) $(DIRVAR)=$$PWD SRCROOT=$$PWD/$(SRCROOT) \ MODULEBUILDDIR=$(MODULEBUILDDIR) modules $(MAKE) -C $$PWD SRCROOT=$$PWD/$(SRCROOT) \ MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild --- a/vmnet/bridge.c +++ b/vmnet/bridge.c @@ -26,6 +26,9 @@ #include #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 10) +#include +#endif #include #include #include @@ -684,14 +684,11 @@ } spin_unlock_irqrestore(&bridge->historyLock, flags); - /* - * We used to cli() before calling netif_rx() here. It was probably - * unneeded (as we never did it in netif.c, and the code worked). In - * any case, now that we are using netif_rx_ni(), we should certainly - * not do it, or netif_rx_ni() will deadlock on the cli() lock --hpreg - */ - - netif_rx_ni(clone); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) + netif_rx_ni(clone); +#else + netif_rx(clone); +#endif # if LOGLEVEL >= 4 do_gettimeofday(&vnetTime); # endif --- a/vmnet/driver.c +++ b/vmnet/driver.c @@ -279,7 +279,7 @@ /* *---------------------------------------------------------------------- * - * init_module -- + * LinuxDriverInit -- * * linux module entry point. Called by /sbin/insmod command. * Initializes module and Registers this driver for a @@ -296,7 +296,7 @@ */ int -init_module(void) +LinuxDriverInit(void) { int retval; @@ -358,7 +358,7 @@ /* *---------------------------------------------------------------------- * - * cleanup_module -- + * LinuxDriverExit -- * * Called by /sbin/rmmod. Unregisters this driver for a * vnet major #, and deinitializes the modules. The 64-bit @@ -375,7 +375,7 @@ */ void -cleanup_module(void) +LinuxDriverExit(void) { unregister_chrdev(VNET_MAJOR_NUMBER, "vmnet"); VNetProtoUnregister(); @@ -1701,3 +1701,5 @@ * by default (i.e., neither mkinitrd nor modprobe will accept it). */ MODULE_INFO(supported, "external"); +module_init(LinuxDriverInit); +module_exit(LinuxDriverExit); --- a/vmnet/netif.c +++ b/vmnet/netif.c @@ -219,7 +219,11 @@ memset(&netIf->stats, 0, sizeof netIf->stats); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) memcpy(dev->dev_addr, netIf->port.paddr, sizeof netIf->port.paddr); +#else + eth_hw_addr_set(dev, netIf->port.paddr); +#endif if (register_netdev(dev) != 0) { LOG(0, (KERN_NOTICE "%s: could not register network device\n", @@ -311,7 +315,11 @@ /* send to the host interface */ skb->dev = netIf->dev; skb->protocol = eth_type_trans(skb, netIf->dev); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) netif_rx_ni(skb); +#else + netif_rx(skb); +#endif netIf->stats.rx_packets++; return; @@ -498,7 +506,11 @@ return -EINVAL; } memcpy(netIf->port.paddr, addr->sa_data, dev->addr_len); - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) + memcpy(dev->dev_addr, netIf->port.paddr, dev->addr_len); +#else + eth_hw_addr_set(dev, netIf->port.paddr); +#endif return 0; } --- a/vmnet/procfs.c +++ a/vmnet/procfs.c @@ -137,6 +137,7 @@ VNetProcShow(struct seq_file *p, // IN: } +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) /* *---------------------------------------------------------------------- * @@ -168,6 +169,7 @@ static struct file_operations fops = { .release = single_release, }; #endif +#endif /* @@ -203,7 +205,12 @@ VNetProcMakeEntryInt(VNetProcEntry *pa } else { ent->data = data; ent->fn = fn; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) + ent->pde = proc_create_single_data(name, mode, parent->pde, + VNetProcShow, ent); +#else ent->pde = proc_create_data(name, mode, parent->pde, &fops, ent); +#endif } if (ent->pde != NULL) { *ret = ent; --- a/vmnet/smac.c +++ b/vmnet/smac.c @@ -4118,7 +4118,7 @@ void SMACINT SMAC_SetMac(SMACState *state, // IN: state to update - uint8 *mac) // IN: pointer to host adapter's MAC + const uint8 *mac) // IN: pointer to host adapter's MAC { VNETKdPrintCall(("SMAC_SetMac")); ASSERT(state); --- a/vmnet/smac.h +++ b/vmnet/smac.h @@ -72,7 +72,7 @@ void SMACINT SMAC_InitState(struct SMACState **ptr); // IN: state to alloc/init void SMACINT -SMAC_SetMac(struct SMACState *state, uint8 *mac); // IN: state, and host MAC +SMAC_SetMac(struct SMACState *state, const uint8 *mac); // IN: state, and host MAC void SMACINT SMAC_CleanupState(struct SMACState **ptr); // IN: state to cleanup/dealloc --- a/vmnet/userif.c +++ b/vmnet/userif.c @@ -78,11 +78,11 @@ static int VNetUserIfSetUplinkState(VNe extern unsigned int vnet_max_qlen; #if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) -# define compat_kmap(page) kmap(page) -# define compat_kunmap(page) kunmap(page) -#else -# define compat_kmap(page) kmap((page).p) -# define compat_kunmap(page) kunmap((page).p) +# define skb_frag_page(frag) (frag)->page +# define skb_frag_size(frag) (frag)->size +#endif +#if COMPAT_LINUX_VERSION_CHECK_LT(5, 4, 0) +# define skb_frag_off(frag) (frag)->page_offset #endif /* @@ -137,16 +137,21 @@ UserifLockPage(VA addr) // IN */ static INLINE int -VNetUserIfMapPtr(VA uAddr, // IN: pointer to user memory +VNetUserIfMapPtr(VA64 uAddr, // IN: pointer to user memory size_t size, // IN: size of data struct page **p, // OUT: locked page void **ptr) // OUT: kernel mapped pointer { - if (!access_ok(VERIFY_WRITE, (void *)uAddr, size) || - (((uAddr + size - 1) & ~(PAGE_SIZE - 1)) != - (uAddr & ~(PAGE_SIZE - 1)))) { + uint8 v; + + /* Check area does not straddle two pages. */ + if ((uAddr & (PAGE_SIZE - 1)) + size > PAGE_SIZE) { return -EINVAL; } + /* Check if it is user's area. UserifLockPage() checks writability. */ + if (copy_from_user(&v, (void *)(unsigned long)uAddr, sizeof v) != 0) { + return -EFAULT; + } *p = UserifLockPage(uAddr); if (*p == NULL) { @@ -158,7 +163,7 @@ VNetUserIfMapPtr(VA uAddr, // IN: } static INLINE int -VNetUserIfMapUint32Ptr(VA uAddr, // IN: pointer to user memory +VNetUserIfMapUint32Ptr(VA64 uAddr, // IN: pointer to user memory struct page **p, // OUT: locked page uint32 **ptr) // OUT: kernel mapped pointer { @@ -201,7 +206,7 @@ VNetUserIfSetupNotify(VNetUserIF *userIf return -EBUSY; } - if ((retval = VNetUserIfMapUint32Ptr((VA)vn->pollPtr, &pollPage, + if ((retval = VNetUserIfMapUint32Ptr(vn->pollPtr, &pollPage, &pollPtr)) < 0) { return retval; } @@ -213,7 +218,7 @@ VNetUserIfSetupNotify(VNetUserIF *userIf goto error_free; } - if ((retval = VNetUserIfMapUint32Ptr((VA)vn->recvClusterPtr, + if ((retval = VNetUserIfMapUint32Ptr(vn->recvClusterPtr, &recvClusterPage, &recvClusterCount)) < 0) { goto error_free; @@ -511,6 +516,50 @@ /* *---------------------------------------------------------------------- * + * VNetCsumAndCopyToUser -- + * + * Checksum data and copy them to userspace. + * + * Results: + * folded checksum (non-zero value) on success, + * err set to 0 on success, negative errno on failure. + * + * Side effects: + * Data copied to the buffer. + * + *---------------------------------------------------------------------- + */ + +static unsigned int +VNetCsumAndCopyToUser(const void *src, // IN: Source + void *dst, // IN: Destination + int len, // IN: Bytes to copy + int *err) // OUT: Error code +{ + unsigned int csum; + +#if COMPAT_LINUX_VERSION_CHECK_LT(5, 10, 0) + csum = csum_and_copy_to_user(src, dst, len, 0, err); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) + csum = csum_and_copy_to_user(src, dst, len); + *err = (csum == 0) ? -EFAULT : 0; +#else + if (!user_access_begin(dst, len)) { + *err = -EFAULT; + csum = 0; + } else { + *err = 0; + csum = csum_partial_copy_nocheck(src, dst, len); + user_access_end(); + } +#endif + return csum; +} + + +/* + *---------------------------------------------------------------------- + * * VNetCsumCopyDatagram -- * * Copy part of datagram to userspace doing checksum at same time. @@ -550,7 +555,7 @@ VNetCsumCopyDatagram(const struct sk_buf return -EINVAL; } - csum = csum_and_copy_to_user(skb->data + offset, curr, len, 0, &err); + csum = VNetCsumAndCopyToUser(skb->data + offset, curr, len, &err); if (err) { return err; } @@ -559,20 +569,20 @@ VNetCsumCopyDatagram(const struct sk_buf for (frag = skb_shinfo(skb)->frags; frag != skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags; frag++) { - if (frag->size > 0) { + if (skb_frag_size(frag) > 0) { unsigned int tmpCsum; const void *vaddr; - vaddr = compat_kmap(frag->page); - tmpCsum = csum_and_copy_to_user(vaddr + frag->page_offset, - curr, frag->size, 0, &err); - compat_kunmap(frag->page); + vaddr = kmap(skb_frag_page(frag)); + tmpCsum = VNetCsumAndCopyToUser(vaddr + skb_frag_off(frag), + curr, skb_frag_size(frag), &err); + kunmap(skb_frag_page(frag)); if (err) { return err; } csum = csum_block_add(csum, tmpCsum, curr - buf); - curr += frag->size; + curr += skb_frag_size(frag); } } Fixing VMWare Player on Linux when using DHCP addresses: https://www.nikhef.nl/~janjust/vmnet/ @@ -973,6 +989,9 @@ userIf = (VNetUserIF *)port->jack.private; hubJack = port->jack.peer; + /* never send link down events */ + if (!linkUp) return 0; + if (port->jack.state == FALSE || hubJack == NULL) { return -EINVAL; } --- a/vmnet/vnetEvent.c +++ b/vmnet/vnetEvent.c @@ -60,10 +60,12 @@ struct VNetEvent_EventNode { VNetEvent_EventNode *nextEvent; - VNet_EventHeader event; + union { + VNet_EventHeader header; + VNet_LinkStateEvent lse; + } event; }; -#define EVENT_NODE_HEADER_SIZE offsetof(struct VNetEvent_EventNode, event) struct VNetEvent_Mechanism { VNetKernel_SpinLock lock; /* mechanism lock */ @@ -369,6 +371,10 @@ return VNetKernel_EINVAL; } + if (e->size > sizeof(p->event)) { + return VNetKernel_EINVAL; + } + /* lock */ VNetKernel_SpinLockAcquire(&m->lock); m->handlerTask = VNetKernel_ThreadCurrent(); @@ -378,22 +384,15 @@ while (TRUE) { p = *q; if (p == NULL || - (p->event.eventId == e->eventId && p->event.type == e->type)) { + (p->event.header.eventId == e->eventId && p->event.header.type == e->type)) { break; } q = &p->nextEvent; } - /* remove previously sent event */ - if (p != NULL && p->event.size != e->size) { - *q = p->nextEvent; - VNetKernel_MemoryFree(p); - p = NULL; - } - /* insert new event into event list*/ if (p == NULL) { - p = VNetKernel_MemoryAllocate(EVENT_NODE_HEADER_SIZE + e->size); + p = VNetKernel_MemoryAllocate(sizeof(*p)); if (p == NULL) { m->handlerTask = NULL; VNetKernel_SpinLockRelease(&m->lock); @@ -485,8 +484,8 @@ while (s != NULL) { e = s->firstEvent; while (e != NULL) { - if ((e->event.classSet & classMask) != 0) { - h(data, &e->event); + if ((e->event.header.classSet & classMask) != 0) { + h(data, &e->event.header); } e = e->nextEvent; } --- a/vmnet/vnetUserListener.c --- b/vmnet/vnetUserListener.c @@ -42,10 +42,12 @@ struct VNetUserListener_EventNode { VNetUserListener_EventNode *nextEvent; - VNet_EventHeader event; + union { + VNet_EventHeader header; + VNet_LinkStateEvent lse; + } event; }; -#define EVENT_NODE_HEADER_SIZE offsetof(struct VNetUserListener_EventNode, event) typedef struct VNetUserListener { VNetPort port; /* base port/jack */ @@ -220,7 +222,7 @@ VNetUserListener_EventNode *t; /* allocate and initialize event node */ - t = kmalloc(EVENT_NODE_HEADER_SIZE + e->size, GFP_ATOMIC); + t = kmalloc(sizeof *t, GFP_ATOMIC); if (t == NULL) { LOG(0, (KERN_DEBUG "VNetUserListenerEventHandler, out of memory\n")); return; @@ -299,7 +301,7 @@ spin_unlock(&userListener->lock); /* return data and free event */ - n = t->event.size; + n = t->event.header.size; if (count < n) { n = count; } From add7a6d8b99565fdfa79098315b0a69fd244eda3 Mon Sep 17 00:00:00 2001 From: Michal Kubecek Date: Fri, 12 Jan 2024 08:30:33 +0100 Subject: [PATCH] modules: fix build with -Wmissing-prototypes Mainline commit 0fcb70851fbf ("Makefile.extrawarn: turn on missing-prototypes globally") in 6.8-rc1 enables -Wmissing-prototypes globally, revealing a lot of unclean code and also some actual problems. This is also the case in vmmon and vmnet modules. Most of them are addressed by making functions used only within one file static. A special case are Vmx86_MapPage() and Vmx86_UnmapPage() which were defined since Workstation 14.0.0 but they are not actually used anywhere until 15.0.0 so that dropping them seems to be the best option. The missing prototype of random_get_entropy_fallback() is handled by including rather than . Finally, there are four functions in vmnet module which are actually used in multiple files but instead of proper declarations, their prototype is duplicated in vmnet-only/driver.c, risking that the two copies won't match (which actually happened in one case). The cleanest solution would be creating separate header files for them (bridge.h, netif.h, userif.h and vnetUserListener.h) and including them in the respective source file and driver.c. As the developers already handle similar cases by simply putting the declarations into vnetInt.h, let us do the same to keep things simple. --- vmmon-only/bootstrap/monLoaderVmmon.c | 1 + vmmon-only/common/vmx86.c | 50 +-------------------------- vmmon-only/linux/driver.c | 4 +-- vmmon-only/linux/hostif.c | 6 ++-- vmnet-only/bridge.c | 2 +- vmnet-only/driver.c | 16 ++------- vmnet-only/vnetInt.h | 7 ++++ 7 files changed, 17 insertions(+), 69 deletions(-) diff --git a/vmnet-only/bridge.c b/vmnet-only/bridge.c index b144adab..b46df795 100644 --- a/vmnet-only/bridge.c +++ b/vmnet-only/bridge.c @@ -1405,7 +1405,7 @@ VNetBridgeComputeHeaderPos(struct sk_buff *skb) // IN: buffer to examine *---------------------------------------------------------------------- */ -void +static void VNetBridgeSendLargePacket(struct sk_buff *skb, // IN: packet to split VNetBridge *bridge) // IN: bridge { diff --git a/vmnet-only/driver.c b/vmnet-only/driver.c index 602bbfa1..a6f6a7d9 100644 --- a/vmnet-only/driver.c +++ b/vmnet-only/driver.c @@ -50,18 +50,6 @@ #include "vmnetInt.h" -/* - * Initialization and creation routines from other files. - * Putting them here reduces the need for so many header files. - */ - -extern int VNetUserIf_Create(VNetPort **ret); -extern int VNetNetIf_Create(char *devName, VNetPort **ret, int hubNum); -extern int VNetBridge_Create(char *devName, uint32 flags, VNetJack *hubJack, - VNetPort **ret); -extern int VNetUserListener_Create(uint32 classMask, VNetJack *hubJack, VNetPort **ret); - - /* * Structure for cycle detection of host interfaces. This * struct is only used by VNetCycleDetectIf(). @@ -295,7 +283,7 @@ VNetRemovePortFromList(const VNetPort *port) // IN: port to remove from list *---------------------------------------------------------------------- */ -int +static int LinuxDriverInit(void) { int retval; @@ -374,7 +362,7 @@ vmnet_init_module(void) *---------------------------------------------------------------------- */ -void +static void LinuxDriverExit(void) { unregister_chrdev(VNET_MAJOR_NUMBER, "vmnet"); diff --git a/vmnet-only/vnetInt.h b/vmnet-only/vnetInt.h index 5f41269d..cb25e3b8 100644 --- a/vmnet-only/vnetInt.h +++ b/vmnet-only/vnetInt.h @@ -225,6 +225,13 @@ extern int VNetProc_Init(void); extern void VNetProc_Cleanup(void); +int VNetNetIf_Create(char *devName, VNetPort **ret, int hubNum); +int VNetUserIf_Create(VNetPort **ret); +int VNetBridge_Create(const char *devName, uint32 flags, VNetJack *hubJack, + VNetPort **ret); +int VNetUserListener_Create(uint32 classMask, VNetJack *hubJack, + VNetPort **port); + /* *----------------------------------------------------------------------