diff --git a/README.txt b/README.txt index 59648d01f4c..5d3721f4c50 100644 --- a/README.txt +++ b/README.txt @@ -464,9 +464,9 @@ Notes about Header Files Certain header files, such as setjmp.h, stdarg.h, and math.h, may still be needed from your toolchain and your compiler may not, however, be able - to find these if you compile NuttX without using standard header file. - If that is the case, one solution is to copy those header file from - your toolchain into the NuttX include directory. + to find these if you compile NuttX without using standard header files + (ie., with -nostdinc). If that is the case, one solution is to copy + those header file from your toolchain into the NuttX include directory. Duplicated Header Files. diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig index ff7dfe80cfd..e727aef24aa 100644 --- a/arch/arm/src/stm32f7/Kconfig +++ b/arch/arm/src/stm32f7/Kconfig @@ -1823,7 +1823,7 @@ config STM32F7_HAVE_RTC_COUNTER config STM32F7_HAVE_RTC_SUBSECONDS bool - default n + default y config RTC_MAGIC_REG int "The BKP register used to store/check the Magic value to determine if RTC is set already" diff --git a/arch/arm/src/stm32f7/Make.defs b/arch/arm/src/stm32f7/Make.defs index 8baa4fbf135..06a190f463f 100644 --- a/arch/arm/src/stm32f7/Make.defs +++ b/arch/arm/src/stm32f7/Make.defs @@ -149,6 +149,10 @@ ifeq ($(filter y,$(CONFIG_STM32F7_IWDG) $(CONFIG_STM32F7_RTC_LSICLOCK)),y) CHIP_CSRCS += stm32_lsi.c endif +ifeq ($(CONFIG_STM32F7_RTC_LSECLOCK),y) +CHIP_CSRCS += stm32_lse.c +endif + ifeq ($(CONFIG_STM32F7_I2C),y) CHIP_CSRCS += stm32_i2c.c endif diff --git a/arch/arm/src/stm32f7/stm32_exti_pwr.c b/arch/arm/src/stm32f7/stm32_exti_pwr.c index 09d064e930e..3c4f2d07a3b 100644 --- a/arch/arm/src/stm32f7/stm32_exti_pwr.c +++ b/arch/arm/src/stm32f7/stm32_exti_pwr.c @@ -129,7 +129,7 @@ static int stm32_exti_pvd_isr(int irq, void *context, void *arg) ****************************************************************************/ int stm32_exti_pvd(bool risingedge, bool fallingedge, bool event, - xcpt_t func, void *arg); + xcpt_t func, void *arg) { /* Get the previous GPIO IRQ handler; Save the new IRQ handler. */ diff --git a/net/sixlowpan/sixlowpan_sniffer.c b/arch/arm/src/stm32f7/stm32_lse.c similarity index 69% rename from net/sixlowpan/sixlowpan_sniffer.c rename to arch/arm/src/stm32f7/stm32_lse.c index 32a2e3121e1..162630060b9 100644 --- a/net/sixlowpan/sixlowpan_sniffer.c +++ b/arch/arm/src/stm32f7/stm32_lse.c @@ -1,8 +1,9 @@ /**************************************************************************** - * net/sixlowpan/sixlowpan_sniffer.c + * arch/arm/src/stm32f7/stm32_lse.c * * Copyright (C) 2017 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Authors: Gregory Nutt + * David Sidrane * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,43 +40,47 @@ #include -#include "nuttx/net/net.h" -#include "nuttx/net/sixlowpan.h" +#include "up_arch.h" -#include "sixlowpan/sixlowpan_internal.h" - -#ifdef CONFIG_NET_6LOWPAN_SNIFFER +#include "stm32_rcc.h" +#include "stm32_pwr.h" /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Function: sixlowpan_set_sniffer + * Name: stm32_rcc_enablelse * * Description: - * Configure to use an architecture-specific sniffer to enable tracing of - * IP. - * - * Input parameters: - * sniffer - A reference to the new sniffer to be used. This may - * be a NULL value to disable the sniffer. - * - * Returned Value: - * None + * Enable the External Low-Speed (LSE) oscillator. * ****************************************************************************/ -void sixlowpan_set_sniffer(FAR struct sixlowpan_rime_sniffer_s *sniffer) +void stm32_rcc_enablelse(void) { - /* Make sure that the sniffer is not in use */ + uint32_t regval; - net_lock(); + /* The LSE is in the RTC domain and write access is denied to this domain + * after reset, you have to enable write access using DBP bit in the PWR CR + * register before to configuring the LSE. + */ - /* Then instantiate the new sniffer */ + stm32_pwr_enablebkp(true); - g_sixlowpan_sniffer = sniffer; - net_unlock(); + /* Enable the External Low-Speed (LSE) oscillator by setting the LSEON bit + * the RCC BDCR register. + */ + + regval = getreg32(STM32_RCC_BDCR); + regval |= RCC_BDCR_LSEON; + putreg32(regval,STM32_RCC_BDCR); + + /* Wait for the LSE clock to be ready */ + + while (((regval = getreg32(STM32_RCC_BDCR)) & RCC_BDCR_LSERDY) == 0); + + /* Disable backup domain access if it was disabled on entry */ + + stm32_pwr_enablebkp(false); } - -#endif /* CONFIG_NET_6LOWPAN_SNIFFER */ diff --git a/arch/arm/src/stm32f7/stm32_lsi.c b/arch/arm/src/stm32f7/stm32_lsi.c index 46e96163727..636662721b5 100644 --- a/arch/arm/src/stm32f7/stm32_lsi.c +++ b/arch/arm/src/stm32f7/stm32_lsi.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/stm32f/stm32_lsi.c + * arch/arm/src/stm32f7/stm32_lsi.c * * Copyright (C) 2012, 2015-2016 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt diff --git a/arch/arm/src/stm32f7/stm32_rtc.c b/arch/arm/src/stm32f7/stm32_rtc.c index 8a21ec41fea..2840fac8a5d 100644 --- a/arch/arm/src/stm32f7/stm32_rtc.c +++ b/arch/arm/src/stm32f7/stm32_rtc.c @@ -196,7 +196,7 @@ static void rtc_dumpregs(FAR const char *msg) rtcinfo(" TSDR: %08x\n", getreg32(STM32_RTC_TSDR)); rtcinfo(" TSSSR: %08x\n", getreg32(STM32_RTC_TSSSR)); rtcinfo(" CALR: %08x\n", getreg32(STM32_RTC_CALR)); - rtcinfo(" TAFCR: %08x\n", getreg32(STM32_RTC_TAFCR)); + rtcinfo(" TAMPCR: %08x\n", getreg32(STM32_RTC_TAMPCR)); rtcinfo("ALRMASSR: %08x\n", getreg32(STM32_RTC_ALRMASSR)); rtcinfo("ALRMBSSR: %08x\n", getreg32(STM32_RTC_ALRMBSSR)); rtcinfo("MAGICREG: %08x\n", getreg32(RTC_MAGIC_REG)); @@ -227,7 +227,8 @@ static void rtc_dumpregs(FAR const char *msg) ****************************************************************************/ #ifdef CONFIG_DEBUG_RTC_INFO -static void rtc_dumptime(FAR const struct tm *tp, FAR const char *msg) +static void rtc_dumptime(FAR const struct tm *tp, FAR const uint32_t *usecs, + FAR const char *msg) { rtcinfo("%s:\n", msg); rtcinfo(" tm_sec: %08x\n", tp->tm_sec); @@ -236,9 +237,14 @@ static void rtc_dumptime(FAR const struct tm *tp, FAR const char *msg) rtcinfo(" tm_mday: %08x\n", tp->tm_mday); rtcinfo(" tm_mon: %08x\n", tp->tm_mon); rtcinfo(" tm_year: %08x\n", tp->tm_year); + + if (usecs != NULL) + { + rtcinfo(" usecs: %08x\n", (unsigned int)*usecs); + } } #else -# define rtc_dumptime(tp, msg) +# define rtc_dumptime(tp, usecs, msg) #endif /**************************************************************************** @@ -1069,34 +1075,48 @@ int up_rtc_initialize(void) * ****************************************************************************/ -#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS +#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS int stm32_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec) #else int up_rtc_getdatetime(FAR struct tm *tp) #endif { -#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS - uint32_t ssr; -#endif uint32_t dr; uint32_t tr; uint32_t tmp; +#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS + uint32_t ssr; + uint32_t prediv_s; + uint32_t usecs; +#endif /* Sample the data time registers. There is a race condition here... If * we sample the time just before midnight on December 31, the date could - * be wrong because the day rolled over while were sampling. + * be wrong because the day rolled over while were sampling. Thus loop for + * checking overflow here is needed. There is a race condition with + * subseconds too. If we sample TR register just before second rolling + * and subseconds are read at wrong second, we get wrong time. */ do { dr = getreg32(STM32_RTC_DR); tr = getreg32(STM32_RTC_TR); -#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS +#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS ssr = getreg32(STM32_RTC_SSR); + tmp = getreg32(STM32_RTC_TR); + if (tmp != tr) + { + continue; + } #endif tmp = getreg32(STM32_RTC_DR); + if (tmp == dr) + { + break; + } } - while (tmp != dr); + while (1); rtc_dumpregs("Reading Time"); @@ -1141,31 +1161,31 @@ int up_rtc_getdatetime(FAR struct tm *tp) tp->tm_isdst = 0 #endif -#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS +#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS /* Return RTC sub-seconds if no configured and if a non-NULL value * of nsec has been provided to receive the sub-second value. */ - if (nsec) + prediv_s = getreg32(STM32_RTC_PRER) & RTC_PRER_PREDIV_S_MASK; + prediv_s >>= RTC_PRER_PREDIV_S_SHIFT; + + ssr &= RTC_SSR_MASK; + + /* Maximum prediv_s is 0x7fff, thus we can multiply by 100000 and + * still fit 32-bit unsigned integer. + */ + + usecs = (((prediv_s - ssr) * 100000) / (prediv_s + 1)) * 10; + if (nsec != NULL) { - uint32_t prediv_s; - uint32_t usecs; - - prediv_s = getreg32(STM32_RTC_PRER) & RTC_PRER_PREDIV_S_MASK; - prediv_s >>= RTC_PRER_PREDIV_S_SHIFT; - - ssr &= RTC_SSR_MASK; - - /* Maximum prediv_s is 0x7fff, thus we can multiply by 100000 and - * still fit 32-bit unsigned integer. - */ - - usecs = (((prediv_s - ssr) * 100000) / (prediv_s + 1)) * 10; *nsec = usecs * 1000; } -#endif /* CONFIG_STM32_HAVE_RTC_SUBSECONDS */ - rtc_dumptime((FAR const struct tm *)tp, "Returning"); + rtc_dumptime((FAR const struct tm *)tp, &usecs, "Returning"); +#else /* CONFIG_STM32_HAVE_RTC_SUBSECONDS */ + rtc_dumptime((FAR const struct tm *)tp, NULL, "Returning"); +#endif + return OK; } @@ -1192,7 +1212,7 @@ int up_rtc_getdatetime(FAR struct tm *tp) * ****************************************************************************/ -#ifdef CONFIG_STM32_HAVE_RTC_SUBSECONDS +#ifdef CONFIG_STM32F7_HAVE_RTC_SUBSECONDS int up_rtc_getdatetime(FAR struct tm *tp) { return stm32_rtc_getdatetime_with_subseconds(tp, NULL); @@ -1221,7 +1241,7 @@ int stm32_rtc_setdatetime(FAR const struct tm *tp) uint32_t dr; int ret; - rtc_dumptime(tp, "Setting time"); + rtc_dumptime(tp, NULL, "Setting time"); /* Then write the broken out values to the RTC */ @@ -1337,7 +1357,7 @@ int stm32_rtc_setalarm(FAR struct alm_setalarm_s *alminfo) /* REVISIT: Should test that the time is in the future */ - rtc_dumptime(&alminfo->as_time, "New alarm time"); + rtc_dumptime(&alminfo->as_time, NULL, "New alarm time"); /* Break out the values to the HW alarm register format. The values in * all STM32 fields match the fields of struct tm in this case. Notice diff --git a/arch/arm/src/stm32f7/stm32_sdmmc.c b/arch/arm/src/stm32f7/stm32_sdmmc.c index 2249dc87c3b..9225312bd1b 100644 --- a/arch/arm/src/stm32f7/stm32_sdmmc.c +++ b/arch/arm/src/stm32f7/stm32_sdmmc.c @@ -1510,7 +1510,7 @@ static int stm32_sdmmc_rdyinterrupt(int irq, void *context, void *arg) * ****************************************************************************/ -static int stm32_sdmmc_interrupt(int irq, void *context, void *arg); +static int stm32_sdmmc_interrupt(int irq, void *context, void *arg) { struct stm32_dev_s *priv =(struct stm32_dev_s *)arg; uint32_t enabled; diff --git a/arch/arm/src/stm32f7/stm32_serial.c b/arch/arm/src/stm32f7/stm32_serial.c index 77138526dd6..b839aad8f44 100644 --- a/arch/arm/src/stm32f7/stm32_serial.c +++ b/arch/arm/src/stm32f7/stm32_serial.c @@ -1,8 +1,9 @@ /**************************************************************************** * arch/arm/src/stm32f7/stm32_serial.c * - * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2015-2017 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * David Sidrane * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -189,16 +190,6 @@ CONFIG_USART_DMAPRIO | \ DMA_SCR_PBURST_SINGLE | \ DMA_SCR_MBURST_SINGLE) -# ifdef CONFIG_SERIAL_IFLOWCONTROL -# define SERIAL_DMA_IFLOW_CONTROL_WORD \ - (DMA_SCR_DIR_P2M | \ - DMA_SCR_MINC | \ - DMA_SCR_PSIZE_8BITS | \ - DMA_SCR_MSIZE_8BITS | \ - CONFIG_USART_DMAPRIO | \ - DMA_SCR_PBURST_SINGLE | \ - DMA_SCR_MBURST_SINGLE) -# endif #endif /* SERIAL_HAVE_DMA */ /* Power management definitions */ @@ -286,8 +277,7 @@ struct up_dev_s #ifdef SERIAL_HAVE_DMA DMA_HANDLE rxdma; /* currently-open receive DMA stream */ bool rxenable; /* DMA-based reception en/disable */ - uint16_t rxdmain; /* Next byte in the DMA where hardware will write */ - uint16_t rxdmaout; /* Next byte in the DMA buffer to be read */ + uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */ char *const rxfifo; /* Receive DMA buffer */ #endif @@ -1139,7 +1129,22 @@ static void up_set_format(struct uart_dev_s *dev) uint32_t regval; uint32_t usartdiv8; uint32_t cr1; + uint32_t cr1_ue; uint32_t brr; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Get the original state of UE */ + + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + cr1_ue = cr1 & USART_CR1_UE; + cr1 &= ~USART_CR1_UE; + + /* Disable UE as the format bits and baud rate registers can not be + * updated while UE = 1 */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1); /* In case of oversampling by 8, the equation is: * @@ -1159,7 +1164,6 @@ static void up_set_format(struct uart_dev_s *dev) /* Use oversamply by 8 only if the divisor is small. But what is small? */ - cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); if (usartdiv8 > 100) { /* Use usartdiv16 */ @@ -1188,30 +1192,44 @@ static void up_set_format(struct uart_dev_s *dev) /* Configure parity mode */ - regval = up_serialin(priv, STM32_USART_CR1_OFFSET); - regval &= ~(USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0); + cr1 &= ~(USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0 | USART_CR1_M1); if (priv->parity == 1) /* Odd parity */ { - regval |= (USART_CR1_PCE | USART_CR1_PS); + cr1 |= (USART_CR1_PCE | USART_CR1_PS); } else if (priv->parity == 2) /* Even parity */ { - regval |= USART_CR1_PCE; + cr1 |= USART_CR1_PCE; } - /* Configure word length (Default: 8-bits) */ + /* Configure word length (parity uses one of configured bits) + * + * Default: 1 start, 8 data (no parity), n stop, OR + * 1 start, 7 data + parity, n stop + */ - if (priv->bits == 7) + if (priv->bits == 9 || (priv->bits == 8 && priv->parity != 0)) { - regval |= USART_CR1_M1; + /* Select: 1 start, 8 data + parity, n stop, OR + * 1 start, 9 data (no parity), n stop. + */ + + cr1 |= USART_CR1_M0; } - else if (priv->bits == 9) + else if (priv->bits == 7 && priv->parity == 0) { - regval |= USART_CR1_M0; + /* Select: 1 start, 7 data (no parity), n stop, OR + */ + + cr1 |= USART_CR1_M1; } - up_serialout(priv, STM32_USART_CR1_OFFSET, regval); + /* Else Select: 1 start, 7 data + parity, n stop, OR + * 1 start, 8 data (no parity), n stop. + */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1); /* Configure STOP bits */ @@ -1230,7 +1248,8 @@ static void up_set_format(struct uart_dev_s *dev) regval = up_serialin(priv, STM32_USART_CR3_OFFSET); regval &= ~(USART_CR3_CTSE | USART_CR3_RTSE); -#if defined(CONFIG_SERIAL_IFLOWCONTROL) && !defined(CONFIG_STM32F7_FLOWCONTROL_BROKEN) +#if defined(CONFIG_SERIAL_IFLOWCONTROL) && \ + !defined(CONFIG_STM32F7_FLOWCONTROL_BROKEN) if (priv->iflow && (priv->rts_gpio != 0)) { regval |= USART_CR3_RTSE; @@ -1245,6 +1264,8 @@ static void up_set_format(struct uart_dev_s *dev) #endif up_serialout(priv, STM32_USART_CR3_OFFSET, regval); + up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue); + leave_critical_section(flags); } #endif /* CONFIG_SUPPRESS_UART_CONFIG */ @@ -1473,35 +1494,19 @@ static int up_dma_setup(struct uart_dev_s *dev) priv->rxdma = stm32_dmachannel(priv->rxdma_channel); -#ifdef CONFIG_SERIAL_IFLOWCONTROL - if (priv->iflow) - { - /* Configure for non-circular DMA reception into the RX FIFO */ + /* Configure for circular DMA reception into the RX FIFO */ - stm32_dmasetup(priv->rxdma, - priv->usartbase + STM32_USART_RDR_OFFSET, - (uint32_t)priv->rxfifo, - RXDMA_BUFFER_SIZE, - SERIAL_DMA_IFLOW_CONTROL_WORD); - } - else -#endif - { - /* Configure for circular DMA reception into the RX FIFO */ - - stm32_dmasetup(priv->rxdma, - priv->usartbase + STM32_USART_RDR_OFFSET, - (uint32_t)priv->rxfifo, - RXDMA_BUFFER_SIZE, - SERIAL_DMA_CONTROL_WORD); - } + stm32_dmasetup(priv->rxdma, + priv->usartbase + STM32_USART_RDR_OFFSET, + (uint32_t)priv->rxfifo, + RXDMA_BUFFER_SIZE, + SERIAL_DMA_CONTROL_WORD); /* Reset our DMA shadow pointer to match the address just * programmed above. */ - priv->rxdmaout = 0; - priv->rxdmain = 0; + priv->rxdmanext = 0; /* Enable receive DMA for the UART */ @@ -1509,26 +1514,12 @@ static int up_dma_setup(struct uart_dev_s *dev) regval |= USART_CR3_DMAR; up_serialout(priv, STM32_USART_CR3_OFFSET, regval); -#ifdef CONFIG_SERIAL_IFLOWCONTROL - if (priv->iflow) - { - /* Start the DMA channel, and arrange for callbacks at the full point - * in the FIFO. After buffer gets full, hardware flow-control kicks - * in and DMA transfer is stopped. - */ + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ - stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, false); - } - else -#endif - { - /* Start the DMA channel, and arrange for callbacks at the half and - * full points in the FIFO. This ensures that we have half a FIFO - * worth of time to claim bytes before they are overwritten. - */ - - stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, true); - } + stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, true); return OK; } @@ -2226,49 +2217,27 @@ static bool up_rxflowcontrol(struct uart_dev_s *dev, static int up_dma_receive(struct uart_dev_s *dev, unsigned int *status) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; - uint32_t rxdmain; int c = 0; /* If additional bytes have been added to the DMA buffer, then we will need * to invalidate the DMA buffer before reading the byte. */ - rxdmain = up_dma_nextrx(priv); - if (rxdmain != priv->rxdmain) + if (up_dma_nextrx(priv) != priv->rxdmanext) { /* Invalidate the DMA buffer */ arch_invalidate_dcache((uintptr_t)priv->rxfifo, (uintptr_t)priv->rxfifo + RXDMA_BUFFER_SIZE - 1); - /* Since DMA is ongoing, there are lots of race conditions here. We - * just have to hope that the rxdmaout stays well ahead of rxdmain. - */ + /* Now read from the DMA buffer */ - priv->rxdmain = rxdmain; - } + c = priv->rxfifo[priv->rxdmanext]; - /* Now check if there are any bytes to read from the DMA buffer */ - - if (rxdmain != priv->rxdmaout) - { - c = priv->rxfifo[priv->rxdmaout]; - - priv->rxdmaout++; - if (priv->rxdmaout == RXDMA_BUFFER_SIZE) + priv->rxdmanext++; + if (priv->rxdmanext == RXDMA_BUFFER_SIZE) { -#ifdef CONFIG_SERIAL_IFLOWCONTROL - if (priv->iflow) - { - /* RX DMA buffer full. RX paused, RTS line pulled up to prevent - * more input data from other end. - */ - } - else -#endif - { - priv->rxdmaout = 0; - } + priv->rxdmanext = 0; } } @@ -2276,41 +2245,6 @@ static int up_dma_receive(struct uart_dev_s *dev, unsigned int *status) } #endif -/**************************************************************************** - * Name: up_dma_reenable - * - * Description: - * Call to re-enable RX DMA. - * - ****************************************************************************/ - -#if defined(SERIAL_HAVE_DMA) && defined(CONFIG_SERIAL_IFLOWCONTROL) -static void up_dma_reenable(struct up_dev_s *priv) -{ - /* Configure for non-circular DMA reception into the RX FIFO */ - - stm32_dmasetup(priv->rxdma, - priv->usartbase + STM32_USART_RDR_OFFSET, - (uint32_t)priv->rxfifo, - RXDMA_BUFFER_SIZE, - SERIAL_DMA_IFLOW_CONTROL_WORD); - - /* Reset our DMA shadow pointer to match the address just programmed - * above. - */ - - priv->rxdmaout = 0; - priv->rxdmain = 0; - - /* Start the DMA channel, and arrange for callbacks at the full point in - * the FIFO. After buffer gets full, hardware flow-control kicks in and - * DMA transfer is stopped. - */ - - stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, false); -} -#endif - /**************************************************************************** * Name: up_dma_rxint * @@ -2333,15 +2267,6 @@ static void up_dma_rxint(struct uart_dev_s *dev, bool enable) */ priv->rxenable = enable; - -#ifdef CONFIG_SERIAL_IFLOWCONTROL - if (priv->iflow && priv->rxenable && (priv->rxdmaout == RXDMA_BUFFER_SIZE)) - { - /* Re-enable RX DMA. */ - - up_dma_reenable(priv); - } -#endif } #endif @@ -2362,7 +2287,7 @@ static bool up_dma_rxavailable(struct uart_dev_s *dev) * do not match, then there are bytes to be received. */ - return (up_dma_nextrx(priv) != priv->rxdmaout); + return (up_dma_nextrx(priv) != priv->rxdmanext); } #endif @@ -2486,16 +2411,6 @@ static void up_dma_rxcallback(DMA_HANDLE handle, uint8_t status, void *arg) if (priv->rxenable && up_dma_rxavailable(&priv->dev)) { uart_recvchars(&priv->dev); - -#ifdef CONFIG_SERIAL_IFLOWCONTROL - if (priv->iflow && priv->rxenable && - (priv->rxdmaout == RXDMA_BUFFER_SIZE)) - { - /* Re-enable RX DMA. */ - - up_dma_reenable(priv); - } -#endif } } #endif diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c index b33c46e6e09..d354ab8130b 100644 --- a/drivers/net/skeleton.c +++ b/drivers/net/skeleton.c @@ -437,8 +437,8 @@ static void skel_receive(FAR struct skel_driver_s *priv) skel_transmit(priv); } } -#endif else +#endif { NETDEV_RXDROPPED(&priv->sk_dev); } diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index e62cfc908ff..5c51e2e328c 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -374,19 +374,19 @@ #define _LOOPIOCVALID(c) (_IOC_TYPE(c)==_LOOPBASE) #define _LOOPIOC(nr) _IOC(_LOOPBASE,nr) -/* Modem driver ioctl definitions ********************************************/ +/* Modem driver ioctl definitions *******************************************/ /* see nuttx/include/modem/ioctl.h */ #define _MODEMIOCVALID(c) (_IOC_TYPE(c)==_MODEMBASE) #define _MODEMIOC(nr) _IOC(_MODEMBASE,nr) -/* I2C driver ioctl definitions **********************************************/ +/* I2C driver ioctl definitions *********************************************/ /* see nuttx/include/i2c/i2c_master.h */ #define _I2CIOCVALID(c) (_IOC_TYPE(c)==_I2CBASE) #define _I2CIOC(nr) _IOC(_I2CBASE,nr) -/* SPI driver ioctl definitions **********************************************/ +/* SPI driver ioctl definitions *********************************************/ /* see nuttx/include/spi/spi_transfer.h */ #define _SPIIOCVALID(c) (_IOC_TYPE(c)==_SPIBASE) diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 337e0a63665..d99c2f584a6 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -79,7 +79,7 @@ enum net_lltype_e NET_LL_SLIP, /* Serial Line Internet Protocol (SLIP) */ NET_LL_TUN, /* TUN Virtual Network Device */ NET_LL_IEEE80211, /* IEEE 802.11 */ - NET_LL_IEEE805154 /* IEEE 802.15.4 MAC */ + NET_LL_IEEE802154 /* IEEE 802.15.4 MAC */ }; /* This defines a bitmap big enough for one bit for each socket option */ diff --git a/include/nuttx/net/netconfig.h b/include/nuttx/net/netconfig.h index 34561329013..0e912a53523 100644 --- a/include/nuttx/net/netconfig.h +++ b/include/nuttx/net/netconfig.h @@ -97,7 +97,7 @@ * * - Maximum Transfer Unit (MTU) * - TCP Receive Window size (See TCP configuration options below) - * + * * A better solution would be to support device-by-device MTU and receive * window sizes. This minimum support is require to support the optimal * SLIP MTU of 296 bytes and the standard Ethernet MTU of 1500 @@ -226,6 +226,12 @@ # define MIN_NET_DEV_MTU CONFIG_NET_6LOWPAN_MTU # define MAX_NET_DEV_MTU CONFIG_NET_6LOWPAN_MTU +/* For the IEEE802.15.4 MAC device, we will use the packet MTU + * (which is probably much larger than the IEEE802.15.4 fram size) + */ + +# define NET_LO_MTU MAX_NET_DEV_MTU + #else /* Perhaps only Unix domain sockets or the loopback device */ @@ -289,47 +295,113 @@ #endif /* The UDP maximum packet size. This is should not be to set to more - * than NET_DEV_MTU(d) - NET_LL_HDRLEN(dev) - IPv4UDP_HDRLEN. + * than NET_DEV_MTU(d) - NET_LL_HDRLEN(dev) - IPv*_HDRLEN. + * + * REVISIT: It is unclear to me if the UDP_HDRLEN should subtracted + * or not. */ -#define UDP_MSS(d,h) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) - (h)) - -/* If Ethernet is supported, then it will have the smaller MSS */ - -#if defined(CONFIG_NET_SLIP) -# define SLIP_UDP_MSS(h) (CONFIG_NET_SLIP_MTU - (h)) -# define __MIN_UDP_MSS(h) SLIP_UDP_MSS(h) -#elif defined(CONFIG_NET_LOOPBACK) -# define LO_UDP_MSS(h) (NET_LO_MTU - (h)) -# define __MIN_UDP_MSS(h) LO_UDP_MSS(h) -#endif +#define UDP_MSS(d,h) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) (h)) #ifdef CONFIG_NET_ETHERNET -# define ETH_UDP_MSS(h) (CONFIG_NET_ETH_MTU - ETH_HDRLEN - (h)) -# undef __MIN_UDP_MSS -# define __MIN_UDP_MSS(h) ETH_UDP_MSS(h) -# define __MAX_UDP_MSS(h) ETH_UDP_MSS(h) +# define ETH_UDP_MSS(h) (CONFIG_NET_ETH_MTU - ETH_HDRLEN - (h)) +# ifndef CONFIG_NET_MULTILINK +# define __MIN_UDP_MSS(h) ETH_UDP_MSS(h) +# define __MAX_UDP_MSS(h) ETH_UDP_MSS(h) +# endif #endif -/* If SLIP is supported, then it will have the larger MSS */ +#ifdef CONFIG_NET_6LOWPAN +# define IEEE802154_UDP_MSS(h) (CONFIG_NET_6LOWPAN_MAXPAYLOAD - (h)) +# ifndef CONFIG_NET_MULTILINK +# define __MIN_UDP_MSS(h) IEEE802154_UDP_MSS(h) +# define __MAX_UDP_MSS(h) IEEE802154_UDP_MSS(h) +# endif +#endif + +#ifdef CONFIG_NET_LOOPBACK +# define LO_UDP_MSS(h) (NET_LO_MTU - (h)) +# ifndef CONFIG_NET_MULTILINK +# define __MIN_UDP_MSS(h) LO_UDP_MSS(h) +# define __MAX_UDP_MSS(h) LO_UDP_MSS(h) +# endif +#endif #ifdef CONFIG_NET_SLIP -# undef __MAX_UDP_MSS -# define __MAX_UDP_MSS(h) SLIP_UDP_MSS(h) +# define SLIP_UDP_MSS(h) (CONFIG_NET_SLIP_MTU - (h)) +# ifndef CONFIG_NET_MULTILINK +# define __MIN_UDP_MSS(h) SLIP_UDP_MSS(h) +# define __MAX_UDP_MSS(h) SLIP_UDP_MSS(h) +# endif #endif -/* If IPv4 is supported, it will have the larger MSS */ +#ifdef CONFIG_NET_MULTILINK +# undef __LAST_MIN_UDP_MSS +# undef __LAST_MAX_UDP_MSS -#ifdef CONFIG_NET_IPv6 -# define UDP_IPv6_MSS(d) UDP_MSS(d,IPv6_HDRLEN) -# define ETH_IPv6_UDP_MSS ETH_UDP_MSS(IPv6_HDRLEN) -# define SLIP_IPv6_UDP_MSS SLIP_UDP_MSS(IPv6_HDRLEN) +# ifdef CONFIG_NET_ETHERNET +# ifdef __LAST_MIN_UDP_MSS +# define __MIN_UDP_MSS(h) MIN(ETH_UDP_MSS(h),__LAST_MIN_UDP_MSS(h)) +# define __MAX_UDP_MSS(h) MAX(ETH_UDP_MSS(h),__LAST_MAX_UDP_MSS(h)) +# else +# define __MIN_UDP_MSS(h) ETH_UDP_MSS(h) +# define __MAX_UDP_MSS(h) ETH_UDP_MSS(h) +# endif +# undef __LAST_MIN_UDP_MSS +# undef __LAST_MAX_UDP_MSS +# define __LAST_MIN_UDP_MSS(h) __MIN_UDP_MSS(h) +# define __LAST_MAX_UDP_MSS(h) __MAX_UDP_MSS(h) +# endif -# define MAX_IPv6_UDP_MSS __MAX_UDP_MSS(IPv6_HDRLEN) -# define MAX_UDP_MSS __MAX_UDP_MSS(IPv6_HDRLEN) +# ifdef CONFIG_NET_6LOWPAN +# ifdef __LAST_MIN_UDP_MSS +# define __MIN_UDP_MSS(h) MIN(IEEE802154_UDP_MSS(h),__LAST_MIN_UDP_MSS(h)) +# define __MAX_UDP_MSS(h) MAX(IEEE802154_UDP_MSS(h),__LAST_MAX_UDP_MSS(h)) +# else +# define __MIN_UDP_MSS(h) IEEE802154_UDP_MSS(h) +# define __MAX_UDP_MSS(h) IEEE802154_UDP_MSS(h) +# endif +# undef __LAST_MIN_UDP_MSS +# undef __LAST_MAX_UDP_MSS +# define __LAST_MIN_UDP_MSS(h) __MIN_UDP_MSS(h) +# define __LAST_MAX_UDP_MSS(h) __MAX_UDP_MSS(h) +# endif + +# ifdef CONFIG_NET_LOOPBACK +# ifdef __LAST_MIN_UDP_MSS +# define __MIN_UDP_MSS(h) MIN(LO_UDP_MSS(h),__LAST_MIN_UDP_MSS(h)) +# define __MAX_UDP_MSS(h) MAX(LO_UDP_MSS(h),__LAST_MAX_UDP_MSS(h)) +# else +# define __MIN_UDP_MSS(h) LO_UDP_MSS(h) +# define __MAX_UDP_MSS(h) LO_UDP_MSS(h) +# endif +# undef __LAST_MIN_UDP_MSS +# undef __LAST_MAX_UDP_MSS +# define __LAST_MIN_UDP_MSS(h) __MIN_UDP_MSS(h) +# define __LAST_MAX_UDP_MSS(h) __MAX_UDP_MSS(h) +# endif + +# ifdef CONFIG_NET_SLIP +# ifdef __LAST_MIN_UDP_MSS +# define __MIN_UDP_MSS(h) MIN(SLIP_UDP_MSS(h),__LAST_MIN_UDP_MSS(h)) +# define __MAX_UDP_MSS(h) MAX(SLIP_UDP_MSS(h),__LAST_MAX_UDP_MSS(h)) +# else +# define __MIN_UDP_MSS(h) SLIP_UDP_MSS(h) +# define __MAX_UDP_MSS(h) SLIP_UDP_MSS(h) +# endif +# undef __LAST_MIN_UDP_MSS +# undef __LAST_MAX_UDP_MSS +# define __LAST_MIN_UDP_MSS(h) __MIN_UDP_MSS(h) +# define __LAST_MAX_UDP_MSS(h) __MAX_UDP_MSS(h) +# endif + +# undef __LAST_MIN_UDP_MSS +# undef __LAST_MAX_UDP_MSS #endif -#ifdef CONFIG_NET_IPv4 +/* NOTE: MSS calcuation excludes the UDP_HDRLEN. */ + + #ifdef CONFIG_NET_IPv4 # define UDP_IPv4_MSS(d) UDP_MSS(d,IPv4_HDRLEN) # define ETH_IPv4_UDP_MSS ETH_UDP_MSS(IPv4_HDRLEN) # define SLIP_IPv4_UDP_MSS SLIP_UDP_MSS(IPv4_HDRLEN) @@ -416,36 +488,115 @@ * link layer protocols (CONFIG_NET_MULTILINK), each network device * may support a different UDP MSS value. Here we arbitrarily select * the minimum MSS for that case. + * + * REVISIT: It is unclear to me if the TCP_HDRLEN should subtracted + * or not. */ -#define TCP_MSS(d,h) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) - TCP_HDRLEN - (h)) -#define LO_TCP_MSS(h) (NET_LO_MTU - (h)) +#define TCP_MSS(d,h) (NET_DEV_MTU(d) - NET_LL_HDRLEN(d) - (h)) +#define LO_TCP_MSS(h) (NET_LO_MTU - (h)) -/* If Ethernet is supported, then it will have the smaller MSS */ - -#if defined(CONFIG_NET_SLIP) -# define SLIP_TCP_MSS(h) (CONFIG_NET_SLIP_MTU - (h)) -# define __MIN_TCP_MSS(h) SLIP_TCP_MSS(h) -#elif defined(CONFIG_NET_LOOPBACK) -# define LO_TCP_MSS(h) (NET_LO_MTU - (h)) -# define __MIN_TCP_MSS(h) LO_TCP_MSS(h) -#endif +/* Get the smallest and largest MSS */ #ifdef CONFIG_NET_ETHERNET -# define ETH_TCP_MSS(h) (CONFIG_NET_ETH_MTU - ETH_HDRLEN - (h)) -# undef __MIN_TCP_MSS -# define __MIN_TCP_MSS(h) ETH_TCP_MSS(h) -# define __MAX_TCP_MSS(h) ETH_TCP_MSS(h) +# define ETH_TCP_MSS(h) (CONFIG_NET_ETH_MTU - ETH_HDRLEN - (h)) +# ifndef CONFIG_NET_MULTILINK +# define __MIN_TCP_MSS(h) ETH_TCP_MSS(h) +# define __MAX_TCP_MSS(h) ETH_TCP_MSS(h) +# endif #endif -/* If SLIP is supported, then it will have the larger MSS */ +#ifdef CONFIG_NET_6LOWPAN +# define IEEE802154_TCP_MSS(h) CONFIG_NET_6LOWPAN_MAXPAYLOAD +# ifndef CONFIG_NET_MULTILINK +# define __MIN_TCP_MSS(h) IEEE802154_TCP_MSS(h) +# define __MAX_TCP_MSS(h) IEEE802154_TCP_MSS(h) +# endif +#endif + +#ifdef CONFIG_NET_LOOPBACK +# define LO_TCP_MSS(h) (NET_LO_MTU - (h)) +# ifndef CONFIG_NET_MULTILINK +# define __MIN_TCP_MSS(h) LO_TCP_MSS(h) +# define __MAX_TCP_MSS(h) LO_TCP_MSS(h) +# endif +#endif #ifdef CONFIG_NET_SLIP -# undef __MAX_TCP_MSS -# define __MAX_TCP_MSS(h) SLIP_TCP_MSS(h) +# define SLIP_TCP_MSS(h) (CONFIG_NET_SLIP_MTU - (h)) +# ifndef CONFIG_NET_MULTILINK +# define __MIN_TCP_MSS(h) SLIP_TCP_MSS(h) +# define __MAX_TCP_MSS(h) SLIP_TCP_MSS(h) +# endif #endif -/* If IPv4 is support, it will have the larger MSS */ +#ifdef CONFIG_NET_MULTILINK +# undef __LAST_MIN_TCP_MSS +# undef __LAST_MAX_TCP_MSS + +# ifdef CONFIG_NET_ETHERNET +# ifdef __LAST_MIN_TCP_MSS +# define __MIN_TCP_MSS(h) MIN(ETH_TCP_MSS(h),__LAST_MIN_TCP_MSS(h)) +# define __MAX_TCP_MSS(h) MAX(ETH_TCP_MSS(h),__LAST_MAX_TCP_MSS(h)) +# else +# define __MIN_TCP_MSS(h) ETH_TCP_MSS(h) +# define __MAX_TCP_MSS(h) ETH_TCP_MSS(h) +# endif +# undef __LAST_MIN_TCP_MSS +# undef __LAST_MAX_TCP_MSS +# define __LAST_MIN_TCP_MSS(h) __MIN_TCP_MSS(h) +# define __LAST_MAX_TCP_MSS(h) __MAX_TCP_MSS(h) +# endif + +# ifdef CONFIG_NET_6LOWPAN +# ifdef __LAST_MIN_TCP_MSS +# define __MIN_TCP_MSS(h) MIN(IEEE802154_TCP_MSS(h),__LAST_MIN_TCP_MSS(h)) +# define __MAX_TCP_MSS(h) MAX(IEEE802154_TCP_MSS(h),__LAST_MAX_TCP_MSS(h)) +# else +# define __MIN_TCP_MSS(h) IEEE802154_TCP_MSS(h) +# define __MAX_TCP_MSS(h) IEEE802154_TCP_MSS(h) +# endif +# undef __LAST_MIN_TCP_MSS +# undef __LAST_MAX_TCP_MSS +# define __LAST_MIN_TCP_MSS(h) __MIN_TCP_MSS(h) +# define __LAST_MAX_TCP_MSS(h) __MAX_TCP_MSS(h) +# endif + +# ifdef CONFIG_NET_LOOPBACK +# ifdef __LAST_MIN_TCP_MSS +# define __MIN_TCP_MSS(h) MIN(LO_TCP_MSS(h),__LAST_MIN_TCP_MSS(h)) +# define __MAX_TCP_MSS(h) MAX(LO_TCP_MSS(h),__LAST_MAX_TCP_MSS(h)) +# else +# define __MIN_TCP_MSS(h) LO_TCP_MSS(h) +# define __MAX_TCP_MSS(h) LO_TCP_MSS(h) +# endif +# undef __LAST_MIN_TCP_MSS +# undef __LAST_MAX_TCP_MSS +# define __LAST_MIN_TCP_MSS(h) __MIN_TCP_MSS(h) +# define __LAST_MAX_TCP_MSS(h) __MAX_TCP_MSS(h) +# endif + +# ifdef CONFIG_NET_SLIP +# ifdef __LAST_MIN_TCP_MSS +# define __MIN_TCP_MSS(h) MIN(SLIP_TCP_MSS(h),__LAST_MIN_TCP_MSS(h)) +# define __MAX_TCP_MSS(h) MAX(SLIP_TCP_MSS(h),__LAST_MAX_TCP_MSS(h)) +# else +# define __MIN_TCP_MSS(h) SLIP_TCP_MSS(h) +# define __MAX_TCP_MSS(h) SLIP_TCP_MSS(h) +# endif +# undef __LAST_MIN_TCP_MSS +# undef __LAST_MAX_TCP_MSS +# define __LAST_MIN_TCP_MSS(h) __MIN_TCP_MSS(h) +# define __LAST_MAX_TCP_MSS(h) __MAX_TCP_MSS(h) +# endif + +# undef __LAST_MIN_TCP_MSS +# undef __LAST_MAX_TCP_MSS +#endif + +/* If IPv4 is supported, it will have the larger MSS. + * NOTE: MSS calcuation excludes the TCP_HDRLEN. + */ #ifdef CONFIG_NET_IPv6 # define TCP_IPv6_MSS(d) TCP_MSS(d,IPv6_HDRLEN) @@ -547,6 +698,18 @@ # define CONFIG_NET_ARP_MAXAGE 120 #endif +/* Usrsock configuration options */ + +/* The maximum amount of concurrent usrsock connections, Default: 6 */ + +#ifndef CONFIG_NET_USRSOCK_CONNS +# ifdef CONFIG_NET_USRSOCK +# define CONFIG_NET_USRSOCK_CONNS 6 +# else +# define CONFIG_NET_USRSOCK_CONNS 0 +# endif +#endif + /* General configuration options */ /* Delay after receive to catch a following packet. No delay should be diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index 72bddc067cc..12b71840d72 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -419,7 +419,8 @@ int ipv6_input(FAR struct net_driver_s *dev); #endif #ifdef CONFIG_NET_6LOWPAN -int sixlowpan_input(FAR struct net_driver_s *dev); +struct ieee802154_driver_s; /* See sixlowpan.h */ +int sixlowpan_input(FAR struct ieee802154_driver_s *ieee); #endif /**************************************************************************** diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h index 7463763bff5..f31c453c439 100644 --- a/include/nuttx/net/sixlowpan.h +++ b/include/nuttx/net/sixlowpan.h @@ -53,6 +53,7 @@ #include +#include #include /**************************************************************************** @@ -98,7 +99,6 @@ #define SIXLOWPAN_IPHC_TTL_255 0x03 #define SIXLOWPAN_IPHC_TTL_I 0x00 - /* Values of fields within the IPHC encoding second byte */ #define SIXLOWPAN_IPHC_CID 0x80 @@ -232,62 +232,61 @@ #define SIXLOWPAN_MAC_STDFRAME 127 -/* Packet buffer Definitions */ +/* Frame buffer helper macros. + * + * The IEEE802.15.4 MAC driver structures includes a list of IOB + * structures, i_framelist, containing frames to be sent by the driver or + * that were received by the driver. The IOB structure is defined in + * include/nuttx/net/iob.h. The length of data in the IOB is provided by + * the io_len field of the IOB structure. + * + * NOTE that IOBs must be configured such that CONFIG_IOB_BUFSIZE >= + * CONFIG_NET_6LOWPAN_FRAMELEN + * + * 1. On a TX poll, the IEEE802.15.4 MAC driver should provide its driver + * structure with i_framelist set to NULL. At the conclusion of the + * poll, if there are frames to be sent, they will have been added to + * the i_framelist. The non-empty frame list is the indication that + * there is data to be sent. + * + * The IEEE802.15.4 may use the FRAME_IOB_EMPTY() macro to determine + * if there there frames to be sent. If so, it should remove each + * frame from the frame list using the FRAME_IOB_REMOVE() macro and send + * it. That macro will return NULL when all of the frames have been + * sent. + * + * After sending each frame, the driver must return the IOB to the pool + * of free IOBs using the FROM_IOB_FREE() macro. + */ -#define PACKETBUF_HDR_SIZE 48 -#define PACKETBUF_ATTR_PACKET_TYPE_DATA 0 -#define PACKETBUF_ATTR_PACKET_TYPE_ACK 1 -#define PACKETBUF_ATTR_PACKET_TYPE_STREAM 2 -#define PACKETBUF_ATTR_PACKET_TYPE_STREAM_END 3 -#define PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP 4 +#define FRAME_IOB_EMPTY(ieee) ((ieee)->i_framelist == NULL) +#define FRAME_IOB_REMOVE(ieee, iob) \ + do \ + { \ + (iob) = (ieee)->i_framelist; \ + (ieee)->i_framelist = (iob)->io_flink; \ + (iob)->io_flink = NULL; \ + } \ + while (0) +#define FRAME_IOB_FREE(iob) iob_free(iob) -/* Packet buffer attributes (indices into i_pktattr) */ +/* 2. When receiving data, the IEEE802.15.4 MAC driver should receive the + * frame data directly into the payload area of an IOB structure. That + * IOB structure may be obtained using the FRAME_IOB_ALLOC() macro. The + * single frame should be added to the frame list using FRAME_IOB_ADD() + * (it will be a list of length one) . The MAC driver should then inform + * the network of the by calling sixlowpan_input(). + */ -#define PACKETBUF_ATTR_NONE 0 - -/* Scope 0 attributes: used only on the local node. */ - -#define PACKETBUF_ATTR_CHANNEL 1 -#define PACKETBUF_ATTR_NETWORK_ID 2 -#define PACKETBUF_ATTR_LINK_QUALITY 3 -#define PACKETBUF_ATTR_RSSI 4 -#define PACKETBUF_ATTR_TIMESTAMP 5 -#define PACKETBUF_ATTR_RADIO_TXPOWER 6 -#define PACKETBUF_ATTR_LISTEN_TIME 7 -#define PACKETBUF_ATTR_TRANSMIT_TIME 8 -#define PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS 9 -#define PACKETBUF_ATTR_MAC_SEQNO 10 -#define PACKETBUF_ATTR_MAC_ACK 11 - -/* Scope 1 attributes: used between two neighbors only. */ - -#define PACKETBUF_ATTR_RELIABLE 12 -#define PACKETBUF_ATTR_PACKET_ID 13 -#define PACKETBUF_ATTR_PACKET_TYPE 14 -#define PACKETBUF_ATTR_REXMIT 15 -#define PACKETBUF_ATTR_MAX_REXMIT 16 -#define PACKETBUF_ATTR_NUM_REXMIT 17 -#define PACKETBUF_ATTR_PENDING 18 - -/* Scope 2 attributes: used between end-to-end nodes. */ - -#define PACKETBUF_ATTR_HOPS 11 -#define PACKETBUF_ATTR_TTL 20 -#define PACKETBUF_ATTR_EPACKET_ID 21 -#define PACKETBUF_ATTR_EPACKET_TYPE 22 -#define PACKETBUF_ATTR_ERELIABLE 23 - -#define PACKETBUF_NUM_ATTRS 24 - - /* Addresses (indices into i_pktaddr) */ - -#define PACKETBUF_ADDR_SENDER 0 -#define PACKETBUF_ADDR_RECEIVER 1 -#define PACKETBUF_ADDR_ESENDER 2 -#define PACKETBUF_ADDR_ERECEIVER 3 - -#define PACKETBUF_NUM_ADDRS 4 +#define FRAME_IOB_ALLOC() iob_alloc(false) +#define FRAME_IOB_ADD(ieee, iob) \ + do \ + { \ + (iob)->io_flink = (ieee)->i_framelist; \ + (ieee)->i_framelist = (iob); \ + } \ + while (0) /**************************************************************************** * Public Types @@ -305,18 +304,20 @@ struct rimeaddr_s * difference is that fragmentation must be supported. * * The IEEE802.15.4 MAC does not use the d_buf packet buffer directly. - * Rather, it uses a smaller frame buffer, i_frame. + * Rather, it uses a list smaller frame buffers, i_framelist. * - * - The packet fragment data is provided to the i_frame buffer each time - * that the IEEE802.15.4 MAC needs to send more data. The length of - * the frame is provided in i_frame. + * - The packet fragment data is provided to an IOB in the i_framelist + * buffer each time that the IEEE802.15.4 MAC needs to send more data. + * The length of the frame is provided in the io_len field of the IOB. * - * In this case, the d_buf holds the packet data yet to be sent; d_len - * holds the size of entire packet. + * In this case, the d_buf is not used at all and, if fact, may be + * NULL. * * - Received frames are provided by IEEE802.15.4 MAC to the network - * via i_frame with length i_framelen for reassembly in d_buf; d_len - * will hold the size of the reassembled packet. + * via and IOB in i_framelist with length io_len for reassembly in + * d_buf; d_len will hold the size of the reassembled packet. + * + * In this case, a d_buf of size CONFIG_NET_6LOWPAN_MTU must be provided. * * This is accomplished by "inheriting" the standard 'struct net_driver_s' * and appending the frame buffer as well as other metadata needed to @@ -328,36 +329,51 @@ struct rimeaddr_s * this structure. In general, all fields must be set to NULL. In * addtion: * - * 1) i_panid must be set to identify the network. It may be set to 0xfff + * 1. i_panid must be set to identify the network. It may be set to 0xfff * if the device is not associated. - * 2) i_dsn must be set to a random value. After that, it will be managed + * + * 2. i_dsn must be set to a random value. After that, it will be managed * by the network. - * 3) i_nodeaddr must be set after the MAC is assigned an address. - * 4) On network TX poll operations, the IEEE802.15.4 MAC needs to provide - * the i_frame buffer with size greater than or equal to - * CONFIG_NET_6LOWPAN_FRAMELEN. No dev.d_buf need be provided in this - * case. The entire is TX is performed using only the i_frame buffer. - * 5) On network input RX oprations, both buffers must be provided. The size - * of the i_frame buffer is, again, greater than or equal to - * CONFIG_NET_6LOWPAN_FRAMELEN. The larger dev.d_buf must have a size - * of at least the advertised MTU of the protocol, CONFIG_NET_6LOWPAN_MTU. - * If fragmentation is enabled, then the logical packet size may be - * significantly larger than the size of the frame buffer. The dev.d_buf - * is used for de-compressing each frame and reassembling any fragmented - * packets to create the full input packet that is provided to the - * application. * - * Frame Organization: + * 3. i_nodeaddr must be set after the MAC is assigned an address. * - * Content Offset - * +------------------+ 0 - * | Frame Header | - * +------------------+ i_dataoffset - * | Procotol Headers | - * | Data Payload | - * +------------------+ i_framelen - * | Unused | - * +------------------+ CONFIG_NET_6LOWPAN_FRAMELEN + * 4. On a TX poll, the IEEE802.15.4 MAC driver should provide its driver + * structure with i_framelist set to NULL. At the conclusion of the + * poll, if there are frames to be sent, they will have been added to + * the i_framelist. The non-empty frame list at the conclusion of the + * TX poll is the indication that is data to be sent. + * + * The IEEE802.15.4 may use the FRAME_IOB_EMPTY() macro to determine + * if there there frames to be sent. If so, it should remove each + * frame from the frame list using the FRAME_IOB_REMOVE() macro and send + * it. That macro will return NULL when all of the frames have been + * sent. + * + * After sending each frame, the driver must return the IOB to the pool + * of free IOBs using the FROM_IOB_FREE() macro. + * + * 5. When receiving data both buffers must be provided: + * + * The IEEE802.15.4 MAC driver should receive the frame data directly + * into the payload area of an IOB structure. That IOB structure may be + * obtained using the FRAME_IOB_ALLOC() macro. The single frame should + * be added to the frame list using FRAME_IOB_ADD() (it will be a list of + * length one). + * + * The larger dev.d_buf must have a size of at least the advertised MTU + * of the protocol, CONFIG_NET_6LOWPAN_MTU. If fragmentation is enabled, + * then the logical packet size may be significantly larger than the + * size of the frame buffer. The dev.d_buf is used for de-compressing + * each frame and reassembling any fragmented packets to create the full + * input packet that is provided to the application. + * + * The MAC driver should then inform the network of the by calling + * sixlowpan_input(). + * + * Normally, the network will free the IOB and will nullify the frame + * list. But ss a complexity, the result of receiving a frame may be + * that the network may respond provide an outgoing frames in the + * frame list. */ struct ieee802154_driver_s @@ -370,31 +386,21 @@ struct ieee802154_driver_s /* IEEE802.15.4 MAC-specific definitions follow. */ - /* The i_frame array is used to hold outgoing frame. When the - * IEEE802.15.4 device polls for new data, the outgoing frame containing - * the next fragment is placed in i_frame. + /* The i_framelist is used to hold a outgoing frames contained in IOB + * structures. When the IEEE802.15.4 device polls for new TX data, the + * outgoing frame(s) containing the packet fragments are placed in IOBs + * and queued in i_framelist. * - * The network will handle only a single outgong frame at a time. The - * IEEE802.15.4 MAC driver design may be concurrently sending and - * requesting new framesusing break-off fram buffers. That frame buffer - * management must be controlled by the IEEE802.15.4 MAC driver. + * The i_framelist is similary used to hold incoming frames in IOB + * structures. The IEEE802.15.4 MAC driver must receive frames in an IOB, + * place the IOB in the i_framelist, and call sixlowpan_input(). * - * Driver provided frame buffers should of size CONFIG_NET_6LOWPAN_FRAMELEN - * and should be 16-bit aligned. + * The IEEE802.15.4 MAC driver design may be concurrently sending and + * requesting new frames using lists of IOBs. That IOB frame buffer + * management must be managed by the IEEE802.15.4 MAC driver. */ - FAR uint8_t *i_frame; - - /* The length of valid data in the i_frame buffer. - * - * When the network device driver calls the network input function, - * i_framelen should be set to zero. If there is frame to be sent - * by the network, i_framelen will be set to indicate the size of - * frame to be sent. The value zero means that there is no frame - * to be sent. - */ - - uint16_t i_framelen; + FAR struct iob_s *i_framelist; /* i_panid. The PAN ID is 16-bit number that identifies the network. It * must be unique to differentiate a network. All the nodes in the same @@ -421,39 +427,12 @@ struct ieee802154_driver_s uint8_t i_dsn; - /* The following fields are device-specific metadata used by the 6loWPAN - * stack and should not be modified by the IEEE802.15.4 MAC network drvier. + /* i_dgramtag. Datagram tag to be put in the header of the set of + * fragments. It is used by the recipient to match fragments of the + * same payload. */ - /* A pointer to the rime buffer. - * - * We initialize it to the beginning of the rime buffer, then access - * different fields by updating the offset ieee->i_rime_hdrlen. - */ - - FAR uint8_t *i_rimeptr; - - /* i_uncomp_hdrlen is the length of the headers before compression (if HC2 - * is used this includes the UDP header in addition to the IP header). - */ - - uint8_t i_uncomp_hdrlen; - - /* i_rime_hdrlen is the total length of (the processed) 6lowpan headers - * (fragment headers, IPV6 or HC1, HC2, and HC1 and HC2 non compressed - * fields). - */ - - uint8_t i_rime_hdrlen; - - /* Offset first available byte for the payload after header region. */ - - uint8_t i_dataoffset; - - /* Packet buffer metadata: Attributes and addresses */ - - uint16_t i_pktattrs[PACKETBUF_NUM_ATTRS]; - struct rimeaddr_s i_pktaddrs[PACKETBUF_NUM_ADDRS]; + uint16_t i_dgramtag; }; /* The structure of a next header compressor. This compressor is provided @@ -480,18 +459,65 @@ struct sixlowpan_nhcompressor_s FAR uint8_t *uncompressed_len); }; -/* RIME sniffer callbacks */ - -struct sixlowpan_rime_sniffer_s -{ - CODE void (*input)(void); - CODE void (*output)(int mac_status); -}; - /**************************************************************************** * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: sixlowpan_input + * + * Description: + * Process an incoming 6loWPAN frame. + * + * This function is called when the device driver has received a 6loWPAN + * frame from the network. The frame from the device driver must be + * provided in a IOB present in the i_framelist: The frame data is in the + * IOB io_data[] buffer and the length of the frame is in the IOB io_len + * field. Only a single IOB is expected in the i_framelist. This incoming + * data will be processed one frame at a time. + * + * An non-NULL d_buf of size CONFIG_NET_6LOWPAN_MTU must also be provided. + * The frame will be decompressed and placed in the d_buf. Fragmented + * packets will also be reassembled in the d_buf as they are received + * (meaning for the driver, that two packet buffers are required: One for + * reassembly of RX packets and one used for TX polling). + * + * After each frame is processed into d_buf, the IOB is removed and + * deallocated. i_framelist will be nullified. If reassembly is + * incomplete, this function will return to called with i_framelist + * equal to NULL. The partially reassembled packet must be preserved by + * the IEEE802.15.4 MAC and provided again when the next frame is + * received. + * + * When the packet in the d_buf is fully reassembled, it will be provided + * to the network as with any other received packet. d_len will be set + * the the length of the uncompressed, reassembled packet. + * + * After the network processes the packet, d_len will be set to zero. + * Network logic may also decide to send a response to the packet. In + * that case, the outgoing network packet will be placed in d_buf the + * d_buf and d_len will be set to a non-zero value. That case is handled + * by this function. + * + * If that case occurs, the packet will be converted to a list of + * compressed and possibly fragmented frames in i_framelist as with other + * TX operations. + * + * So from the standpoint of the IEEE802.15.4 MAC driver, there are two + * possible results: (1) i_framelist is NULL meaning that the frame + * was fully processed and freed, or (2) i_framelist is non-NULL meaning + * that there are outgoing frame(s) to be sent. + * + * Input Parameters: + * ieee - The IEEE802.15.4 MAC network driver interface. + * + * Returned Value: + * Ok is returned on success; Othewise a negated errno value is returned. + * + ****************************************************************************/ + +int sixlowpan_input(FAR struct ieee802154_driver_s *ieee); + /**************************************************************************** * Function: sixlowpan_set_compressor * @@ -509,24 +535,4 @@ struct sixlowpan_rime_sniffer_s void sixlowpan_set_compressor(FAR struct sixlowpan_nhcompressor_s *compressor); -/**************************************************************************** - * Function: sixlowpan_set_sniffer - * - * Description: - * Configure to use an architecture-specific sniffer to enable tracing of - * IP. - * - * Input parameters: - * sniffer - A reference to the new sniffer to be used. This may - * be a NULL value to disable the sniffer. - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_NET_6LOWPAN_SNIFFER -void sixlowpan_set_sniffer(FAR struct sixlowpan_rime_sniffer_s *sniffer); -#endif - #endif /* __INCLUDE_NUTTX_NET_SIXLOWOAN_H */ diff --git a/include/nuttx/net/usrsock.h b/include/nuttx/net/usrsock.h new file mode 100644 index 00000000000..3ca990d44e3 --- /dev/null +++ b/include/nuttx/net/usrsock.h @@ -0,0 +1,233 @@ +/**************************************************************************** + * include/nuttx/net/usrsock.h + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_NET_USRSOCK_H +#define __INCLUDE_NUTTX_NET_USRSOCK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Event message flags */ + +#define USRSOCK_EVENT_ABORT (1 << 0) +#define USRSOCK_EVENT_SENDTO_READY (1 << 1) +#define USRSOCK_EVENT_RECVFROM_AVAIL (1 << 2) +#define USRSOCK_EVENT_REMOTE_CLOSED (1 << 3) + +/* Response message flags */ + +#define USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS (1 << 0) +#define USRSOCK_MESSAGE_FLAG_EVENT (1 << 1) + +#define USRSOCK_MESSAGE_IS_EVENT(flags) \ + (!!((flags) & USRSOCK_MESSAGE_FLAG_EVENT)) +#define USRSOCK_MESSAGE_IS_REQ_RESPONSE(flags) \ + (!USRSOCK_MESSAGE_IS_EVENT(flags)) + +#define USRSOCK_MESSAGE_REQ_IN_PROGRESS(flags) \ + (!!((flags) & USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS)) +#define USRSOCK_MESSAGE_REQ_COMPLETED(flags) \ + (!USRSOCK_MESSAGE_REQ_IN_PROGRESS(flags)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Request types */ + +enum usrsock_request_types_e +{ + USRSOCK_REQUEST_SOCKET = 0, + USRSOCK_REQUEST_CLOSE, + USRSOCK_REQUEST_CONNECT, + USRSOCK_REQUEST_SENDTO, + USRSOCK_REQUEST_RECVFROM, + USRSOCK_REQUEST_SETSOCKOPT, + USRSOCK_REQUEST_GETSOCKOPT, + USRSOCK_REQUEST_GETSOCKNAME, + USRSOCK_REQUEST_BIND, + USRSOCK_REQUEST__MAX +}; + +/* Response/event message types */ + +enum usrsock_message_types_e +{ + USRSOCK_MESSAGE_RESPONSE_ACK = 0, + USRSOCK_MESSAGE_RESPONSE_DATA_ACK, + USRSOCK_MESSAGE_SOCKET_EVENT, +}; + +/* Request structures (kernel => /dev/usrsock => daemon) */ + +begin_packed_struct struct usrsock_request_common_s +{ + int8_t reqid; + uint8_t xid; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_socket_s +{ + struct usrsock_request_common_s head; + + int16_t domain; + int16_t type; + int16_t protocol; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_close_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_bind_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + uint16_t addrlen; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_connect_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + uint16_t addrlen; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_sendto_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + uint16_t addrlen; + uint16_t buflen; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_recvfrom_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + uint16_t max_buflen; + uint16_t max_addrlen; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_setsockopt_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + int16_t level; + int16_t option; + uint16_t valuelen; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_getsockopt_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + int16_t level; + int16_t option; + uint16_t max_valuelen; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_getsockname_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + uint16_t max_addrlen; +} end_packed_struct; + +/* Response/event message structures (kernel <= /dev/usrsock <= daemon) */ + +begin_packed_struct struct usrsock_message_common_s +{ + int8_t msgid; + int8_t flags; +} end_packed_struct; + +/* Request acknowledgment/completion message */ + +begin_packed_struct struct usrsock_message_req_ack_s +{ + struct usrsock_message_common_s head; + + uint8_t xid; + int32_t result; +} end_packed_struct; + +/* Request acknowledgment/completion message */ + +begin_packed_struct struct usrsock_message_datareq_ack_s +{ + struct usrsock_message_req_ack_s reqack; + + /* head.result => positive buflen, negative error-code. */ + + uint16_t valuelen; /* length of value returned after buffer */ + uint16_t valuelen_nontrunc; /* actual non-truncated length of value at + * daemon-sïde. */ +} end_packed_struct; + +/* Socket event message */ + +begin_packed_struct struct usrsock_message_socket_event_s +{ + struct usrsock_message_common_s head; + + int16_t usockid; + uint16_t events; +} end_packed_struct; + +#endif /* __INCLUDE_NUTTX_NET_USRSOCK_H */ diff --git a/net/Kconfig b/net/Kconfig index 2741c678169..21ef8b3e7a5 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -123,28 +123,37 @@ config NET_USER_DEVFMT config NET_ETHERNET bool "Ethernet support" - default y if !NET_SLIP - default n if NET_SLIP - select NETDEV_MULTINIC if NET_LOOPBACK || NET_SLIP || NET_TUN - select NET_MULTILINK if NET_LOOPBACK || NET_SLIP || NET_TUN + default y + select NETDEV_MULTINIC if NET_6LOWPAN || NET_LOOPBACK || NET_SLIP || NET_TUN + select NET_MULTILINK if NET_6LOWPAN || NET_LOOPBACK || NET_SLIP || NET_TUN ---help--- If NET_SLIP is not selected, then Ethernet will be used (there is no need to define anything special in the configuration file to use Ethernet -- it is the default). +menuconfig NET_6LOWPAN + bool "IEEE 802.15.4 6LoWPAN support" + default n + select NETDEV_MULTINIC if NET_ETHERNET || NET_LOOPBACK || NET_SLIP || NET_TUN + select NET_MULTILINK if NET_ETHERNET || NET_LOOPBACK || NET_SLIP || NET_TUN + depends on EXPERIMENTAL && NET_IPv6 + ---help--- + Enable support for IEEE 802.15.4 Low power Wireless Personal Area + Networking (6LoWPAN). + config NET_LOOPBACK bool "Local loopback" default n - select NETDEV_MULTINIC if NET_ETHERNET || NET_SLIP || NET_TUN - select NET_MULTILINK if NET_ETHERNET || NET_SLIP || NET_TUN + select NETDEV_MULTINIC if NET_ETHERNET || NET_6LOWPAN || NET_SLIP || NET_TUN + select NET_MULTILINK if NET_ETHERNET || NET_6LOWPAN || NET_SLIP || NET_TUN ---help--- Add support for the local network loopback device, lo. config NET_SLIP bool "SLIP support" default n - select NETDEV_MULTINIC if NET_ETHERNET || NET_LOOPBACK || NET_TUN - select NET_MULTILINK if NET_ETHERNET || NET_LOOPBACK || NET_TUN + select NETDEV_MULTINIC if NET_ETHERNET || NET_6LOWPAN || NET_LOOPBACK || NET_TUN + select NET_MULTILINK if NET_ETHERNET || NET_6LOWPAN || NET_LOOPBACK || NET_TUN ---help--- Enables building of the SLIP driver. SLIP requires at least one IP protocol selected. @@ -190,8 +199,8 @@ endif # NET_SLIP config NET_TUN bool "TUN Virtual Network Device support" default n - select NETDEV_MULTINIC if NET_ETHERNET || NET_LOOPBACK || NET_SLIP - select NET_MULTILINK if NET_ETHERNET || NET_LOOPBACK || NET_SLIP + select NETDEV_MULTINIC if NET_ETHERNET || NET_6LOWPAN || NET_LOOPBACK || NET_SLIP + select NET_MULTILINK if NET_ETHERNET || NET_6LOWPAN || NET_LOOPBACK || NET_SLIP select ARCH_HAVE_NETDEV_STATISTICS if NET_TUN @@ -236,6 +245,23 @@ config TUN_LPWORK endchoice # Work queue endif # NET_TUN +config NET_USRSOCK + bool "User-space networking stack API" + default n + ---help--- + Enable or disable user-space networking stack support. + + User-space networking stack API allows user-space daemon to + provide TCP/IP stack implementation for NuttX network. + + Main use for this is to allow use and integration of + HW-provided TCP/IP stacks for NuttX. + + For example, user-space daemon can translate /dev/usrsock API + requests to HW TCP/IP API requests while rest of the user-space + can access standard socket API, with socket descriptors that + can be used with NuttX system calls. + endmenu # Data link support source "net/netdev/Kconfig" @@ -271,6 +297,7 @@ source "net/arp/Kconfig" source "net/loopback/Kconfig" source "net/iob/Kconfig" source "net/procfs/Kconfig" +source "net/usrsock/Kconfig" source "net/utils/Kconfig" config NET_STATISTICS diff --git a/net/Makefile b/net/Makefile index 6898bad40e1..cd6979a4145 100644 --- a/net/Makefile +++ b/net/Makefile @@ -72,6 +72,7 @@ include devif/Make.defs include loopback/Make.defs include route/Make.defs include procfs/Make.defs +include usrsock/Make.defs include utils/Make.defs endif diff --git a/net/README.txt b/net/README.txt index 0f93c075813..e87a0889b51 100644 --- a/net/README.txt +++ b/net/README.txt @@ -22,21 +22,25 @@ Directory Structure +- route - Routing table support +- tcp - Transmission Control Protocol +- udp - User Datagram Protocol + +- usrsock - User socket API for user-space networking stack `- utils - Miscellaneous utility functions - +----------------------------------------------------------------+ - | Application layer | - +----------------------------------------------------------------+ - +----------------------------------------------------------------+ - | Socket layer (socket/) | - +----------------------------------------------------------------+ - +------------++--------------------------------------------------+ - | Network || Protocol stacks (arp, ipv6, icmp, pkt, tcp, udp) | - | Device |+--------------------------------------------------+ - | Interface |+------------------------------------++------------+ - | (netdev/) || Network Device Interface (devif/) || Utilities | - +------------++------------------------------------++------------+ - +----------------------------------------------------------------+ - | Network Device Drivers | - +----------------------------------------------------------------+ + +-------------------------------------------------------------------++------------------------+ + | Application layer || usrsock daemon | + +-------------------------------------------------------------------++------------------------+ + +-------------------------------------------------------------------++----------------+ +-----+ + | Socket layer (socket/) || /dev/usrsock | | | + +-------------------------------------------------------------------++----------------+ | | + +------------++--------------------------------------------------++-------------------+ | | + | Network || Protocol stacks (arp, ipv6, icmp, pkt, tcp, udp) || usrsock/ | | | + | Device |+--------------------------------------------------++-------------------+ | | + | Interface |+------------------------------------++---------------------------------+ | | + | (netdev/) || Network Device Interface (devif/) || Utilities | | | + +------------++------------------------------------++---------------------------------+ | | + +----------------------------------------------------------------+ | | + | Network Device Drivers | | HAL | + +----------------------------------------------------------------+ +-----+ + +----------------------------------------------------------------+ +--------------------------+ + | Networking Hardware | | Hardware TCP/IP Stack | + +----------------------------------------------------------------+ +--------------------------+ \ No newline at end of file diff --git a/net/devif/devif.h b/net/devif/devif.h index bca09878968..28135f4d30f 100644 --- a/net/devif/devif.h +++ b/net/devif/devif.h @@ -1,7 +1,7 @@ /**************************************************************************** * net/devif/devif.h * - * Copyright (C) 2007-2009, 2013-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2013-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * This logic was leveraged from uIP which also has a BSD-style license: @@ -170,11 +170,13 @@ #define TCP_NEWDATA (1 << 1) #define UDP_NEWDATA TCP_NEWDATA #define PKT_NEWDATA TCP_NEWDATA +#define WPAN_NEWDATA TCP_NEWDATA #define TCP_SNDACK (1 << 2) #define TCP_REXMIT (1 << 3) #define TCP_POLL (1 << 4) #define UDP_POLL TCP_POLL #define PKT_POLL TCP_POLL +#define WPAN_POLL TCP_POLL #define TCP_BACKLOG (1 << 5) #define TCP_CLOSE (1 << 6) #define TCP_ABORT (1 << 7) @@ -234,12 +236,17 @@ */ struct net_driver_s; /* Forward reference */ + +typedef CODE uint16_t (*devif_callback_event_t)(FAR struct net_driver_s *dev, + FAR void *pvconn, + FAR void *pvpriv, + uint16_t flags); + struct devif_callback_s { FAR struct devif_callback_s *nxtconn; FAR struct devif_callback_s *nxtdev; - uint16_t (*event)(FAR struct net_driver_s *dev, FAR void *pvconn, - FAR void *pvpriv, uint16_t flags); + FAR devif_callback_event_t event; FAR void *priv; uint16_t flags; }; diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c index 928b779fb38..4a5d325d43a 100644 --- a/net/devif/devif_poll.c +++ b/net/devif/devif_poll.c @@ -186,7 +186,7 @@ static inline int devif_poll_igmp(FAR struct net_driver_s *dev, * ****************************************************************************/ -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK static int devif_poll_udp_connections(FAR struct net_driver_s *dev, devif_poll_callback_t callback) { @@ -208,7 +208,7 @@ static int devif_poll_udp_connections(FAR struct net_driver_s *dev, return bstop; } -#endif /* CONFIG_NET_UDP */ +#endif /* NET_UDP_HAVE_STACK */ /**************************************************************************** * Function: devif_poll_tcp_connections @@ -222,7 +222,7 @@ static int devif_poll_udp_connections(FAR struct net_driver_s *dev, * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev, devif_poll_callback_t callback) { @@ -261,7 +261,7 @@ static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev, * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static inline int devif_poll_tcp_timer(FAR struct net_driver_s *dev, devif_poll_callback_t callback, int hsec) @@ -349,7 +349,7 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback) if (!bstop) #endif -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK { /* Traverse all of the active TCP connections and perform the poll * action. @@ -360,7 +360,7 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback) if (!bstop) #endif -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK { /* Traverse all of the allocated UDP connections and perform * the poll action @@ -467,7 +467,7 @@ int devif_timer(FAR struct net_driver_s *dev, devif_poll_callback_t callback) neighbor_periodic(hsec); #endif -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK /* Traverse all of the active TCP connections and perform the * timer action. */ diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c index 5a773b1ef8d..faa23ad547d 100644 --- a/net/devif/ipv4_input.c +++ b/net/devif/ipv4_input.c @@ -391,7 +391,7 @@ int ipv4_input(FAR struct net_driver_s *dev) #endif /* CONFIG_NET_TCP_REASSEMBLY */ } -#if defined(CONFIG_NET_BROADCAST) && defined(CONFIG_NET_UDP) +#if defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK) /* If IP broadcast support is configured, we check for a broadcast * UDP packet, which may be destined to us (even if there is no IP * address yet assigned to the device as is the case when we are @@ -459,13 +459,13 @@ int ipv4_input(FAR struct net_driver_s *dev) switch (pbuf->proto) { -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK case IP_PROTO_TCP: /* TCP input */ tcp_ipv4_input(dev); break; #endif -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK case IP_PROTO_UDP: /* UDP input */ udp_ipv4_input(dev); break; diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c index 08166306798..149f06d33d9 100644 --- a/net/devif/ipv6_input.c +++ b/net/devif/ipv6_input.c @@ -197,7 +197,7 @@ int ipv6_input(FAR struct net_driver_s *dev) * negotiating over DHCP for an address). */ -#if defined(CONFIG_NET_BROADCAST) && defined(CONFIG_NET_UDP) +#if defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK) if (ipv6->proto == IP_PROTO_UDP && net_ipv6addr_cmp(ipv6->destipaddr, g_ipv6_alloneaddr)) { @@ -253,13 +253,13 @@ int ipv6_input(FAR struct net_driver_s *dev) switch (ipv6->proto) { -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK case IP_PROTO_TCP: /* TCP input */ tcp_ipv6_input(dev); break; #endif -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK case IP_PROTO_UDP: /* UDP input */ udp_ipv6_input(dev); break; diff --git a/net/neighbor/Make.defs b/net/neighbor/Make.defs index cf13cbb732a..7f6b56244ec 100644 --- a/net/neighbor/Make.defs +++ b/net/neighbor/Make.defs @@ -39,7 +39,16 @@ ifeq ($(CONFIG_NET_IPv6),y) NET_CSRCS += neighbor_initialize.c neighbor_add.c neighbor_lookup.c NET_CSRCS += neighbor_update.c neighbor_periodic.c neighbor_findentry.c -NET_CSRCS += neighbor_out.c + +# Link layer specific support + +ifeq ($(CONFIG_NET_ETHERNET),y) +NET_CSRCS += neighbor_ethernet_out.c +endif + +ifeq ($(CONFIG_NET_6LOWPAN),y) +# NET_CSRCS += neighbor_6lowpan_out.c +endif # Include utility build support diff --git a/net/neighbor/neighbor_out.c b/net/neighbor/neighbor_ethernet_out.c similarity index 98% rename from net/neighbor/neighbor_out.c rename to net/neighbor/neighbor_ethernet_out.c index 4725a90ea27..ddd9a3a5ffd 100644 --- a/net/neighbor/neighbor_out.c +++ b/net/neighbor/neighbor_ethernet_out.c @@ -1,7 +1,7 @@ /**************************************************************************** - * net/neighbor/neighbor_out.c + * net/neighbor/neighbor_ethernet_out.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without diff --git a/net/net_initialize.c b/net/net_initialize.c index 988faf6b547..3edbd6849b2 100644 --- a/net/net_initialize.c +++ b/net/net_initialize.c @@ -57,6 +57,7 @@ #include "local/local.h" #include "igmp/igmp.h" #include "route/route.h" +#include "usrsock/usrsock.h" #include "utils/utils.h" /**************************************************************************** @@ -130,7 +131,7 @@ void net_setup(void) local_initialize(); #endif -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK /* Initialize the listening port structures */ tcp_listen_initialize(); @@ -146,7 +147,7 @@ void net_setup(void) #endif #endif /* CONFIG_NET_TCP */ -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK /* Initialize the UDP connection structures */ udp_initialize(); @@ -163,6 +164,12 @@ void net_setup(void) net_initroute(); #endif + +#ifdef CONFIG_NET_USRSOCK + /* Initialize the user-space socket API */ + + usrsock_initialize(); +#endif } /**************************************************************************** diff --git a/net/sixlowpan/Kconfig b/net/sixlowpan/Kconfig index 406a5e8d34d..4d0be0b6600 100644 --- a/net/sixlowpan/Kconfig +++ b/net/sixlowpan/Kconfig @@ -3,14 +3,6 @@ # see the file kconfig-language.txt in the NuttX tools repository. # -menuconfig NET_6LOWPAN - bool "IEEE 802.15.4 6LoWPAN support" - default n - depends on EXPERIMENTAL && NET_IPv6 - ---help--- - Enable support for IEEE 802.15.4 Low power Wireless Personal Area - Networking (6LoWPAN). - if NET_6LOWPAN config NET_6LOWPAN_FRAG @@ -186,10 +178,4 @@ config NET_6LOWPAN_TCP_RECVWNDO the application is slow to process incoming data, or high (32768 bytes) if the application processes data quickly. -config NET_6LOWPAN_SNIFFER - default n - ---help--- - Enable use use an architecture-specific sniffer to support tracing - of IP. - endif # NET_6LOWPAN diff --git a/net/sixlowpan/Make.defs b/net/sixlowpan/Make.defs index e0370185e68..09fc742d397 100644 --- a/net/sixlowpan/Make.defs +++ b/net/sixlowpan/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # net/sixlowpan/Make.defs # -# Copyright (C) 2016 Gregory Nutt. All rights reserved. +# Copyright (C) 2017 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -41,7 +41,7 @@ ifeq ($(CONFIG_NET_6LOWPAN),y) NET_CSRCS += sixlowpan_initialize.c sixlowpan_globals.c sixlowpan_utils.c NET_CSRCS += sixlowpan_input.c sixlowpan_send.c sixlowpan_framer.c -NET_CSRCS += sixlowpan_compressor.c +NET_CSRCS += sixlowpan_framelist.c sixlowpan_compressor.c ifeq ($(CONFIG_NET_TCP),y) NET_CSRCS += sixlowpan_tcpsend.c @@ -59,10 +59,6 @@ ifeq ($(CONFIG_NET_6LOWPAN_COMPRESSION_HC06),y) NET_CSRCS += sixlowpan_hc06.c endif -ifeq ($(CONFIG_NET_6LOWPAN_SNIFFER),y) -NET_CSRCS += sixlowpan_sniffer.c -endif - # Include the sixlowpan directory in the build DEPPATH += --dep-path sixlowpan diff --git a/net/sixlowpan/sixlowpan_compressor.c b/net/sixlowpan/sixlowpan_compressor.c index 837bad77602..7450e408e27 100644 --- a/net/sixlowpan/sixlowpan_compressor.c +++ b/net/sixlowpan/sixlowpan_compressor.c @@ -40,7 +40,6 @@ #include #include "nuttx/net/net.h" -#include "nuttx/net/sixlowpan.h" #include "sixlowpan/sixlowpan_internal.h" diff --git a/net/sixlowpan/sixlowpan_framelist.c b/net/sixlowpan/sixlowpan_framelist.c new file mode 100644 index 00000000000..35750b3ce77 --- /dev/null +++ b/net/sixlowpan/sixlowpan_framelist.c @@ -0,0 +1,473 @@ +/**************************************************************************** + * net/sixlowpan/sixlowpan_framelist.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Parts of this file derive from Contiki: + * + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * Authors: Adam Dunkels + * Nicolas Tsiftes + * Niclas Finne + * Mathilde Durvy + * Julien Abeille + * Joakim Eriksson + * Joel Hoglund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "sixlowpan/sixlowpan_internal.h" + +#ifdef CONFIG_NET_6LOWPAN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* A single IOB must be big enough to hold a full frame */ + +#if CONFIG_IOB_BUFSIZE < CONFIG_NET_6LOWPAN_FRAMELEN +# error IOBs must be large enough to hold full IEEE802.14.5 frame +#endif + +/* There must be at least enough IOBs to hold the full MTU. Probably still + * won't work unless there are a few more. + */ + +#if CONFIG_NET_6LOWPAN_MTU > (CONFIG_IOB_BUFSIZE * CONFIG_IOB_NBUFFERS) +# error Not enough IOBs to hold one full IEEE802.14.5 packet +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sixlowpan_compress_ipv6hdr + * + * Description: + * IPv6 dispatch "compression" function. Packets "Compression" when only + * IPv6 dispatch is used + * + * There is no compression in this case, all fields are sent + * inline. We just add the IPv6 dispatch byte before the packet. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | IPv6 Dsp | IPv6 header and payload ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Input Parameters: + * ieee - Pointer to IEEE802.15.4 MAC driver structure. + * ipv6 - Pointer to the IPv6 header to "compress" + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee, + FAR const struct ipv6_hdr_s *ipv6) +{ + /* Indicate the IPv6 dispatch and length */ + + *g_rimeptr = SIXLOWPAN_DISPATCH_IPV6; + g_rime_hdrlen += SIXLOWPAN_IPV6_HDR_LEN; + + /* Copy the IPv6 header and adjust pointers */ + + memcpy(g_rimeptr + g_rime_hdrlen, ipv6, IPv6_HDRLEN); + g_rime_hdrlen += IPv6_HDRLEN; + g_uncomp_hdrlen += IPv6_HDRLEN; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sixlowpan_queue_frames + * + * Description: + * Process an outgoing UDP or TCP packet. This function is called from + * send interrupt logic when a TX poll is received. It formates the + * list of frames to be sent by the IEEE802.15.4 MAC driver. + * + * The payload data is in the caller 's_buf' and is of length 's_len'. + * Compressed headers will be added and if necessary the packet is + * fragmented. The resulting packet/fragments are put in ieee->i_framelist + * and the entire list of frames will be delivered to the 802.15.4 MAC via + * ieee->i_framelist. + * + * Input Parameters: + * ieee - The IEEE802.15.4 MAC driver instance + * ipv6hdr - IPv6 header followed by TCP or UDP header. + * buf - Data to send + * len - Length of data to send + * destmac - The IEEE802.15.4 MAC address of the destination + * + * Returned Value: + * Ok is returned on success; Othewise a negated errno value is returned. + * This function is expected to fail if the driver is not an IEEE802.15.4 + * MAC network driver. In that case, the UDP/TCP will fall back to normal + * IPv4/IPv6 formatting. + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, + FAR const struct ipv6_hdr_s *destip, + FAR const void *buf, size_t len, + FAR const struct rimeaddr_s *destmac) +{ + FAR struct iob_s *iob; + int framer_hdrlen; + struct rimeaddr_s dest; + uint16_t outlen = 0; + + /* Initialize global data. Locking the network guarantees that we have + * exclusive use of the global values for intermediate calculations. + */ + + FRAME_RESET(); + g_uncomp_hdrlen = 0; + g_rime_hdrlen = 0; + /* REVISIT: Do I need this rimeptr? */ + g_rimeptr = &ieee->i_dev.d_buf[PACKETBUF_HDR_SIZE]; + + /* Reset rime buffer, packet buffer metatadata */ + + memset(g_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t)); + memset(g_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s)); + + g_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] = + CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS; + + /* Set stream mode for all TCP packets, except FIN packets. */ + + if (destip->proto == IP_PROTO_TCP) + { + FAR const struct tcp_hdr_s *tcp = + &((FAR const struct ipv6tcp_hdr_s *)destip)->tcp; + + if ((tcp->flags & TCP_FIN) == 0 && + (tcp->flags & TCP_CTL) != TCP_ACK) + { + g_pktattrs[PACKETBUF_ATTR_PACKET_TYPE] = PACKETBUF_ATTR_PACKET_TYPE_STREAM; + } + else if ((tcp->flags & TCP_FIN) == TCP_FIN) + { + g_pktattrs[PACKETBUF_ATTR_PACKET_TYPE] = PACKETBUF_ATTR_PACKET_TYPE_STREAM_END; + } + } + + /* The destination address will be tagged to each outbound packet. If the + * argument destmac is NULL, we are sending a broadcast packet. + */ + + if (destmac == NULL) + { + memset(&dest, 0, sizeof(struct rimeaddr_s)); + } + else + { + rimeaddr_copy(&dest, (FAR const struct rimeaddr_s *)destmac); + } + + ninfo("Sending packet len %d\n", len); + +#ifndef CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 + if (len >= CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD) + { + /* Try to compress the headers */ + +#if defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC1) + sixlowpan_compresshdr_hc1(ieee, &dest); +#elif defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC06) + sixlowpan_compresshdr_hc06(ieee, &dest); +#else +# error No compression specified +#endif + } + else +#endif /* !CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 */ + { + /* Small.. use IPv6 dispatch (no compression) */ + + sixlowpan_compress_ipv6hdr(ieee, destip); + } + + ninfo("Header of len %d\n", g_rime_hdrlen); + + rimeaddr_copy(&g_pktaddrs[PACKETBUF_ADDR_RECEIVER], &dest); + + /* Pre-calculate frame header length. */ + + framer_hdrlen = sixlowpan_hdrlen(ieee, ieee->i_panid); + if (framer_hdrlen < 0) + { + /* Failed to determine the size of the header failed. */ + + nerr("ERROR: sixlowpan_hdrlen() failed: %d\n", framer_hdrlen); + return framer_hdrlen; + } + + /* Check if we need to fragment the packet into several frames */ + + if ((int)len - (int)g_uncomp_hdrlen > + (int)CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - + (int)g_rime_hdrlen) + { +#if CONFIG_NET_6LOWPAN_FRAG + /* ieee->i_framelist will hold the generated frames; frames will be + * added at qtail. + */ + + FAR struct iob_s *qtail; + int verify; + + /* The outbound IPv6 packet is too large to fit into a single 15.4 + * packet, so we fragment it into multiple packets and send them. + * The first fragment contains frag1 dispatch, then + * IPv6/HC1/HC06/HC_UDP dispatchs/headers. + * The following fragments contain only the fragn dispatch. + */ + + ninfo("Fragmentation sending packet len %d\n", len); + + /* Allocate an IOB to hold the first fragment, waiting if necessary. */ + + iob = iob_alloc(false); + DEBUGASSERT(iob != NULL); + + /* Initialize the IOB */ + + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + + /* Create 1st Fragment */ + /* Add the frame header */ + + verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); + DEBUGASSERT(verify == framer_hdrlen); + UNUSED(verify); + + /* Move HC1/HC06/IPv6 header */ + + memmove(g_rimeptr + SIXLOWPAN_FRAG1_HDR_LEN, g_rimeptr, g_rime_hdrlen); + + /* Setup up the fragment header. + * + * The fragment header contains three fields: Datagram size, datagram + * tag and datagram offset: + * + * 1. Datagram size describes the total (un-fragmented) payload. + * 2. Datagram tag identifies the set of fragments and is used to + * match fragments of the same payload. + * 3. Datagram offset identifies the fragment’s offset within the un- + * fragmented payload. + * + * The fragment header length is 4 bytes for the first header and 5 + * bytes for all subsequent headers. + */ + + PUTINT16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE, + ((SIXLOWPAN_DISPATCH_FRAG1 << 8) | len)); + PUTINT16(RIME_FRAG_PTR, RIME_FRAG_TAG, ieee->i_dgramtag); + ieee->i_dgramtag++; + + /* Copy payload and enqueue */ + + g_rime_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN; + g_rime_payloadlen = + (CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - g_rime_hdrlen) & 0xf8; + + memcpy(g_rimeptr + g_rime_hdrlen, + (FAR uint8_t *)destip + g_uncomp_hdrlen, g_rime_payloadlen); + iob->io_len += g_rime_payloadlen + g_rime_hdrlen; + + /* Set outlen to what we already sent from the IP payload */ + + outlen = g_rime_payloadlen + g_uncomp_hdrlen; + + ninfo("First fragment: len %d, tag %d\n", + g_rime_payloadlen, ieee->i_dgramtag); + + /* Add the first frame to the IOB queue */ + + ieee->i_framelist = iob; + qtail = iob; + + /* Keep track of the total amount of data queue */ + + iob->io_pktlen = iob->io_len; + + /* Create following fragments */ + + g_rime_hdrlen = SIXLOWPAN_FRAGN_HDR_LEN; + + while (outlen < len) + { + /* Allocate an IOB to hold the next fragment, waiting if + * necessary. + */ + + iob = iob_alloc(false); + DEBUGASSERT(iob != NULL); + + /* Initialize the IOB */ + + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + + /* Add the frame header */ + + verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); + DEBUGASSERT(vreify == framer_hdrlen); + UNUSED(verify); + + /* Move HC1/HC06/IPv6 header */ + + memmove(g_rimeptr + SIXLOWPAN_FRAGN_HDR_LEN, g_rimeptr, g_rime_hdrlen); + + /* Setup up the fragment header */ + + PUTINT16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE, + ((SIXLOWPAN_DISPATCH_FRAGN << 8) | len)); + PUTINT16(RIME_FRAG_PTR, RIME_FRAG_TAG, ieee->i_dgramtag); + RIME_FRAG_PTR[RIME_FRAG_OFFSET] = outlen >> 3; + + /* Copy payload and enqueue */ + + if (len - outlen < g_rime_payloadlen) + { + /* Last fragment */ + + g_rime_payloadlen = len - outlen; + } + else + { + g_rime_payloadlen = + (CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - g_rime_hdrlen) & 0xf8; + } + + memcpy(g_rimeptr + g_rime_hdrlen, (FAR uint8_t *)destip + outlen, + g_rime_payloadlen); + iob->io_len = g_rime_payloadlen + g_rime_hdrlen; + + /* Set outlen to what we already sent from the IP payload */ + + outlen += (g_rime_payloadlen + g_uncomp_hdrlen); + + ninfo("sixlowpan output: fragment offset %d, len %d, tag %d\n", + outlen >> 3, g_rime_payloadlen, ieee->i_dgramtag); + + /* Add the next frame to the tail of the IOB queue */ + + qtail->io_flink = iob; + + /* Keep track of the total amount of data queue */ + + ieee->i_framelist->io_pktlen += iob->io_len; + } +#else + nerr("ERROR: Packet too large: %d\n", len); + nerr(" Cannot to be sent without fragmentation support\n"); + nerr(" dropping packet\n"); + + return -E2BIG; +#endif + } + else + { + int verify; + + /* The packet does not need to be fragmented just copy the "payload" + * and send in one frame. + */ + + /* Allocate an IOB to hold the frame, waiting if necessary. */ + + iob = iob_alloc(false); + DEBUGASSERT(iob != NULL); + + /* Initialize the IOB */ + + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + + /* Add the frame header */ + + verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); + DEBUGASSERT(vreify == framer_hdrlen); + UNUSED(verify); + + /* Copy the payload and queue */ + + memcpy(g_rimeptr + g_rime_hdrlen, (FAR uint8_t *)destip + g_uncomp_hdrlen, + len - g_uncomp_hdrlen); + iob->io_len = len - g_uncomp_hdrlen + g_rime_hdrlen; + + /* Add the first frame to the IOB queue */ + + ieee->i_framelist = iob; + + /* Keep track of the total amount of data queue */ + + iob->io_pktlen = iob->io_len; + } + + return OK; +} + +#endif /* CONFIG_NET_6LOWPAN */ diff --git a/net/sixlowpan/sixlowpan_framer.c b/net/sixlowpan/sixlowpan_framer.c index 2b528dea10d..d0efa291d41 100644 --- a/net/sixlowpan/sixlowpan_framer.c +++ b/net/sixlowpan/sixlowpan_framer.c @@ -55,7 +55,6 @@ #include #include "nuttx/net/net.h" -#include "nuttx/net/sixlowpan.h" #include "sixlowpan/sixlowpan_internal.h" @@ -277,9 +276,10 @@ static int sixlowpan_802154_hdrlen(FAR struct frame802154_s *finfo) * * Input parameters: * ieee - A reference IEEE802.15.4 MAC network device structure. - * params - Where to put the parmeters + * iob - The IOB in which to create the frame. * dest_panid - PAN ID of the destination. May be 0xffff if the destination * is not associated. + * params - Where to put the parmeters * * Returned Value: * None. @@ -287,8 +287,8 @@ static int sixlowpan_802154_hdrlen(FAR struct frame802154_s *finfo) ****************************************************************************/ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee, - FAR struct frame802154_s *params, - uint16_t dest_panid) + FAR struct iob_s *iob, uint16_t dest_panid, + FAR struct frame802154_s *params) { bool rcvrnull; @@ -298,22 +298,21 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee, /* Reset to an empty frame */ - ieee->i_framelen = 0; - ieee->i_dataoffset = 0; + FRAME_RESET(); /* Build the FCF (Only non-zero elements need to be initialized). */ params->fcf.frame_type = FRAME802154_DATAFRAME; - params->fcf.frame_pending = ieee->i_pktattrs[PACKETBUF_ATTR_PENDING]; + params->fcf.frame_pending = g_pktattrs[PACKETBUF_ATTR_PENDING]; /* If the output address is NULL in the Rime buf, then it is broadcast * on the 802.15.4 network. */ - rcvrnull = sixlowpan_addrnull(ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8); + rcvrnull = sixlowpan_addrnull(g_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8); if (rcvrnull) { - params->fcf.ack_required = ieee->i_pktattrs[PACKETBUF_ATTR_MAC_ACK]; + params->fcf.ack_required = g_pktattrs[PACKETBUF_ATTR_MAC_ACK]; } /* Insert IEEE 802.15.4 (2003) version bit. */ @@ -322,14 +321,14 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee, /* Increment and set the data sequence number. */ - if (ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] != 0) + if (g_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] != 0) { - params->seq = ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO]; + params->seq = g_pktattrs[PACKETBUF_ATTR_MAC_SEQNO]; } else { params->seq = ieee->i_dsn++; - ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] = params->seq; + g_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] = params->seq; } /* Complete the addressing fields. */ @@ -355,7 +354,7 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee, /* Copy the destination address */ rimeaddr_copy((struct rimeaddr_s *)¶ms->dest_addr, - ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8); + g_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8); /* Use short address mode if so configured */ @@ -370,10 +369,13 @@ static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee, rimeaddr_copy((struct rimeaddr_s *)¶ms->src_addr, &ieee->i_nodeaddr.u8); - /* Configure the payload address and length */ + /* Configure the (optional) payload address and length */ - params->payload = FRAME_DATA_START(ieee); - params->payload_len = FRAME_DATA_SIZE(ieee); + if (iob != NULL) + { + params->payload = FRAME_DATA_START(iob); + params->payload_len = FRAME_DATA_SIZE(iob); + } } /**************************************************************************** @@ -406,7 +408,7 @@ int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee, /* Set up the frame parameters */ - sixlowpan_setup_params(ieee, ¶ms, dest_panid); + sixlowpan_setup_params(ieee, NULL, dest_panid, ¶ms); /* Return the length of the header */ @@ -516,11 +518,14 @@ int sixlowpan_802154_framecreate(FAR struct frame802154_s *finfo, * Function: sixlowpan_framecreate * * Description: - * This function is called after the IEEE802.15.4 MAC driver polls for - * TX data. It creates the IEEE802.15.4 header in the frame buffer. + * This function is called after eiether (1) the IEEE802.15.4 MAC driver + * polls for TX data or (2) after the IEEE802.15.4 MAC driver provides an + * in frame and the network responds with an outgoing packet. It creates + * the IEEE802.15.4 header in the frame buffer. * * Input parameters: * ieee - A reference IEEE802.15.4 MAC network device structure. + * iob - The IOB in which to create the frame. * dest_panid - PAN ID of the destination. May be 0xffff if the destination * is not associated. * @@ -531,7 +536,7 @@ int sixlowpan_802154_framecreate(FAR struct frame802154_s *finfo, ****************************************************************************/ int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, - uint16_t dest_panid) + FAR struct iob_s *iob, uint16_t dest_panid) { struct frame802154_s params; int len; @@ -539,7 +544,7 @@ int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, /* Set up the frame parameters */ - sixlowpan_setup_params(ieee, ¶ms, dest_panid); + sixlowpan_setup_params(ieee, iob, dest_panid, ¶ms); /* Get the length of the header */ @@ -547,7 +552,7 @@ int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, /* Allocate space for the header in the frame buffer */ - ret = sixlowpan_frame_hdralloc(ieee, len); + ret = sixlowpan_frame_hdralloc(iob, len); if (ret < 0) { wlerr("ERROR: Header too large: %u\n", len); @@ -556,11 +561,11 @@ int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, /* Then create the frame */ - sixlowpan_802154_framecreate(¶ms, FRAME_HDR_START(ieee), len); + sixlowpan_802154_framecreate(¶ms, FRAME_HDR_START(iob), len); wlinfo("Frame type: %02x Data len: %d %u (%u)\n", - params.fcf.frame_type, len, FRAME_DATA_SIZE(ieee), - FRAME_SIZE(ieee)); + params.fcf.frame_type, len, FRAME_DATA_SIZE(iob), + FRAME_SIZE(ieee, iob)); #if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2 wlinfo("Dest address: %02x:%02x\n", params.dest_addr[0], params.dest_addr[1]); diff --git a/net/sixlowpan/sixlowpan_globals.c b/net/sixlowpan/sixlowpan_globals.c index 4be92354dd0..6b0f5bcf74b 100644 --- a/net/sixlowpan/sixlowpan_globals.c +++ b/net/sixlowpan/sixlowpan_globals.c @@ -39,8 +39,6 @@ #include -#include "nuttx/net/sixlowpan.h" - #include "sixlowpan/sixlowpan_internal.h" #ifdef CONFIG_NET_6LOWPAN @@ -53,10 +51,50 @@ FAR struct sixlowpan_nhcompressor_s *g_sixlowpan_compressor; -#ifdef CONFIG_NET_6LOWPAN_SNIFFER -/* A pointer to the optional, architecture-specific sniffer */ +/* The following data values are used to hold intermediate settings while + * processing IEEE802.15.4 frames. These globals are shared with incoming + * and outgoing frame processing and possibly with mutliple IEEE802.15.4 MAC + * devices. The network lock provides exclusive use of these globals + * during that processing + */ -FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer; -#endif +/* A pointer to the rime buffer. + * + * We initialize it to the beginning of the rime buffer, then access + * different fields by updating the offset ieee->g_rime_hdrlen. + */ + +FAR uint8_t *g_rimeptr; + +/* The length of the payload in the Rime buffer. + * + * The payload is what comes after the compressed or uncompressed headers + * (can be the IP payload if the IP header only is compressed or the UDP + * payload if the UDP header is also compressed) + */ + +uint8_t g_rime_payloadlen; + +/* g_uncomp_hdrlen is the length of the headers before compression (if HC2 + * is used this includes the UDP header in addition to the IP header). + */ + +uint8_t g_uncomp_hdrlen; + +/* g_rime_hdrlen is the total length of (the processed) 6lowpan headers + * (fragment headers, IPV6 or HC1, HC2, and HC1 and HC2 non compressed + * fields). + */ + +uint8_t g_rime_hdrlen; + +/* Offset first available byte for the payload after header region. */ + +uint8_t g_dataoffset; + +/* Packet buffer metadata: Attributes and addresses */ + +uint16_t g_pktattrs[PACKETBUF_NUM_ATTRS]; +struct rimeaddr_s g_pktaddrs[PACKETBUF_NUM_ADDRS]; #endif /* CONFIG_NET_6LOWPAN */ diff --git a/net/sixlowpan/sixlowpan_hc06.c b/net/sixlowpan/sixlowpan_hc06.c index 534cb1adbf5..e0ca657c036 100644 --- a/net/sixlowpan/sixlowpan_hc06.c +++ b/net/sixlowpan/sixlowpan_hc06.c @@ -59,7 +59,6 @@ #include #include -#include #include "sixlowpan/sixlowpan_internal.h" @@ -169,7 +168,7 @@ void sixlowpan_hc06_initialize(void) } /**************************************************************************** - * Name: sixlowpan_hc06_initialize + * Name: sixlowpan_compresshdr_hc06 * * Description: * Compress IP/UDP header @@ -203,7 +202,7 @@ void sixlowpan_hc06_initialize(void) * compress the IID. * * Input Parameters: - * dev - A reference to the IEE802.15.4 network device state + * ieee - A reference to the IEE802.15.4 network device state * destaddr - L2 destination address, needed to compress IP dest * * Returned Value: @@ -211,7 +210,7 @@ void sixlowpan_hc06_initialize(void) * ****************************************************************************/ -void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev, +void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, FAR struct rimeaddr_s *destaddr) { /* REVISIT: To be provided */ @@ -231,7 +230,7 @@ void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev, * appropriate values * * Input Parmeters: - * dev - A reference to the IEE802.15.4 network device state + * ieee - A reference to the IEE802.15.4 network device state * iplen - Equal to 0 if the packet is not a fragment (IP length is then * inferred from the L2 length), non 0 if the packet is a 1st * fragment. @@ -241,7 +240,7 @@ void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev, * ****************************************************************************/ -void sixlowpan_uncompresshdr_hc06(FAR struct net_driver_s *dev, +void sixlowpan_uncompresshdr_hc06(FAR struct ieee802154_driver_s *ieee, uint16_t iplen) { /* REVISIT: To be provided */ diff --git a/net/sixlowpan/sixlowpan_hc1.c b/net/sixlowpan/sixlowpan_hc1.c index 245a7465c2c..268f0bad3e0 100644 --- a/net/sixlowpan/sixlowpan_hc1.c +++ b/net/sixlowpan/sixlowpan_hc1.c @@ -102,7 +102,7 @@ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Input Parmeters: - * dev - A reference to the IEE802.15.4 network device state + * ieee - A reference to the IEE802.15.4 network device state * destaddr - L2 destination address, needed to compress the IP * destination field * @@ -111,7 +111,7 @@ * ****************************************************************************/ -void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev, +void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, FAR struct rimeaddr_s *destaddr) { /* REVISIT: To be provided */ @@ -130,7 +130,7 @@ void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev, * are set to the appropriate values * * Input Parameters: - * dev - A reference to the IEE802.15.4 network device state + * ieee - A reference to the IEE802.15.4 network device state * iplen - Equal to 0 if the packet is not a fragment (IP length is then * inferred from the L2 length), non 0 if the packet is a 1st * fragment. @@ -140,7 +140,7 @@ void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev, * ****************************************************************************/ -void sixlowpan_uncompresshdr_hc1(FAR struct net_driver_s *dev, +void sixlowpan_uncompresshdr_hc1(FAR struct ieee802154_driver_s *ieee, uint16_t iplen) { /* REVISIT: To be provided */ diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c index ce520f8e5e3..151d205f851 100644 --- a/net/sixlowpan/sixlowpan_input.c +++ b/net/sixlowpan/sixlowpan_input.c @@ -1,35 +1,45 @@ /**************************************************************************** * net/sixlowpan/sixlowpan_input.c + * 6lowpan implementation (RFC4944 and draft-ietf-6lowpan-hc-06) * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017, Gregory Nutt, all rights reserved * Author: Gregory Nutt * + * Derives in large part from Contiki: + * + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * Authors: Adam Dunkels + * Nicolas Tsiftes + * Niclas Finne + * Mathilde Durvy + * Julien Abeille + * Joakim Eriksson + * Joel Hoglund + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * ****************************************************************************/ @@ -39,13 +49,31 @@ #include +#include #include +#include #include "nuttx/net/netdev.h" +#include "nuttx/net/ip.h" +#include "nuttx/net/sixlowpan.h" + +#ifdef CONFIG_NET_PKT +# include "pkt/pkt.h" +#endif + #include "sixlowpan/sixlowpan_internal.h" #ifdef CONFIG_NET_6LOWPAN +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Success return values from sixlowpan_frame_process */ + +#define INPUT_PARTIAL 0 /* Frame processed successful, packet incomplete */ +#define INPUT_COMPLETE 1 /* Frame processed successful, packet complete */ + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -79,6 +107,129 @@ static bool sixlowpan_isbroadcast(uint8_t mode, FAR uint8_t *addr) return true; } +/**************************************************************************** + * Name: sixlowpan_set_pktattrs + * + * Description: + * Setup some packet buffer attributes + * + * Input Parameters: + * ieee - Pointer to IEEE802.15.4 MAC driver structure. + * ipv6 - Pointer to the IPv6 header to "compress" + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void sixlowpan_set_pktattrs(FAR struct ieee802154_driver_s *ieee, + FAR const struct ipv6_hdr_s *ipv6) +{ + int attr = 0; + + /* Set protocol in NETWORK_ID */ + + g_pktattrs[PACKETBUF_ATTR_NETWORK_ID] = ipv6->proto; + + /* Assign values to the channel attribute (port or type + code) */ + + if (ipv6->proto == IP_PROTO_UDP) + { + FAR struct udp_hdr_s *udp = &((FAR struct ipv6udp_hdr_s *)ipv6)->udp; + + attr = udp->srcport; + if (udp->destport < attr) + { + attr = udp->destport; + } + } + else if (ipv6->proto == IP_PROTO_TCP) + { + FAR struct tcp_hdr_s *tcp = &((FAR struct ipv6tcp_hdr_s *)ipv6)->tcp; + + attr = tcp->srcport; + if (tcp->destport < attr) + { + attr = tcp->destport; + } + } + else if (ipv6->proto == IP_PROTO_ICMP6) + { + FAR struct icmpv6_iphdr_s *icmp = &((FAR struct ipv6icmp_hdr_s *)ipv6)->icmp; + + attr = icmp->type << 8 | icmp->code; + } + + g_pktattrs[PACKETBUF_ATTR_CHANNEL] = attr; +} + +/**************************************************************************** + * Name: sixlowpan_frame_process + * + * Description: + * Process an incoming 6loWPAN frame in 'iob'. + * + * If its a FRAG1 or a non-fragmented frame we first uncompress the IP + * header. The 6loWPAN payload and possibly the uncompressed IP header + * are then copied into d_buf. An indication is returned if the packet + * in d_buf is complete (i.e., non-fragmented frame or and the last + * FRAGN frame). + * + * NOTE: We do not check for overlapping sixlowpan fragments (that is a + * SHALL in the RFC 4944 and should never happen) + * + * Input Parameters: + * ieee - The IEEE802.15.4 MAC network driver interface. + * iob - The IOB containing the frame. + * + * Returned Value: + * Ok is returned on success; Othewise a negated errno value is returned. + * + ****************************************************************************/ + +static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, + FAR struct iob_s *iob) +{ + /* REVISIT: To be provided */ + return -ENOSYS; +} + +/**************************************************************************** + * Function: sixlowpan_dispatch + * + * Description: + * Inject the packet in d_buf into the network for normal packet processing. + * + * Parameters: + * ieee - The IEEE802.15.4 MAC network driver interface. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int sixlowpan_dispatch(FAR struct ieee802154_driver_s *ieee) +{ +#ifdef CONFIG_NET_PKT + /* When packet sockets are enabled, feed the frame into the packet tap */ + + ninfo("Packet tap\n"); + pkt_input(&ieee->i_dev); +#endif + + /* We only accept IPv6 packets. */ + + ninfo("Iv6 packet dispatch\n"); + NETDEV_RXIPV6(&ieee->i_dev); + + /* Give the IPv6 packet to the network layer. NOTE: If there is a + * problem with IPv6 header, it will be silently dropped and d_len will + * be set to zero. Oddly, ipv6_input() will return OK in this case. + */ + + return ipv6_input(&ieee->i_dev); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -87,30 +238,117 @@ static bool sixlowpan_isbroadcast(uint8_t mode, FAR uint8_t *addr) * Name: sixlowpan_input * * Description: - * Process an incoming IP packet. + * Process an incoming 6loWPAN frame. * * This function is called when the device driver has received a 6loWPAN - * packet from the network. The packet from the device driver must be - * present in the d_buf buffer, and the length of the packet should be - * placed in the d_len field. + * frame from the network. The frame from the device driver must be + * provided in a IOB present in the i_framelist: The frame data is in the + * IOB io_data[] buffer and the length of the frame is in the IOB io_len + * field. Only a single IOB is expected in the i_framelist. This incoming + * data will be processed one frame at a time. * - * When the function returns, there may be an outbound packet placed - * in the d_buf packet buffer. If so, the d_len field is set to - * the length of the packet. If no packet is to be sent out, the - * d_len field is set to 0. + * An non-NULL d_buf of size CONFIG_NET_6LOWPAN_MTU must also be provided. + * The frame will be decompressed and placed in the d_buf. Fragmented + * packets will also be reassembled in the d_buf as they are received + * (meaning for the driver, that two packet buffers are required: One for + * reassembly of RX packets and one used for TX polling). + * + * After each frame is processed into d_buf, the IOB is removed and + * deallocated. i_framelist will be nullified. If reassembly is + * incomplete, this function will return to called with i_framelist + * equal to NULL. The partially reassembled packet must be preserved by + * the IEEE802.15.4 MAC and provided again when the next frame is + * received. + * + * When the packet in the d_buf is fully reassembled, it will be provided + * to the network as with any other received packet. d_len will be set + * the the length of the uncompressed, reassembled packet. + * + * After the network processes the packet, d_len will be set to zero. + * Network logic may also decide to send a response to the packet. In + * that case, the outgoing network packet will be placed in d_buf the + * d_buf and d_len will be set to a non-zero value. That case is handled + * by this function. + * + * If that case occurs, the packet will be converted to a list of + * compressed and possibly fragmented frames in i_framelist as with other + * TX operations. + * + * So from the standpoint of the IEEE802.15.4 MAC driver, there are two + * possible results: (1) i_framelist is NULL meaning that the frame + * was fully processed and freed, or (2) i_framelist is non-NULL meaning + * that there are outgoing frame(s) to be sent. * * Input Parameters: - * dev - The IEEE802.15.4 MAC network driver interface. + * ieee - The IEEE802.15.4 MAC network driver interface. * * Returned Value: * Ok is returned on success; Othewise a negated errno value is returned. * ****************************************************************************/ -int sixlowpan_input(FAR struct net_driver_s *dev) +int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) { - /* REVISIT: To be provided */ - return -ENOSYS; + int ret = -EINVAL; + + DEBUGASSERT(ieee != NULL && !FRAME_IOB_EMPTY(ieee)); + + /* Verify that an IOB is provided in the device structure */ + + while (!FRAME_IOB_EMPTY(ieee)) + { + FAR struct iob_s *iob; + + /* Remove the IOB containing the frame from the device structure */ + + FRAME_IOB_REMOVE(ieee, iob); + DEBUGASSERT(iob != NULL); + + /* Process the frame, decompressing it into the packet buffer */ + + ret = sixlowpan_frame_process(ieee, iob); + + /* Was the frame successfully processed? Is the packet in d_buf fully + * reassembled? + */ + + if (ret == INPUT_COMPLETE) + { + /* Inject the uncompressed, reassembled packet into the network */ + + ret = sixlowpan_dispatch(ieee); + if (ret >= 0) + { + /* Check if this resulted in a request to send an outgoing + * packet. + */ + + if (ieee->i_dev.d_len > 0) + { + FAR struct ipv6_hdr_s *ipv6hdr; + struct rimeaddr_s destmac; + + /* The IPv6 header followed by TCP or UDP headers should + * lie at the beginning of d_buf since there is no link + * layer protocol header. + */ + + ipv6hdr = (FAR struct ipv6_hdr_s *)(ieee->i_dev.d_buf); + + /* Get the Rime MAC address of the destination */ +#warning Missing logic + + /* Convert the outgoing packet into a frame list. */ + + ret = sixlowpan_queue_frames(ieee, ipv6hdr, ieee->i_dev.d_buf, + ieee->i_dev.d_len, &destmac); + ieee->i_dev.d_len = 0; + } + } + } + } + + return ret; } #endif /* CONFIG_NET_6LOWPAN */ diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h index 6828c141285..644880398f9 100644 --- a/net/sixlowpan/sixlowpan_internal.h +++ b/net/sixlowpan/sixlowpan_internal.h @@ -63,6 +63,7 @@ #include #include #include +#include #ifdef CONFIG_NET_6LOWPAN @@ -81,30 +82,45 @@ #define rimeaddr_cmp(addr1,addr2) \ (memcmp(addr1, addr2, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE) == 0) -/* Frame buffer helpers */ +/* Pointers in the Rime buffer */ -#define FRAME_RESET(ieee) \ - do \ - { \ - (ieee)->i_dataoffset = 0; \ - (ieee)->i_framelen = 0; \ - } \ - while (0) +/* Fragment header. + * + * The fragment header is used when the payload is too large to fit in a + * single IEEE 802.15.4 frame. The fragment header contains three fields: + * Datagram size, datagram tag and datagram offset. + * + * 1. Datagram size describes the total (un-fragmented) payload. + * 2. Datagram tag identifies the set of fragments and is used to match + * fragments of the same payload. + * 3. Datagram offset identifies the fragment’s offset within the un- + * fragmented payload. + * + * The fragment header length is 4 bytes for the first header and 5 + * bytes for all subsequent headers. + */ -#define FRAME_HDR_START(ieee) \ - ((ieee)->i_frame) -#define FRAME_HDR_SIZE(ieee) \ - ((ieee)->i_dataoffset) +#define RIME_FRAG_PTR g_rimeptr +#define RIME_FRAG_DISPATCH_SIZE 0 /* 16 bit */ +#define RIME_FRAG_TAG 2 /* 16 bit */ +#define RIME_FRAG_OFFSET 4 /* 8 bit */ -#define FRAME_DATA_START(ieee) \ - ((FAR uint8_t *)((ieee)->i_frame) + (ieee)->i_dataoffset) -#define FRAME_DATA_SIZE(ieee) \ - ((ieee)->i_framelen - (ieee)->i_dataoffset) +/* Define the Rime buffer as a byte array */ -#define FRAME_REMAINING(ieee) \ - (CONFIG_NET_6LOWPAN_FRAMELEN - (ieee)->i_framelen) -#define FRAME_SIZE(ieee) \ - ((ieee)->i_framelen) +#define RIME_IPHC_BUF (g_rimeptr + g_rime_hdrlen) + +#define RIME_HC1_PTR (g_rimeptr + g_rime_hdrlen) +#define RIME_HC1_DISPATCH 0 /* 8 bit */ +#define RIME_HC1_ENCODING 1 /* 8 bit */ +#define RIME_HC1_TTL 2 /* 8 bit */ + +#define RIME_HC1_HC_UDP_PTR (g_rimeptr + g_rime_hdrlen) +#define RIME_HC1_HC_UDP_DISPATCH 0 /* 8 bit */ +#define RIME_HC1_HC_UDP_HC1_ENCODING 1 /* 8 bit */ +#define RIME_HC1_HC_UDP_UDP_ENCODING 2 /* 8 bit */ +#define RIME_HC1_HC_UDP_TTL 3 /* 8 bit */ +#define RIME_HC1_HC_UDP_PORTS 4 /* 8 bit */ +#define RIME_HC1_HC_UDP_CHKSUM 5 /* 16 bit */ /* These are some definitions of element values used in the FCF. See the * IEEE802.15.4 spec for details. @@ -133,6 +149,94 @@ #define FRAME802154_SECURITY_LEVEL_NONE 0 #define FRAME802154_SECURITY_LEVEL_128 3 +/* Packet buffer Definitions */ + +#define PACKETBUF_HDR_SIZE 48 + +#define PACKETBUF_ATTR_PACKET_TYPE_DATA 0 +#define PACKETBUF_ATTR_PACKET_TYPE_ACK 1 +#define PACKETBUF_ATTR_PACKET_TYPE_STREAM 2 +#define PACKETBUF_ATTR_PACKET_TYPE_STREAM_END 3 +#define PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP 4 + +/* Packet buffer attributes (indices into i_pktattr) */ + +#define PACKETBUF_ATTR_NONE 0 + +/* Scope 0 attributes: used only on the local node. */ + +#define PACKETBUF_ATTR_CHANNEL 1 +#define PACKETBUF_ATTR_NETWORK_ID 2 +#define PACKETBUF_ATTR_LINK_QUALITY 3 +#define PACKETBUF_ATTR_RSSI 4 +#define PACKETBUF_ATTR_TIMESTAMP 5 +#define PACKETBUF_ATTR_RADIO_TXPOWER 6 +#define PACKETBUF_ATTR_LISTEN_TIME 7 +#define PACKETBUF_ATTR_TRANSMIT_TIME 8 +#define PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS 9 +#define PACKETBUF_ATTR_MAC_SEQNO 10 +#define PACKETBUF_ATTR_MAC_ACK 11 + +/* Scope 1 attributes: used between two neighbors only. */ + +#define PACKETBUF_ATTR_RELIABLE 12 +#define PACKETBUF_ATTR_PACKET_ID 13 +#define PACKETBUF_ATTR_PACKET_TYPE 14 +#define PACKETBUF_ATTR_REXMIT 15 +#define PACKETBUF_ATTR_MAX_REXMIT 16 +#define PACKETBUF_ATTR_NUM_REXMIT 17 +#define PACKETBUF_ATTR_PENDING 18 + +/* Scope 2 attributes: used between end-to-end nodes. */ + +#define PACKETBUF_ATTR_HOPS 11 +#define PACKETBUF_ATTR_TTL 20 +#define PACKETBUF_ATTR_EPACKET_ID 21 +#define PACKETBUF_ATTR_EPACKET_TYPE 22 +#define PACKETBUF_ATTR_ERELIABLE 23 + +#define PACKETBUF_NUM_ATTRS 24 + +/* Addresses (indices into i_pktaddr) */ + +#define PACKETBUF_ADDR_SENDER 0 +#define PACKETBUF_ADDR_RECEIVER 1 +#define PACKETBUF_ADDR_ESENDER 2 +#define PACKETBUF_ADDR_ERECEIVER 3 + +#define PACKETBUF_NUM_ADDRS 4 + +/* Frame buffer helpers *****************************************************/ + +#define FRAME_RESET() \ + do \ + { \ + g_dataoffset = 0; \ + } \ + while (0) + +#define FRAME_HDR_START(iob) ((iob)->io_data) +#define FRAME_HDR_SIZE(iob) g_dataoffset + +#define FRAME_DATA_START(iob) ((FAR uint8_t *)((iob)->io_data) + g_dataoffset) +#define FRAME_DATA_SIZE(iob) ((iob)->io_len - g_dataoffset) + +#define FRAME_REMAINING(iob) (CONFIG_NET_6LOWPAN_FRAMELEN - (iob)->io_len) +#define FRAME_SIZE(ieee,iob) \ + ((iob)->io_len) + +/* General helper macros ****************************************************/ + +#define GETINT16(ptr,index) \ + ((((uint16_t)((ptr)[index]) << 8)) | ((uint16_t)(((ptr)[(index) + 1])))) +#define PUTINT16(ptr,index,value) \ + do \ + { \ + (ptr)[index] = ((uint16_t)(value) >> 8) & 0xff; \ + (ptr)[index + 1] = (uint16_t)(value) & 0xff; \ + } \ + while(0) + /**************************************************************************** * Public Types ****************************************************************************/ @@ -236,12 +340,51 @@ struct frame802154_s struct sixlowpan_nhcompressor_s; /* Foward reference */ extern FAR struct sixlowpan_nhcompressor_s *g_sixlowpan_compressor; -#ifdef CONFIG_NET_6LOWPAN_SNIFFER -/* Rime Sniffer support for one single listener to enable trace of IP */ +/* The following data values are used to hold intermediate settings while + * processing IEEE802.15.4 frames. These globals are shared with incoming + * and outgoing frame processing and possibly with mutliple IEEE802.15.4 MAC + * devices. The network lock provides exclusive use of these globals + * during that processing + */ -struct sixlowpan_rime_sniffer_s; /* Foward reference */ -extern FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer; -#endif +/* A pointer to the rime buffer. + * + * We initialize it to the beginning of the rime buffer, then access + * different fields by updating the offset ieee->g_rime_hdrlen. + */ + +extern FAR uint8_t *g_rimeptr; + +/* The length of the payload in the Rime buffer. + * + * The payload is what comes after the compressed or uncompressed headers + * (can be the IP payload if the IP header only is compressed or the UDP + * payload if the UDP header is also compressed) + */ + +extern uint8_t g_rime_payloadlen; + +/* g_uncomp_hdrlen is the length of the headers before compression (if HC2 + * is used this includes the UDP header in addition to the IP header). + */ + +extern uint8_t g_uncomp_hdrlen; + +/* g_rime_hdrlen is the total length of (the processed) 6lowpan headers + * (fragment headers, IPV6 or HC1, HC2, and HC1 and HC2 non compressed + * fields). + */ + +extern uint8_t g_rime_hdrlen; + +/* Offset first available byte for the payload after header region. */ + +uint8_t g_dataoffset; + +/* Packet buffer metadata: Attributes and addresses */ + +extern uint16_t g_pktattrs[PACKETBUF_NUM_ATTRS]; +extern struct rimeaddr_s g_pktaddrs[PACKETBUF_NUM_ADDRS]; /**************************************************************************** * Public Types @@ -254,6 +397,7 @@ extern FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer; struct net_driver_s; /* Forward reference */ struct ieee802154_driver_s; /* Forward reference */ struct rimeaddr_s; /* Forward reference */ +struct iob_s; /* Forward reference */ /**************************************************************************** * Name: sixlowpan_send @@ -263,19 +407,19 @@ struct rimeaddr_s; /* Forward reference */ * it to be sent on an 802.15.4 network using 6lowpan. Called from common * UDP/TCP send logic. * - * The payload data is in the caller 'buf' and is of length 'len'. - * Compressed headers will be added and if necessary the packet is - * fragmented. The resulting packet/fragments are put in dev->d_buf and - * the first frame will be delivered to the 802.15.4 MAC. via ieee->i_frame. - * - * Input Parmeters: + * The payload data is in the caller 'buf' and is of length 'len'. + * Compressed headers will be added and if necessary the packet is + * fragmented. The resulting packet/fragments are put in ieee->i_framelist + * and the entire list of frames will be delivered to the 802.15.4 MAC via + * ieee->i_framelist. * * Input Parameters: - * dev - The IEEE802.15.4 MAC network driver interface. - * ipv6 - IPv6 plus TCP or UDP headers. - * buf - Data to send - * len - Length of data to send - * raddr - The MAC address of the destination + * dev - The IEEE802.15.4 MAC network driver interface. + * ipv6 - IPv6 plus TCP or UDP headers. + * buf - Data to send + * len - Length of data to send + * raddr - The MAC address of the destination + * timeout - Send timeout in deciseconds * * Returned Value: * Ok is returned on success; Othewise a negated errno value is returned. @@ -290,7 +434,8 @@ struct rimeaddr_s; /* Forward reference */ int sixlowpan_send(FAR struct net_driver_s *dev, FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf, - size_t len, FAR const struct rimeaddr_s *raddr); + size_t len, FAR const struct rimeaddr_s *raddr, + uint16_t timeout); /**************************************************************************** * Function: sixlowpan_hdrlen @@ -323,6 +468,7 @@ int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee, * * Input parameters: * ieee - A reference IEEE802.15.4 MAC network device structure. + * iob - The IOB in which to create the frame. * dest_panid - PAN ID of the destination. May be 0xffff if the destination * is not associated. * @@ -333,7 +479,44 @@ int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee, ****************************************************************************/ int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, - uint16_t dest_panid); + FAR struct iob_s *iob, uint16_t dest_panid); + +/**************************************************************************** + * Name: sixlowpan_queue_frames + * + * Description: + * Process an outgoing UDP or TCP packet. This function is called from + * send interrupt logic when a TX poll is received. It formates the + * list of frames to be sent by the IEEE802.15.4 MAC driver. + * + * The payload data is in the caller 's_buf' and is of length 's_len'. + * Compressed headers will be added and if necessary the packet is + * fragmented. The resulting packet/fragments are put in ieee->i_framelist + * and the entire list of frames will be delivered to the 802.15.4 MAC via + * ieee->i_framelist. + * + * Input Parameters: + * ieee - The IEEE802.15.4 MAC driver instance + * ipv6hdr - IPv6 header followed by TCP or UDP header. + * buf - Data to send + * len - Length of data to send + * destmac - The IEEE802.15.4 MAC address of the destination + * + * Returned Value: + * Ok is returned on success; Othewise a negated errno value is returned. + * This function is expected to fail if the driver is not an IEEE802.15.4 + * MAC network driver. In that case, the UDP/TCP will fall back to normal + * IPv4/IPv6 formatting. + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, + FAR const struct ipv6_hdr_s *ipv6hdr, + FAR const void *buf, size_t len, + FAR const struct rimeaddr_s *destmac); /**************************************************************************** * Name: sixlowpan_hc06_initialize @@ -375,7 +558,7 @@ void sixlowpan_hc06_initialize(void); * compression * * Input Parameters: - * dev - A reference to the IEE802.15.4 network device state + * ieee - A reference to the IEE802.15.4 network device state * destaddr - L2 destination address, needed to compress IP dest * * Returned Value: @@ -384,7 +567,7 @@ void sixlowpan_hc06_initialize(void); ****************************************************************************/ #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06 -void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev, +void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *dev, FAR struct rimeaddr_s *destaddr); #endif @@ -402,7 +585,7 @@ void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev, * appropriate values * * Input Parmeters: - * dev - A reference to the IEE802.15.4 network device state + * ieee - A reference to the IEE802.15.4 network device state * iplen - Equal to 0 if the packet is not a fragment (IP length is then * inferred from the L2 length), non 0 if the packet is a 1st * fragment. @@ -413,7 +596,7 @@ void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev, ****************************************************************************/ #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06 -void sixlowpan_uncompresshdr_hc06(FAR struct net_driver_s *dev, +void sixlowpan_uncompresshdr_hc06(FAR struct ieee802154_driver_s *ieee, uint16_t iplen); #endif @@ -428,7 +611,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct net_driver_s *dev, * uip_buf buffer. * * Input Parmeters: - * dev - A reference to the IEE802.15.4 network device state + * ieee - A reference to the IEE802.15.4 network device state * destaddr - L2 destination address, needed to compress the IP * destination field * @@ -438,7 +621,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct net_driver_s *dev, ****************************************************************************/ #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1 -void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev, +void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, FAR struct rimeaddr_s *destaddr); #endif @@ -455,7 +638,7 @@ void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev, * are set to the appropriate values * * Input Parameters: - * dev - A reference to the IEE802.15.4 network device state + * ieee - A reference to the IEE802.15.4 network device state * iplen - Equal to 0 if the packet is not a fragment (IP length is then * inferred from the L2 length), non 0 if the packet is a 1st * fragment. @@ -466,7 +649,7 @@ void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev, ****************************************************************************/ #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1 -void sixlowpan_uncompresshdr_hc1(FAR struct net_driver_s *dev, +void sixlowpan_uncompresshdr_hc1(FAR struct ieee802154_driver_s *ieee, uint16_t ip_len); #endif @@ -474,12 +657,11 @@ void sixlowpan_uncompresshdr_hc1(FAR struct net_driver_s *dev, * Name: sixlowpan_frame_hdralloc * * Description: - * Allocate space for a header within the frame buffer (i_frame). + * Allocate space for a header within the frame buffer (IOB). * ****************************************************************************/ -int sixlowpan_frame_hdralloc(FAR struct ieee802154_driver_s *ieee, - int size); +int sixlowpan_frame_hdralloc(FAR struct iob_s *iob, int size); #endif /* CONFIG_NET_6LOWPAN */ #endif /* _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H */ diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c index ad72cce3836..cff92eeceed 100644 --- a/net/sixlowpan/sixlowpan_send.c +++ b/net/sixlowpan/sixlowpan_send.c @@ -4,18 +4,6 @@ * Copyright (C) 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * - * Parts of this file derive from Contiki: - * - * Copyright (c) 2008, Swedish Institute of Computer Science. - * All rights reserved. - * Authors: Adam Dunkels - * Nicolas Tsiftes - * Niclas Finne - * Mathilde Durvy - * Julien Abeille - * Joakim Eriksson - * Joel Hoglund - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -23,23 +11,25 @@ * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ @@ -49,183 +39,168 @@ #include -#include -#include +#include #include #include -#include "nuttx/net/iob.h" -#include "nuttx/net/netdev.h" -#include "nuttx/net/ip.h" -#include "nuttx/net/tcp.h" -#include "nuttx/net/udp.h" -#include "nuttx/net/icmpv6.h" -#include "nuttx/net/sixlowpan.h" +#include +#include +#include -#include "iob/iob.h" #include "netdev/netdev.h" -#include "socket/socket.h" -#include "tcp/tcp.h" -#include "udp/udp.h" +#include "devif/devif.h" + #include "sixlowpan/sixlowpan_internal.h" #ifdef CONFIG_NET_6LOWPAN /**************************************************************************** - * Pre-processor Definitions + * Private Types ****************************************************************************/ -/* Configuration ************************************************************/ - -/* A single IOB must be big enough to hold a full frame */ - -#if CONFIG_IOB_BUFSIZE < CONFIG_NET_6LOWPAN_FRAMELEN -# error IOBs must be large enough to hold full IEEE802.14.5 frame -#endif - -/* There must be at least enough IOBs to hold the full MTU. Probably still - * won't work unless there are a few more. +/* This is the state data provided to the send interrupt logic. No actions + * can be taken until the until we receive the TX poll, then we can call + * sixlowpan_queue_frames() with this data strurcture. */ -#if CONFIG_NET_6LOWPAN_MTU > (CONFIG_IOB_BUFSIZE * CONFIG_IOB_NBUFFERS) -# error Not enough IOBs to hold one full IEEE802.14.5 packet -#endif +struct sixlowpan_send_s +{ + FAR struct devif_callback_s *s_cb; /* Reference to callback instance */ + sem_t s_waitsem; /* Supports waiting for driver events */ + int s_result; /* The result of the transfer */ + uint16_t s_timeout; /* Send timeout in deciseconds */ + systime_t s_time; /* Last send time for determining timeout */ + FAR const struct ipv6_hdr_s *s_ipv6hdr; /* IPv6 header, followed by UDP or TCP header. */ + FAR const struct rimeaddr_s *s_destmac; /* Destination MAC address */ + FAR const void *s_buf; /* Data to send */ + size_t s_len; /* Length of data in buf */ +}; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: sixlowpan_set_pktattrs + * Function: send_timeout * * Description: - * Setup some packet buffer attributes + * Check for send timeout. * * Input Parameters: - * ieee - Pointer to IEEE802.15.4 MAC driver structure. - * ipv6 - Pointer to the IPv6 header to "compress" + * sinfo - Send state structure reference * * Returned Value: - * None + * TRUE:timeout FALSE:no timeout + * + * Assumptions: + * The network is locked * ****************************************************************************/ -static void sixlowpan_set_pktattrs(FAR struct ieee802154_driver_s *ieee, - FAR const struct ipv6_hdr_s *ipv6) +static inline bool send_timeout(FAR struct sixlowpan_send_s *sinfo) { - int attr = 0; - - /* Set protocol in NETWORK_ID */ - - ieee->i_pktattrs[PACKETBUF_ATTR_NETWORK_ID] = ipv6->proto; - - /* Assign values to the channel attribute (port or type + code) */ - - if (ipv6->proto == IP_PROTO_UDP) - { - FAR struct udp_hdr_s *udp = &((FAR struct ipv6udp_hdr_s *)ipv6)->udp; - - attr = udp->srcport; - if (udp->destport < attr) - { - attr = udp->destport; - } - } - else if (ipv6->proto == IP_PROTO_TCP) - { - FAR struct tcp_hdr_s *tcp = &((FAR struct ipv6tcp_hdr_s *)ipv6)->tcp; - - attr = tcp->srcport; - if (tcp->destport < attr) - { - attr = tcp->destport; - } - } - else if (ipv6->proto == IP_PROTO_ICMP6) - { - FAR struct icmpv6_iphdr_s *icmp = &((FAR struct ipv6icmp_hdr_s *)ipv6)->icmp; - - attr = icmp->type << 8 | icmp->code; - } - - ieee->i_pktattrs[PACKETBUF_ATTR_CHANNEL] = attr; -} - -/**************************************************************************** - * Name: sixlowpan_compress_ipv6hdr - * - * Description: - * IPv6 dispatch "compression" function. Packets "Compression" when only - * IPv6 dispatch is used - * - * There is no compression in this case, all fields are sent - * inline. We just add the IPv6 dispatch byte before the packet. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | IPv6 Dsp | IPv6 header and payload ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * Input Parameters: - * ieee - Pointer to IEEE802.15.4 MAC driver structure. - * ipv6 - Pointer to the IPv6 header to "compress" - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee, - FAR const struct ipv6_hdr_s *ipv6) -{ - /* Indicate the IPv6 dispatch and length */ - - *ieee->i_rimeptr = SIXLOWPAN_DISPATCH_IPV6; - ieee->i_rime_hdrlen += SIXLOWPAN_IPV6_HDR_LEN; - - /* Copy the IPv6 header and adjust pointers */ - - memcpy(ieee->i_rimeptr + ieee->i_rime_hdrlen, ipv6, IPv6_HDRLEN); - ieee->i_rime_hdrlen += IPv6_HDRLEN; - ieee->i_uncomp_hdrlen += IPv6_HDRLEN; -} - -/**************************************************************************** - * Name: sixlowpan_send_frame - * - * Description: - * Send one frame when the IEEE802.15.4 MAC device next polls. - * - * Input Parameters: - * ieee - Pointer to IEEE802.15.4 MAC driver structure. - * iobq - The list of frames to send. - * - * Returned Value: - * Zero (OK) on success; otherwise a negated errno value is returned. - * - ****************************************************************************/ - -static int sixlowpan_send_frame(FAR struct ieee802154_driver_s *ieee, - FAR struct iob_s *iobq) -{ - /* Prepare the frame */ -#warning Missing logic - /* Set up for the TX poll */ - /* When polled, then we need to call sixlowpan_framecreate() to create the - * frame and copy the payload data into the frame. + /* Check for a timeout. Zero means none and, in that case, we will let + * the send wait forever. */ -#if 0 /* Just some notes of what needs to be done in interrupt handler */ - framer_hdrlen = sixlowpan_createframe(ieee, ieee->i_panid); - memcpy(ieee->i_rimeptr + ieee->i_rime_hdrlen, (uint8_t *)ipv6 + ieee->i_uncomp_hdrlen, len - ieee->i_uncomp_hdrlen); - dev->i_framelen = len - ieee->i_uncomp_hdrlen + ieee->i_rime_hdrlen; -#endif -#warning Missing logic - /* Notify the IEEE802.14.5 MAC driver that we have data to be sent */ -#warning Missing logic - /* Wait for the transfer to complete */ -#warning Missing logic - return -ENOSYS; + + if (sinfo->s_timeout != 0) + { + /* Check if the configured timeout has elapsed */ + + systime_t timeo_ticks = DSEC2TICK(sinfo->s_timeout); + systime_t elapsed = clock_systimer() - sinfo->s_time; + + if (elapsed >= timeo_ticks) + { + return true; + } + } + + /* No timeout */ + + return false; +} + +/**************************************************************************** + * Function: send_interrupt + * + * Description: + * This function is called from the interrupt level to perform the actual + * send operation when polled by the lower, device interfacing layer. + * + * Parameters: + * dev - The structure of the network driver that caused the interrupt + * conn - The connection structure associated with the socket + * flags - Set of events describing why the callback was invoked + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static uint16_t send_interrupt(FAR struct net_driver_s *dev, + FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct sixlowpan_send_s *sinfo = (FAR struct sixlowpan_send_s *)pvpriv; + + ninfo("flags: %04x: %d\n", flags); + + /* Check if the IEEE802.15.4 went down */ + + if ((flags & NETDEV_DOWN) != 0) + { + ninfo("Device is down\n"); + sinfo->s_result = -ENOTCONN; + goto end_wait; + } + + /* Check for a poll for TX data. */ + + if ((flags & WPAN_NEWDATA) == 0) + { + DEBUGASSERT((flags & WPAN_POLL) != 0); + + /* Transfer the frame listto the IEEE802.15.4 MAC device */ + + sinfo->s_result = + sixlowpan_queue_frames((FAR struct ieee802154_driver_s *)dev, + sinfo->s_ipv6hdr, sinfo->s_buf, sinfo->s_len, + sinfo->s_destmac); + + flags &= ~WPAN_POLL; + goto end_wait; + } + + /* Check for a timeout. */ + + if (send_timeout(sinfo)) + { + /* Yes.. report the timeout */ + + nwarn("WARNING: SEND timeout\n"); + sinfo->s_result = -ETIMEDOUT; + goto end_wait; + } + + /* Continue waiting */ + + return flags; + +end_wait: + /* Do not allow any further callbacks */ + + sinfo->s_cb->flags = 0; + sinfo->s_cb->priv = NULL; + sinfo->s_cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&sinfo->s_waitsem); + return flags; } /**************************************************************************** @@ -240,19 +215,19 @@ static int sixlowpan_send_frame(FAR struct ieee802154_driver_s *ieee, * it to be sent on an 802.15.4 network using 6lowpan. Called from common * UDP/TCP send logic. * - * The payload data is in the caller 'buf' and is of length 'len'. - * Compressed headers will be added and if necessary the packet is - * fragmented. The resulting packet/fragments are put in dev->d_buf and - * the first frame will be delivered to the 802.15.4 MAC. via ieee->i_frame. - * - * Input Parmeters: + * The payload data is in the caller 'buf' and is of length 'len'. + * Compressed headers will be added and if necessary the packet is + * fragmented. The resulting packet/fragments are put in ieee->i_framelist + * and the entire list of frames will be delivered to the 802.15.4 MAC via + * ieee->i_framelist. * * Input Parameters: - * dev - The IEEE802.15.4 MAC network driver interface. - * ipv6 - IPv6 plus TCP or UDP headers. - * buf - Data to send - * len - Length of data to send - * raddr - The IEEE802.15.4 MAC address of the destination + * dev - The IEEE802.15.4 MAC network driver interface. + * ipv6hdr - IPv6 header followed by TCP or UDP header. + * buf - Data to send + * len - Length of data to send + * destmac - The IEEE802.15.4 MAC address of the destination + * timeout - Send timeout in deciseconds * * Returned Value: * Ok is returned on success; Othewise a negated errno value is returned. @@ -266,238 +241,71 @@ static int sixlowpan_send_frame(FAR struct ieee802154_driver_s *ieee, ****************************************************************************/ int sixlowpan_send(FAR struct net_driver_s *dev, - FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf, - size_t len, FAR const struct rimeaddr_s *raddr) + FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf, + size_t len, FAR const struct rimeaddr_s *destmac, + uint16_t timeout) { - FAR struct ieee802154_driver_s *ieee = (FAR struct ieee802154_driver_s *)dev; - FAR struct iob_s *iob; - int framer_hdrlen; - struct rimeaddr_s dest; - uint16_t outlen = 0; + struct sixlowpan_send_s sinfo; - /* Initialize device-specific data */ + /* Initialize the send state structure */ - FRAME_RESET(ieee); - ieee->i_uncomp_hdrlen = 0; - ieee->i_rime_hdrlen = 0; - /* REVISIT: Do I need this rimeptr? */ - ieee->i_rimeptr = &dev->d_buf[PACKETBUF_HDR_SIZE]; + sem_init(&sinfo.s_waitsem, 0, 0); + (void)sem_setprotocol(&sinfo.s_waitsem, SEM_PRIO_NONE); - /* Reset rime buffer, packet buffer metatadata */ + sinfo.s_result = -EBUSY; + sinfo.s_timeout = timeout; + sinfo.s_time = clock_systimer(); + sinfo.s_ipv6hdr = ipv6hdr; + sinfo.s_destmac = destmac; + sinfo.s_buf = buf; + sinfo.s_len = len; - memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t)); - memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s)); - - ieee->i_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] = - CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS; - -#ifdef CONFIG_NET_6LOWPAN_SNIFFER - if (g_sixlowpan_sniffer != NULL) + net_lock(); + if (len > 0) { - /* Reset rime buffer, packet buffer metatadata */ + /* Allocate resources to receive a callback. + * + * The second parameter is NULL meaning that we can get only + * device related events, no connect-related events. + */ - memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t)); - memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s)); - - ieee->i_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] = - CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS; - - /* Call the attribution when the callback comes, but set attributes here */ - - sixlowpan_set_pktattrs(ieee, ipv6); - } -#endif - - /* Reset rime buffer, packet buffer metatadata */ - - memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t)); - memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s)); - - ieee->i_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] = - CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS; - - /* Set stream mode for all TCP packets, except FIN packets. */ - - if (ipv6->proto == IP_PROTO_TCP) - { - FAR const struct tcp_hdr_s *tcp = &((FAR const struct ipv6tcp_hdr_s *)ipv6)->tcp; - - if ((tcp->flags & TCP_FIN) == 0 && - (tcp->flags & TCP_CTL) != TCP_ACK) + sinfo.s_cb = devif_callback_alloc(dev, NULL); + if (sinfo.s_cb != NULL) { - ieee->i_pktattrs[PACKETBUF_ATTR_PACKET_TYPE] = PACKETBUF_ATTR_PACKET_TYPE_STREAM; - } - else if ((tcp->flags & TCP_FIN) == TCP_FIN) - { - ieee->i_pktattrs[PACKETBUF_ATTR_PACKET_TYPE] = PACKETBUF_ATTR_PACKET_TYPE_STREAM_END; - } - } + int ret; - /* The destination address will be tagged to each outbound packet. If the - * argument raddr is NULL, we are sending a broadcast packet. - */ + /* Set up the callback in the connection */ - if (raddr == NULL) - { - memset(&dest, 0, sizeof(struct rimeaddr_s)); - } - else - { - rimeaddr_copy(&dest, (FAR const struct rimeaddr_s *)raddr); - } + sinfo.s_cb->flags = (NETDEV_DOWN | WPAN_POLL); + sinfo.s_cb->priv = (FAR void *)&sinfo; + sinfo.s_cb->event = send_interrupt; - ninfo("Sending packet len %d\n", len); + /* Notify the the IEEE802.15.4 MAC that we have data to send. */ -#ifndef CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 - if (len >= CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD) - { - /* Try to compress the headers */ + netdev_txnotify_dev(dev); -#if defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC1) - sixlowpan_compresshdr_hc1(dev, &dest); -#elif defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC06) - sixlowpan_compresshdr_hc06(dev, &dest); -#else -# error No compression specified -#endif - } - else -#endif /* !CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 */ - { - /* Small.. use IPv6 dispatch (no compression) */ - - sixlowpan_compress_ipv6hdr(ieee, ipv6); - } - - ninfo("Header of len %d\n", ieee->i_rime_hdrlen); - - rimeaddr_copy(&ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER], &dest); - - /* Pre-calculate frame header length. */ - - framer_hdrlen = sixlowpan_hdrlen(ieee, ieee->i_panid); - if (framer_hdrlen < 0) - { - /* Failed to determine the size of the header failed. */ - - nerr("ERROR: sixlowpan_framecreate() failed: %d\n", framer_hdrlen); - return framer_hdrlen; - } - - /* Check if we need to fragment the packet into several frames */ - - if ((int)len - (int)ieee->i_uncomp_hdrlen > - (int)CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - - (int)ieee->i_rime_hdrlen) - { -#if CONFIG_NET_6LOWPAN_FRAG - /* qhead will hold the generated frames; Subsequent frames will be - * added at qtail. - */ - - FAR struct iob_s *qhead; - FAR struct iob_s *qtail; - - /* The outbound IPv6 packet is too large to fit into a single 15.4 - * packet, so we fragment it into multiple packets and send them. - * The first fragment contains frag1 dispatch, then - * IPv6/HC1/HC06/HC_UDP dispatchs/headers. - * The following fragments contain only the fragn dispatch. - */ - - ninfo("Fragmentation sending packet len %d\n", len); - - /* Allocate an IOB to hold the first fragment, waiting if necessary. */ - - iob = iob_alloc(false); - DEBUGASSERT(iob != NULL); - - /* Create 1st Fragment */ -# warning Missing logic - - /* Move HC1/HC06/IPv6 header */ -# warning Missing logic - - /* FRAG1 dispatch + header - * Note that the length is in units of 8 bytes - */ -# warning Missing logic - - /* Copy payload and send */ -# warning Missing logic - - /* Check TX result. */ -# warning Missing logic - - /* Set outlen to what we already sent from the IP payload */ -# warning Missing logic - - /* Add the first frame to the IOB queue */ - - qhead = iob; - qtail = iob; - iob->io_flink = NULL; - - /* Create following fragments - * Datagram tag is already in the buffer, we need to set the - * FRAGN dispatch and for each fragment, the offset - */ -# warning Missing logic - - while (outlen < len) - { - /* Allocate an IOB to hold the next fragment, waiting if - * necessary. + /* Wait for the send to complete or an error to occur: NOTES: (1) + * net_lockedwait will also terminate if a signal is received, (2) interrupts + * may be disabled! They will be re-enabled while the task sleeps and + * automatically re-enabled when the task restarts. */ - iob = iob_alloc(false); - DEBUGASSERT(iob != NULL); + ret = net_lockedwait(&sinfo.s_waitsem); + if (ret < 0) + { + sinfo.s_result = -get_errno(); + } - /* Copy payload */ -# warning Missing logic + /* Make sure that no further interrupts are processed */ - ninfo("sixlowpan output: fragment offset %d, len %d, tag %d\n", - outlen >> 3, g_rime_payloadlen, g_mytag); - - /* Add the next frame to the tail of the IOB queue */ - - qtail->io_flink = iob; - iob->io_flink = NULL; - - /* Check tx result. */ -# warning Missing logic + devif_dev_callback_free(dev, sinfo.s_cb); } - - /* Send the list of frames */ - - return sixlowpan_send_frame(ieee, qhead); -#else - nerr("ERROR: Packet too large: %d\n", len); - nerr(" Cannot to be sent without fragmentation support\n"); - nerr(" dropping packet\n"); - - return -E2BIG; -#endif } - else - { - /* The packet does not need to be fragmented just copy the "payload" - * and send in one frame. - */ - /* Allocate an IOB to hold the frame, waiting if necessary. */ + sem_destroy(&sinfo.s_waitsem); + net_unlock(); - iob = iob_alloc(false); - DEBUGASSERT(iob != NULL); - - /* Format the single frame */ -# warning Missing logic - - /* Send the single frame */ - - iob->io_flink = NULL; - return sixlowpan_send_frame(ieee, iob); - } + return (sinfo.s_result < 0 ? sinfo.s_result : len); } #endif /* CONFIG_NET_6LOWPAN */ diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c index 9928bc3d115..ba11700ab44 100644 --- a/net/sixlowpan/sixlowpan_tcpsend.c +++ b/net/sixlowpan/sixlowpan_tcpsend.c @@ -44,8 +44,6 @@ #include #include "nuttx/net/netdev.h" -#include "nuttx/net/tcp.h" -#include "nuttx/net/sixlowpan.h" #include "netdev/netdev.h" #include "socket/socket.h" @@ -87,7 +85,8 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, FAR struct tcp_conn_s *conn; FAR struct net_driver_s *dev; struct ipv6tcp_hdr_s ipv6tcp; - struct rimeaddr_s dest; + struct rimeaddr_s destmac; + uint16_t timeout; int ret; DEBUGASSERT(psock != NULL && psock->s_crefs > 0); @@ -128,14 +127,22 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, #ifdef CONFIG_NETDEV_MULTINIC dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr); - if (dev == NULL || dev->d_lltype != NET_LL_IEEE805154) +#ifdef CONFIG_NETDEV_MULTILINK + if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) +#else + if (dev == NULL) +#endif { nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n"); return (ssize_t)-ENETUNREACH; } #else dev = netdev_findby_ipv6addr(conn->u.ipv6.raddr); +#ifdef CONFIG_NETDEV_MULTILINK + if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) +#else if (dev == NULL) +#endif { nwarn("WARNING: Not routable\n"); return (ssize_t)-ENETUNREACH; @@ -167,13 +174,22 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, * packet. */ +#ifdef CONFIG_NET_SOCKOPTS + timeout = psock->s_sndtimeo; +#else + timeout = 0; +#endif + ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6tcp, - buf, len, &dest); + buf, len, &destmac, timeout); if (ret < 0) { nerr("ERROR: sixlowpan_send() failed: %d\n", ret); } + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); return ret; } diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c index 9946516e009..3b17d00767d 100644 --- a/net/sixlowpan/sixlowpan_udpsend.c +++ b/net/sixlowpan/sixlowpan_udpsend.c @@ -44,8 +44,6 @@ #include #include "nuttx/net/netdev.h" -#include "nuttx/net/udp.h" -#include "nuttx/net/sixlowpan.h" #include "netdev/netdev.h" #include "socket/socket.h" @@ -87,7 +85,8 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, FAR struct udp_conn_s *conn; FAR struct net_driver_s *dev; struct ipv6udp_hdr_s ipv6udp; - struct rimeaddr_s dest; + struct rimeaddr_s destmac; + uint16_t timeout; int ret; DEBUGASSERT(psock != NULL && psock->s_crefs > 0); @@ -129,14 +128,22 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, #ifdef CONFIG_NETDEV_MULTINIC dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr); - if (dev == NULL || dev->d_lltype != NET_LL_IEEE805154) +#ifdef CONFIG_NETDEV_MULTILINK + if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) +#else + if (dev == NULL) +#endif { nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n"); return (ssize_t)-ENETUNREACH; } #else dev = netdev_findby_ipv6addr(conn->u.ipv6.raddr); +#ifdef CONFIG_NETDEV_MULTILINK + if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) +#else if (dev == NULL) +#endif { nwarn("WARNING: Not routable\n"); return (ssize_t)-ENETUNREACH; @@ -168,13 +175,22 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, * packet. */ +#ifdef CONFIG_NET_SOCKOPTS + timeout = psock->s_sndtimeo; +#else + timeout = 0; +#endif + ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp, - buf, len, &dest); + buf, len, &destmac, timeout); if (ret < 0) { nerr("ERROR: sixlowpan_send() failed: %d\n", ret); } + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); return ret; } diff --git a/net/sixlowpan/sixlowpan_utils.c b/net/sixlowpan/sixlowpan_utils.c index f00eaeae4c3..f6ad77c68b1 100644 --- a/net/sixlowpan/sixlowpan_utils.c +++ b/net/sixlowpan/sixlowpan_utils.c @@ -44,15 +44,17 @@ * SUCH DAMAGE. * ****************************************************************************/ -/* Frame Organization: + +/* Frame Organization. The IOB data is retained in the io_data[] field of the + * IOB structure like: * * Content Offset * +------------------+ 0 * | Frame Header | - * +------------------+ i_dataoffset + * +------------------+ g_dataoffset * | Procotol Headers | * | Data Payload | - * +------------------+ i_framelen + * +------------------+ iob->io_len * | Unused | * +------------------+ CONFIG_NET_6LOWPAN_FRAMELEN */ @@ -66,8 +68,6 @@ #include #include -#include "nuttx/net/sixlowpan.h" - #include "sixlowpan/sixlowpan_internal.h" #ifdef CONFIG_NET_6LOWPAN @@ -84,13 +84,12 @@ * ****************************************************************************/ -int sixlowpan_frame_hdralloc(FAR struct ieee802154_driver_s *ieee, - int size) +int sixlowpan_frame_hdralloc(FAR struct iob_s *iob, int size) { - if (size <= FRAME_REMAINING(ieee)) + if (size <= FRAME_REMAINING(iob)) { - ieee->i_dataoffset += size; - ieee->i_framelen += size; + g_dataoffset += size; + iob->io_len += size; return OK; } diff --git a/net/socket/Make.defs b/net/socket/Make.defs index cfb6233bd1f..6f433cd97a8 100644 --- a/net/socket/Make.defs +++ b/net/socket/Make.defs @@ -42,7 +42,10 @@ SOCK_CSRCS += net_dupsd2.c net_clone.c net_poll.c net_vfcntl.c # TCP/IP support ifeq ($(CONFIG_NET_TCP),y) -SOCK_CSRCS += listen.c accept.c net_monitor.c +SOCK_CSRCS += listen.c accept.c +ifneq ($(CONFIG_NET_TCP_NO_STACK),y) +SOCK_CSRCS += net_monitor.c +endif # Local Unix domain support diff --git a/net/socket/accept.c b/net/socket/accept.c index 4bf35dc7f21..ec7385b4f24 100644 --- a/net/socket/accept.c +++ b/net/socket/accept.c @@ -54,6 +54,7 @@ #include "tcp/tcp.h" #include "local/local.h" #include "socket/socket.h" +#include "usrsock/usrsock.h" /**************************************************************************** * Public Functions @@ -129,7 +130,9 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen, FAR struct socket *newsock) { int errcode; +#ifdef NET_TCP_HAVE_STACK int ret; +#endif DEBUGASSERT(psock != NULL); @@ -141,6 +144,13 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, if (psock->s_type != SOCK_STREAM) { +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { +#warning "Missing logic" + } +#endif + errcode = EOPNOTSUPP; goto errout; } @@ -238,6 +248,7 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, else #endif { +#ifdef NET_TCP_HAVE_STACK /* Perform the local accept operation (with the network locked) */ net_lock(); @@ -267,6 +278,10 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, } net_unlock(); +#else + errcode = EOPNOTSUPP; + goto errout; +#endif /* NET_TCP_HAVE_STACK */ } #endif /* CONFIG_NET_TCP */ @@ -278,8 +293,10 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, leave_cancellation_point(); return OK; +#ifdef NET_TCP_HAVE_STACK errout_after_accept: psock_close(newsock); +#endif errout: set_errno(errcode); diff --git a/net/socket/bind.c b/net/socket/bind.c index 1197460ce79..8ffc1274e8b 100644 --- a/net/socket/bind.c +++ b/net/socket/bind.c @@ -46,6 +46,7 @@ #include #include #include +#include #ifdef CONFIG_NET_PKT # include @@ -60,6 +61,7 @@ #include "udp/udp.h" #include "pkt/pkt.h" #include "local/local.h" +#include "usrsock/usrsock.h" /**************************************************************************** * Private Functions @@ -212,6 +214,20 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr, switch (psock->s_type) { +#ifdef CONFIG_NET_USRSOCK + case SOCK_USRSOCK_TYPE: + { + FAR struct usrsock_conn_s *conn = psock->s_conn; + + DEBUGASSERT(conn); + + /* Perform the usrsock bind operation */ + + ret = usrsock_bind(conn, addr, addrlen); + } + break; +#endif + #ifdef CONFIG_NET_PKT case SOCK_RAW: ret = pkt_bind(psock->s_conn, lladdr); @@ -243,9 +259,13 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr, else #endif { +#ifdef NET_TCP_HAVE_STACK /* Bind the TCP/IP connection structure */ ret = tcp_bind(psock->s_conn, addr); +#else + ret = -ENOSYS; +#endif } #endif /* CONFIG_NET_TCP */ @@ -284,9 +304,13 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr, else #endif { +#ifdef NET_UDP_HAVE_STACK /* Bind the UDPP/IP connection structure */ ret = udp_bind(psock->s_conn, addr); +#else + ret = -ENOSYS; +#endif } #endif /* CONFIG_NET_UDP */ diff --git a/net/socket/connect.c b/net/socket/connect.c index 6a0140ea55a..dd3ee97e096 100644 --- a/net/socket/connect.c +++ b/net/socket/connect.c @@ -62,12 +62,13 @@ #include "udp/udp.h" #include "local/local.h" #include "socket/socket.h" +#include "usrsock/usrsock.h" /**************************************************************************** * Private Types ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK struct tcp_connect_s { FAR struct tcp_conn_s *tc_conn; /* Reference to TCP connection structure */ @@ -82,7 +83,7 @@ struct tcp_connect_s * Private Function Prototypes ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static inline int psock_setup_callbacks(FAR struct socket *psock, FAR struct tcp_connect_s *pstate); static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate, @@ -92,7 +93,7 @@ static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, uint16_t flags); static inline int psock_tcp_connect(FAR struct socket *psock, FAR const struct sockaddr *addr); -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Private Functions @@ -101,7 +102,7 @@ static inline int psock_tcp_connect(FAR struct socket *psock, * Name: psock_setup_callbacks ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static inline int psock_setup_callbacks(FAR struct socket *psock, FAR struct tcp_connect_s *pstate) { @@ -137,13 +138,13 @@ static inline int psock_setup_callbacks(FAR struct socket *psock, return ret; } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Name: psock_teardown_callbacks ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate, int status) { @@ -165,7 +166,7 @@ static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate, net_stopmonitor(conn); } } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Name: psock_connect_interrupt @@ -187,7 +188,7 @@ static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate, * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) @@ -299,7 +300,7 @@ static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, else #endif { - pstate->tc_conn->mss = TCP_IPv4_INITIAL_MSS(dev); + pstate->tc_conn->mss = TCP_IPv6_INITIAL_MSS(dev); } #endif /* CONFIG_NET_IPv6 */ @@ -322,7 +323,7 @@ static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, return flags; } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Name: psock_tcp_connect @@ -342,7 +343,7 @@ static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static inline int psock_tcp_connect(FAR struct socket *psock, FAR const struct sockaddr *addr) { @@ -434,7 +435,7 @@ static inline int psock_tcp_connect(FAR struct socket *psock, net_unlock(); return ret; } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Public Functions @@ -512,7 +513,8 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen) { FAR const struct sockaddr_in *inaddr = (FAR const struct sockaddr_in *)addr; -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) || \ + defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_USRSOCK) int ret; #endif int errcode; @@ -570,6 +572,13 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, #endif default: +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + break; + } +#endif + DEBUGPANIC(); errcode = EAFNOSUPPORT; goto errout; @@ -608,9 +617,13 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, else #endif { +#ifdef NET_TCP_HAVE_STACK /* Connect the TCP/IP socket */ ret = psock_tcp_connect(psock, addr); +#else + ret = -ENOSYS; +#endif } #endif /* CONFIG_NET_TCP */ @@ -642,6 +655,7 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, else #endif { +#ifdef NET_UDP_HAVE_STACK ret = udp_connect(psock->s_conn, addr); if (ret < 0 || addr == NULL) { @@ -651,6 +665,9 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, { psock->s_flags |= _SF_CONNECTED; } +#else + ret = -ENOSYS; +#endif } #endif /* CONFIG_NET_UDP */ @@ -663,6 +680,19 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, break; #endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */ +#ifdef CONFIG_NET_USRSOCK + case SOCK_USRSOCK_TYPE: + { + ret = usrsock_connect(psock, addr, addrlen); + if (ret < 0) + { + errcode = -ret; + goto errout; + } + } + break; +#endif /* CONFIG_NET_USRSOCK */ + default: errcode = EBADF; goto errout; diff --git a/net/socket/getsockname.c b/net/socket/getsockname.c index 7bf87c29d12..703136e0d9e 100644 --- a/net/socket/getsockname.c +++ b/net/socket/getsockname.c @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -54,6 +55,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "socket/socket.h" +#include "usrsock/usrsock.h" #ifdef CONFIG_NET @@ -92,7 +94,7 @@ int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen) { FAR struct net_driver_s *dev; -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) +#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) FAR struct sockaddr_in *outaddr = (FAR struct sockaddr_in *)addr; #endif #ifdef CONFIG_NETDEV_MULTINIC @@ -116,7 +118,7 @@ int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, switch (psock->s_type) { -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK case SOCK_STREAM: { FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn; @@ -129,7 +131,7 @@ int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, break; #endif -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK case SOCK_DGRAM: { FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn; @@ -171,7 +173,7 @@ int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, /* Set the address family and the IP address */ -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) +#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) outaddr->sin_family = AF_INET; outaddr->sin_addr.s_addr = dev->d_ipaddr; *addrlen = sizeof(struct sockaddr_in); @@ -215,7 +217,7 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen) { FAR struct net_driver_s *dev; -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) +#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) FAR struct sockaddr_in6 *outaddr = (FAR struct sockaddr_in6 *)addr; #endif #ifdef CONFIG_NETDEV_MULTINIC @@ -239,7 +241,7 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, switch (psock->s_type) { -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK case SOCK_STREAM: { FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn; @@ -252,7 +254,7 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, break; #endif -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK case SOCK_DGRAM: { FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn; @@ -294,7 +296,7 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, /* Set the address family and the IP address */ -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) +#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) outaddr->sin6_family = AF_INET6; memcpy(outaddr->sin6_addr.in6_u.u6_addr8, dev->d_ipv6addr, 16); *addrlen = sizeof(struct sockaddr_in6); @@ -371,6 +373,26 @@ int getsockname(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) } #endif +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + FAR struct usrsock_conn_s *conn = psock->s_conn; + + DEBUGASSERT(conn); + + /* Handle usrsock getsockname */ + + ret = usrsock_getsockname(conn, addr, addrlen); + if (ret < 0) + { + errcode = -ret; + goto errout; + } + + return OK; + } +#endif + /* Handle by address domain */ switch (psock->s_domain) diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c index 5072f02067c..ab15d511aaf 100644 --- a/net/socket/getsockopt.c +++ b/net/socket/getsockopt.c @@ -43,9 +43,12 @@ #include #include #include +#include +#include #include #include "socket/socket.h" +#include "usrsock/usrsock.h" #include "utils/utils.h" /**************************************************************************** @@ -106,6 +109,40 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option, goto errout; } +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + FAR struct usrsock_conn_s *conn = psock->s_conn; + int ret; + + DEBUGASSERT(conn); + + /* Some of the socket options are handled from this function. */ + + switch (option) + { + case SO_TYPE: /* Type can be read from NuttX psock structure. */ + case SO_RCVTIMEO: /* Rx timeouts can be handled at NuttX side, thus + * simplify daemon implementation. */ + case SO_SNDTIMEO: /* Rx timeouts can be handled at NuttX side, thus + * simplify daemon implementation. */ + break; + + default: /* Other options are passed to usrsock daemon. */ + { + ret = usrsock_getsockopt(conn, level, option, value, value_len); + if (ret < 0) + { + errcode = -ret; + goto errout; + } + + return OK; + } + } + } +#endif + /* Process the option */ switch (option) @@ -159,6 +196,20 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option, goto errout; } +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + FAR struct usrsock_conn_s *conn = psock->s_conn; + + /* Return the actual socket type */ + + *(int*)value = conn->type; + *value_len = sizeof(int); + + break; + } +#endif + /* Return the socket type */ *(FAR int *)value = psock->s_type; diff --git a/net/socket/listen.c b/net/socket/listen.c index 0d91ccb5867..3b0189d019d 100644 --- a/net/socket/listen.c +++ b/net/socket/listen.c @@ -48,6 +48,7 @@ #include "tcp/tcp.h" #include "local/local.h" #include "socket/socket.h" +#include "usrsock/usrsock.h" /**************************************************************************** * Public Functions @@ -92,6 +93,13 @@ int psock_listen(FAR struct socket *psock, int backlog) if (psock->s_type != SOCK_STREAM || !psock->s_conn) { +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { +#warning "Missing logic" + } +#endif + errcode = EOPNOTSUPP; goto errout; } @@ -118,6 +126,7 @@ int psock_listen(FAR struct socket *psock, int backlog) else #endif { +#ifdef NET_TCP_HAVE_STACK FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)psock->s_conn; @@ -143,6 +152,10 @@ int psock_listen(FAR struct socket *psock, int backlog) */ tcp_listen(conn); +#else + errcode = EOPNOTSUPP; + goto errout; +#endif /* NET_TCP_HAVE_STACK */ } #endif /* CONFIG_NET_TCP */ diff --git a/net/socket/net_clone.c b/net/socket/net_clone.c index 5398c614fdf..83a7c5150c4 100644 --- a/net/socket/net_clone.c +++ b/net/socket/net_clone.c @@ -51,6 +51,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "socket/socket.h" +#include "usrsock/usrsock.h" /**************************************************************************** * Public Functions @@ -96,7 +97,7 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2) DEBUGASSERT(psock2->s_conn); psock2->s_crefs = 1; /* One reference on the new socket itself */ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK if (psock2->s_type == SOCK_STREAM) { FAR struct tcp_conn_s *conn = psock2->s_conn; @@ -105,7 +106,7 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2) } else #endif -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK if (psock2->s_type == SOCK_DGRAM) { FAR struct udp_conn_s *conn = psock2->s_conn; @@ -113,6 +114,15 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2) conn->crefs++; } else +#endif +#ifdef CONFIG_NET_USRSOCK + if (psock2->s_type == SOCK_USRSOCK_TYPE) + { + FAR struct usrsock_conn_s *conn = psock2->s_conn; + DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255); + conn->crefs++; + } + else #endif { nerr("ERROR: Unsupported type: %d\n", psock2->s_type); diff --git a/net/socket/net_close.c b/net/socket/net_close.c index ba0fb85dc1d..6bbc01b725f 100644 --- a/net/socket/net_close.c +++ b/net/socket/net_close.c @@ -67,12 +67,13 @@ #include "pkt/pkt.h" #include "local/local.h" #include "socket/socket.h" +#include "usrsock/usrsock.h" /**************************************************************************** * Private Types ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK struct tcp_close_s { FAR struct devif_callback_s *cl_cb; /* Reference to TCP callback instance */ @@ -106,7 +107,7 @@ struct tcp_close_s * ****************************************************************************/ -#if defined(CONFIG_NET_TCP) && defined(CONFIG_NET_SOLINGER) +#if defined(NET_TCP_HAVE_STACK) && defined(CONFIG_NET_SOLINGER) static inline int close_timeout(FAR struct tcp_close_s *pstate) { FAR struct socket *psock = 0; @@ -132,7 +133,7 @@ static inline int close_timeout(FAR struct tcp_close_s *pstate) return FALSE; } -#endif /* CONFIG_NET_SOCKOPTS && CONFIG_NET_SOLINGER */ +#endif /* NET_TCP_HAVE_STACK && CONFIG_NET_SOLINGER */ /**************************************************************************** * Function: netclose_interrupt @@ -151,7 +152,7 @@ static inline int close_timeout(FAR struct tcp_close_s *pstate) * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static uint16_t netclose_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) @@ -256,7 +257,7 @@ end_wait: return 0; #endif } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Function: netclose_txnotify @@ -274,7 +275,7 @@ end_wait: * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static inline void netclose_txnotify(FAR struct socket *psock, FAR struct tcp_conn_s *conn) { @@ -313,7 +314,7 @@ static inline void netclose_txnotify(FAR struct socket *psock, } #endif /* CONFIG_NET_IPv6 */ } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Function: netclose_disconnect @@ -332,7 +333,7 @@ static inline void netclose_txnotify(FAR struct socket *psock, * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static inline int netclose_disconnect(FAR struct socket *psock) { struct tcp_close_s state; @@ -451,7 +452,7 @@ static inline int netclose_disconnect(FAR struct socket *psock) net_unlock(); return ret; } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Function: local_close @@ -557,6 +558,7 @@ int psock_close(FAR struct socket *psock) else #endif { +#ifdef NET_TCP_HAVE_STACK FAR struct tcp_conn_s *conn = psock->s_conn; /* Is this the last reference to the connection structure @@ -592,6 +594,7 @@ int psock_close(FAR struct socket *psock) conn->crefs--; } +#endif /* NET_TCP_HAVE_STACK */ } #endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */ } @@ -617,6 +620,7 @@ int psock_close(FAR struct socket *psock) else #endif { +#ifdef NET_UDP_HAVE_STACK FAR struct udp_conn_s *conn = psock->s_conn; /* Is this the last reference to the connection structure @@ -636,6 +640,7 @@ int psock_close(FAR struct socket *psock) conn->crefs--; } +#endif /* NET_UDP_HAVE_STACK */ } #endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */ } @@ -668,6 +673,44 @@ int psock_close(FAR struct socket *psock) break; #endif +#ifdef CONFIG_NET_USRSOCK + case SOCK_USRSOCK_TYPE: + { + FAR struct usrsock_conn_s *conn = psock->s_conn; + + /* Is this the last reference to the connection structure (there + * could be more if the socket was dup'ed). + */ + + if (conn->crefs <= 1) + { + /* Yes... inform user-space daemon of socket close. */ + + errcode = usrsock_close(conn); + + /* Free the connection structure */ + + conn->crefs = 0; + usrsock_free(psock->s_conn); + + if (errcode < 0) + { + /* Return with error code, but free resources. */ + + errcode = -errcode; + goto errout_with_psock; + } + } + else + { + /* No.. Just decrement the reference count */ + + conn->crefs--; + } + } + break; +#endif + default: errcode = EBADF; goto errout; @@ -679,7 +722,7 @@ int psock_close(FAR struct socket *psock) sock_release(psock); return OK; -#ifdef CONFIG_NET_TCP +#if defined(NET_TCP_HAVE_STACK) || defined(CONFIG_NET_USRSOCK) errout_with_psock: sock_release(psock); #endif diff --git a/net/socket/net_monitor.c b/net/socket/net_monitor.c index cee6a13cd94..d44a6fe5152 100644 --- a/net/socket/net_monitor.c +++ b/net/socket/net_monitor.c @@ -50,6 +50,8 @@ #include "tcp/tcp.h" #include "socket/socket.h" +#ifdef NET_TCP_HAVE_STACK + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -345,4 +347,6 @@ void net_lostconnection(FAR struct socket *psock, uint16_t flags) net_unlock(); } +#endif /* NET_TCP_HAVE_STACK */ + #endif /* CONFIG_NET && CONFIG_NET_TCP */ diff --git a/net/socket/net_poll.c b/net/socket/net_poll.c index e534e9d0220..0fe2b23db15 100644 --- a/net/socket/net_poll.c +++ b/net/socket/net_poll.c @@ -45,6 +45,7 @@ #include "udp/udp.h" #include "local/local.h" #include "socket/socket.h" +#include "usrsock/usrsock.h" #if defined(CONFIG_NET) && !defined(CONFIG_DISABLE_POLL) @@ -57,7 +58,8 @@ */ #undef HAVE_NET_POLL -#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL) || defined(HAVE_LOCAL_POLL) +#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL) || \ + defined(HAVE_LOCAL_POLL) || defined(CONFIG_NET_USRSOCK) # define HAVE_NET_POLL 1 #endif @@ -233,6 +235,15 @@ int psock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup) #else int ret; +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + /* Perform usrsock setup/teardown. */ + + return usrsock_poll(psock, fds, setup); + } +#endif + /* Check if we are setting up or tearing down the poll */ if (setup) diff --git a/net/socket/net_sendfile.c b/net/socket/net_sendfile.c index 617bce53972..81f527abe76 100644 --- a/net/socket/net_sendfile.c +++ b/net/socket/net_sendfile.c @@ -72,6 +72,8 @@ #include "tcp/tcp.h" #include "socket/socket.h" +#ifdef NET_TCP_HAVE_STACK + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -615,6 +617,21 @@ ssize_t net_sendfile(int outfd, struct file *infile, off_t *offset, goto errout; } +#ifdef CONFIG_NET_USRSOCK + /* If this is a usrsock socket, use generic sendfile implementation. */ + + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + int infd; + + list = sched_getfiles(); + DEBUGASSERT(list != NULL); + + infd = infile - list->fl_files; + return lib_sendfile(outfd, infd, offset, count); + } +#endif /* CONFIG_NET_USRSOCK */ + /* If this is an un-connected socket, then return ENOTCONN */ if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) @@ -776,4 +793,6 @@ errout: } } +#endif /* NET_TCP_HAVE_STACK */ + #endif /* CONFIG_NET && CONFIG_NET_TCP */ diff --git a/net/socket/net_timeo.c b/net/socket/net_timeo.c index 47099d205d5..81b7123a312 100644 --- a/net/socket/net_timeo.c +++ b/net/socket/net_timeo.c @@ -78,6 +78,7 @@ int net_timeo(systime_t start_time, socktimeo_t timeo) { return TRUE; } + return FALSE; } diff --git a/net/socket/net_vfcntl.c b/net/socket/net_vfcntl.c index b260edb5b0a..79df78379bc 100644 --- a/net/socket/net_vfcntl.c +++ b/net/socket/net_vfcntl.c @@ -49,6 +49,7 @@ #include #include #include "socket/socket.h" +#include "usrsock/usrsock.h" #if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 @@ -164,6 +165,13 @@ int net_vfcntl(int sockfd, int cmd, va_list ap) ret |= O_NONBLOCK; } #endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD || CONFIG_NET_UDP_READAHEAD */ + +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE && _SS_ISNONBLOCK(psock->s_flags)) + { + ret |= O_NONBLOCK; + } +#endif } break; @@ -178,7 +186,7 @@ int net_vfcntl(int sockfd, int cmd, va_list ap) { #if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_TCP_READAHEAD) || \ - defined(CONFIG_NET_UDP_READAHEAD) + defined(CONFIG_NET_UDP_READAHEAD) || defined(CONFIG_NET_USRSOCK) /* Non-blocking is the only configurable option. And it applies * only Unix domain sockets and to read operations on TCP/IP * and UDP/IP sockets when read-ahead is enabled. @@ -213,7 +221,22 @@ int net_vfcntl(int sockfd, int cmd, va_list ap) } else #endif -#endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD || CONFIG_NET_UDP_READAHEAD */ +#if defined(CONFIG_NET_USRSOCK) + if (psock->s_type == SOCK_USRSOCK_TYPE) /* usrsock socket */ + { + if ((mode & O_NONBLOCK) != 0) + { + psock->s_flags |= _SF_NONBLOCK; + } + else + { + psock->s_flags &= ~_SF_NONBLOCK; + } + } + else +#endif +#endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD || + CONFIG_NET_UDP_READAHEAD || CONFIG_NET_USRSOCK */ { nerr("ERROR: Non-blocking not supported for this socket\n"); } diff --git a/net/socket/recvfrom.c b/net/socket/recvfrom.c index 64789b06720..fc713375cbd 100644 --- a/net/socket/recvfrom.c +++ b/net/socket/recvfrom.c @@ -72,6 +72,7 @@ #include "pkt/pkt.h" #include "local/local.h" #include "socket/socket.h" +#include "usrsock/usrsock.h" /**************************************************************************** * Pre-processor Definitions @@ -90,7 +91,8 @@ * Private Types ****************************************************************************/ -#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) || defined(CONFIG_NET_PKT) +#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK) \ + || defined(CONFIG_NET_PKT) struct recvfrom_s { FAR struct socket *rf_sock; /* The parent socket structure */ @@ -106,7 +108,7 @@ struct recvfrom_s ssize_t rf_recvlen; /* The received length */ int rf_result; /* Success:OK, failure:negated errno */ }; -#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */ +#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */ /**************************************************************************** * Private Functions @@ -129,7 +131,8 @@ struct recvfrom_s * ****************************************************************************/ -#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) || defined(CONFIG_NET_PKT) +#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK) \ + || defined(CONFIG_NET_PKT) static inline void recvfrom_add_recvlen(FAR struct recvfrom_s *pstate, size_t recvlen) @@ -143,7 +146,7 @@ static inline void recvfrom_add_recvlen(FAR struct recvfrom_s *pstate, pstate->rf_buffer += recvlen; pstate->rf_buflen -= recvlen; } -#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP || CONFIG_NET_PKT */ +#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK || CONFIG_NET_PKT */ /**************************************************************************** * Function: recvfrom_newdata @@ -163,7 +166,7 @@ static inline void recvfrom_add_recvlen(FAR struct recvfrom_s *pstate, * ****************************************************************************/ -#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) +#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK) static size_t recvfrom_newdata(FAR struct net_driver_s *dev, FAR struct recvfrom_s *pstate) { @@ -191,7 +194,7 @@ static size_t recvfrom_newdata(FAR struct net_driver_s *dev, return recvlen; } -#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */ +#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */ /**************************************************************************** * Function: recvfrom_newpktdata @@ -255,7 +258,7 @@ static void recvfrom_newpktdata(FAR struct net_driver_s *dev, * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static inline void recvfrom_newtcpdata(FAR struct net_driver_s *dev, FAR struct recvfrom_s *pstate) { @@ -307,7 +310,7 @@ static inline void recvfrom_newtcpdata(FAR struct net_driver_s *dev, dev->d_len = 0; } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Function: recvfrom_newudpdata @@ -327,7 +330,7 @@ static inline void recvfrom_newtcpdata(FAR struct net_driver_s *dev, * ****************************************************************************/ -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK static inline void recvfrom_newudpdata(FAR struct net_driver_s *dev, FAR struct recvfrom_s *pstate) { @@ -339,7 +342,7 @@ static inline void recvfrom_newudpdata(FAR struct net_driver_s *dev, dev->d_len = 0; } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_UDP_HAVE_STACK */ /**************************************************************************** * Function: recvfrom_tcpreadahead @@ -359,7 +362,7 @@ static inline void recvfrom_newudpdata(FAR struct net_driver_s *dev, * ****************************************************************************/ -#if defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCP_READAHEAD) +#if defined(NET_TCP_HAVE_STACK) && defined(CONFIG_NET_TCP_READAHEAD) static inline void recvfrom_tcpreadahead(struct recvfrom_s *pstate) { FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pstate->rf_sock->s_conn; @@ -419,9 +422,9 @@ static inline void recvfrom_tcpreadahead(struct recvfrom_s *pstate) } } } -#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK && CONFIG_NET_TCP_READAHEAD */ -#if defined(CONFIG_NET_UDP) && defined(CONFIG_NET_UDP_READAHEAD) +#if defined(NET_UDP_HAVE_STACK) && defined(CONFIG_NET_UDP_READAHEAD) static inline void recvfrom_udpreadahead(struct recvfrom_s *pstate) { @@ -526,7 +529,7 @@ out: * ****************************************************************************/ -#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) +#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK) #ifdef CONFIG_NET_SOCKOPTS static int recvfrom_timeout(struct recvfrom_s *pstate) { @@ -581,7 +584,7 @@ static int recvfrom_timeout(struct recvfrom_s *pstate) return FALSE; } #endif /* CONFIG_NET_SOCKOPTS */ -#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */ +#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */ /**************************************************************************** * Function: recvfrom_pktsender @@ -684,7 +687,7 @@ static uint16_t recvfrom_pktinterrupt(FAR struct net_driver_s *dev, * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static inline void recvfrom_tcpsender(FAR struct net_driver_s *dev, FAR struct recvfrom_s *pstate) { @@ -735,7 +738,7 @@ static inline void recvfrom_tcpsender(FAR struct net_driver_s *dev, } #endif /* CONFIG_NET_IPv4 */ } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Function: recvfrom_tcpinterrupt @@ -757,7 +760,7 @@ static inline void recvfrom_tcpsender(FAR struct net_driver_s *dev, * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static uint16_t recvfrom_tcpinterrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) @@ -958,7 +961,7 @@ static uint16_t recvfrom_tcpinterrupt(FAR struct net_driver_s *dev, return flags; } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Function: recvfrom_udpsender @@ -978,7 +981,7 @@ static uint16_t recvfrom_tcpinterrupt(FAR struct net_driver_s *dev, * ****************************************************************************/ -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK static inline void recvfrom_udpsender(struct net_driver_s *dev, struct recvfrom_s *pstate) { /* Get the family from the packet type, IP address from the IP header, and @@ -1059,7 +1062,7 @@ static inline void recvfrom_udpsender(struct net_driver_s *dev, struct recvfrom_ } #endif /* CONFIG_NET_IPv4 */ } -#endif /* CONFIG_NET_UDP */ +#endif /* NET_UDP_HAVE_STACK */ /**************************************************************************** * Function: recvfrom_udp_terminate @@ -1076,7 +1079,7 @@ static inline void recvfrom_udpsender(struct net_driver_s *dev, struct recvfrom_ * ****************************************************************************/ -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK static void recvfrom_udp_terminate(FAR struct recvfrom_s *pstate, int result) { /* Don't allow any further UDP call backs. */ @@ -1095,7 +1098,7 @@ static void recvfrom_udp_terminate(FAR struct recvfrom_s *pstate, int result) sem_post(&pstate->rf_sem); } -#endif /* CONFIG_NET_UDP */ +#endif /* NET_UDP_HAVE_STACK */ /**************************************************************************** * Function: recvfrom_udp_interrupt @@ -1117,7 +1120,7 @@ static void recvfrom_udp_terminate(FAR struct recvfrom_s *pstate, int result) * ****************************************************************************/ -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK static uint16_t recvfrom_udp_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) @@ -1189,7 +1192,7 @@ static uint16_t recvfrom_udp_interrupt(FAR struct net_driver_s *dev, return flags; } -#endif /* CONFIG_NET_UDP */ +#endif /* NET_UDP_HAVE_STACK */ /**************************************************************************** * Function: recvfrom_init @@ -1210,7 +1213,8 @@ static uint16_t recvfrom_udp_interrupt(FAR struct net_driver_s *dev, * ****************************************************************************/ -#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) || defined(CONFIG_NET_PKT) +#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK) \ + || defined(CONFIG_NET_PKT) static void recvfrom_init(FAR struct socket *psock, FAR void *buf, size_t len, FAR struct sockaddr *infrom, FAR socklen_t *fromlen, @@ -1246,7 +1250,7 @@ static void recvfrom_init(FAR struct socket *psock, FAR void *buf, #define recvfrom_uninit(s) sem_destroy(&(s)->rf_sem) -#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */ +#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */ /**************************************************************************** * Function: recvfrom_result @@ -1265,7 +1269,8 @@ static void recvfrom_init(FAR struct socket *psock, FAR void *buf, * ****************************************************************************/ -#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) || defined(CONFIG_NET_PKT) +#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK) \ + || defined(CONFIG_NET_PKT) static ssize_t recvfrom_result(int result, struct recvfrom_s *pstate) { int save_errno = get_errno(); /* In case something we do changes it */ @@ -1294,7 +1299,7 @@ static ssize_t recvfrom_result(int result, struct recvfrom_s *pstate) return pstate->rf_recvlen; } -#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */ +#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */ /**************************************************************************** * Function: recvfromo_pkt_rxnotify @@ -1334,7 +1339,7 @@ static void recvfromo_pkt_rxnotify(FAR struct pkt_conn_s *conn) * ****************************************************************************/ -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK static inline void recvfrom_udp_rxnotify(FAR struct socket *psock, FAR struct udp_conn_s *conn) { @@ -1373,7 +1378,7 @@ static inline void recvfrom_udp_rxnotify(FAR struct socket *psock, } #endif /* CONFIG_NET_IPv6 */ } -#endif /* CONFIG_NET_UDP */ +#endif /* NET_UDP_HAVE_STACK */ /**************************************************************************** * Function: pkt_recvfrom @@ -1489,7 +1494,7 @@ errout_with_state: * ****************************************************************************/ -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, FAR struct sockaddr *from, FAR socklen_t *fromlen) { @@ -1607,7 +1612,7 @@ errout_with_state: recvfrom_uninit(&state); return ret; } -#endif /* CONFIG_NET_UDP */ +#endif /* NET_UDP_HAVE_STACK */ /**************************************************************************** * Function: tcp_recvfrom @@ -1629,7 +1634,7 @@ errout_with_state: * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, FAR struct sockaddr *from, FAR socklen_t *fromlen) { @@ -1785,7 +1790,7 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, recvfrom_uninit(&state); return (ssize_t)ret; } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Public Functions @@ -1880,6 +1885,22 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, goto errout; } +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + /* Perform the usrsock recvfrom operation */ + + ret = usrsock_recvfrom(psock, buf, len, from, fromlen); + if (ret < 0) + { + errcode = -ret; + goto errout; + } + + return ret; + } +#endif + /* If a 'from' address has been provided, verify that it is large * enough to hold this address family. */ @@ -1964,7 +1985,11 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, else #endif { +#ifdef NET_TCP_HAVE_STACK ret = tcp_recvfrom(psock, buf, len, from, fromlen); +#else + ret = -ENOSYS; +#endif } #endif /* CONFIG_NET_TCP */ } @@ -1989,7 +2014,11 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, else #endif { +#ifdef NET_UDP_HAVE_STACK ret = udp_recvfrom(psock, buf, len, from, fromlen); +#else + ret = -ENOSYS; +#endif } #endif /* CONFIG_NET_UDP */ } diff --git a/net/socket/send.c b/net/socket/send.c index fd37860a1a1..fb50549e86e 100644 --- a/net/socket/send.c +++ b/net/socket/send.c @@ -51,6 +51,7 @@ #include "sixlowpan/sixlowpan.h" #include "local/local.h" #include "socket/socket.h" +#include "usrsock/usrsock.h" /**************************************************************************** * Public Functions @@ -168,9 +169,14 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, #ifdef CONFIG_NETDEV_MULTINIC if (ret < 0) { - /* UDP/IP packet send */ + /* TCP/IP packet send */ ret = psock_tcp_send(psock, buf, len); +#ifdef NET_TCP_HAVE_STACK + ret = psock_tcp_send(psock, buf, len); +#else + ret = -ENOSYS; +#endif } #endif /* CONFIG_NETDEV_MULTINIC */ @@ -178,7 +184,11 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, /* Only TCP/IP packet send */ +#ifdef NET_TCP_HAVE_STACK ret = psock_tcp_send(psock, buf, len); +#else + ret = -ENOSYS; +#endif #endif /* CONFIG_NET_6LOWPAN */ } #endif /* CONFIG_NET_TCP */ @@ -216,6 +226,11 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, /* UDP/IP packet send */ ret = psock_udp_send(psock, buf, len); +#ifdef NET_UDP_HAVE_STACK + ret = psock_udp_send(psock, buf, len); +#else + ret = -ENOSYS; +#endif } #endif /* CONFIG_NETDEV_MULTINIC */ @@ -223,7 +238,11 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, /* Only UDP/IP packet send */ +#ifdef NET_UDP_HAVE_STACK ret = psock_udp_send(psock, buf, len); +#else + ret = -ENOSYS; +#endif #endif /* CONFIG_NET_6LOWPAN */ } #endif /* CONFIG_NET_UDP */ @@ -231,6 +250,14 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, break; #endif /* CONFIG_NET_UDP */ +#ifdef CONFIG_NET_USRSOCK + case SOCK_USRSOCK_TYPE: + { + ret = usrsock_sendto(psock, buf, len, NULL, 0); + } + break; +#endif /*CONFIG_NET_USRSOCK*/ + default: { /* EDESTADDRREQ. Signifies that the socket is not connection-mode @@ -243,6 +270,11 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, } leave_cancellation_point(); + if (ret < 0) + { + set_errno(-ret); + ret = ERROR; + } return ret; } diff --git a/net/socket/sendto.c b/net/socket/sendto.c index db51b73c79a..eba84f5cea6 100644 --- a/net/socket/sendto.c +++ b/net/socket/sendto.c @@ -51,6 +51,7 @@ #include "udp/udp.h" #include "local/local.h" #include "socket/socket.h" +#include "usrsock/usrsock.h" /**************************************************************************** * Public Functions @@ -126,7 +127,8 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, socklen_t tolen) { socklen_t minlen; -#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM) +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM) || \ + defined(CONFIG_NET_USRSOCK) ssize_t nsent; #endif int errcode; @@ -137,7 +139,8 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, if (!to || !tolen) { -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM) +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM) || \ + defined(CONFIG_NET_USRSOCK) return psock_send(psock, buf, len, flags); #else nerr("ERROR: No 'to' address\n"); @@ -146,6 +149,22 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, #endif } +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + /* Perform the usrsock sendto operation */ + + nsent = usrsock_sendto(psock, buf, len, to, tolen); + if (nsent < 0) + { + errcode = -nsent; + goto errout; + } + + return nsent; + } +#endif + /* Verify that a valid address has been provided */ switch (to->sa_family) @@ -218,7 +237,11 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, else #endif { +#ifdef NET_UDP_HAVE_STACK nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); +#else + nsent = -ENOSYS; +#endif } #endif /* CONFIG_NET_UDP */ diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c index cdcd8d2e851..fd41045f3e3 100644 --- a/net/socket/setsockopt.c +++ b/net/socket/setsockopt.c @@ -45,11 +45,14 @@ #include #include #include +#include +#include #include #include #include "socket/socket.h" +#include "usrsock/usrsock.h" #include "utils/utils.h" /**************************************************************************** @@ -115,6 +118,39 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option, goto errout; } +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + FAR struct usrsock_conn_s *conn = psock->s_conn; + int ret; + + DEBUGASSERT(conn); + + /* Some of the socket options are handled from this function. */ + + switch (option) + { + case SO_RCVTIMEO: /* Rx timeouts can be handled at NuttX side, thus + * simplify daemon implementation. */ + case SO_SNDTIMEO: /* Rx timeouts can be handled at NuttX side, thus + * simplify daemon implementation. */ + break; + + default: /* Other options are passed to usrsock daemon. */ + { + ret = usrsock_setsockopt(conn, level, option, value, value_len); + if (ret < 0) + { + errcode = -ret; + goto errout; + } + + return OK; + } + } + } +#endif + /* Process the option */ switch (option) diff --git a/net/socket/socket.c b/net/socket/socket.c index 56f6ddfe9c2..04d595a8315 100644 --- a/net/socket/socket.c +++ b/net/socket/socket.c @@ -52,6 +52,7 @@ #include "udp/udp.h" #include "pkt/pkt.h" #include "local/local.h" +#include "usrsock/usrsock.h" /**************************************************************************** * Private Functions @@ -65,7 +66,7 @@ * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK static int psock_tcp_alloc(FAR struct socket *psock) { /* Allocate the TCP connection structure */ @@ -90,7 +91,7 @@ static int psock_tcp_alloc(FAR struct socket *psock) psock->s_conn = conn; return OK; } -#endif /* CONFIG_NET_TCP */ +#endif /* NET_TCP_HAVE_STACK */ /**************************************************************************** * Name: psock_udp_alloc @@ -100,7 +101,7 @@ static int psock_tcp_alloc(FAR struct socket *psock) * ****************************************************************************/ -#ifdef CONFIG_NET_UDP +#ifdef NET_UDP_HAVE_STACK static int psock_udp_alloc(FAR struct socket *psock) { /* Allocate the UDP connection structure */ @@ -125,7 +126,7 @@ static int psock_udp_alloc(FAR struct socket *psock) psock->s_conn = conn; return OK; } -#endif /* CONFIG_NET_UDP */ +#endif /* NET_UDP_HAVE_STACK */ /**************************************************************************** * Name: psock_pkt_alloc @@ -250,6 +251,47 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) int ret; int errcode; +#ifdef CONFIG_NET_USRSOCK + switch (domain) + { + default: + break; + + case PF_INET: + case PF_INET6: + { +#ifndef CONFIG_NET_USRSOCK_UDP + if (type == SOCK_DGRAM) + break; +#endif +#ifndef CONFIG_NET_USRSOCK_TCP + if (type == SOCK_STREAM) + break; +#endif + psock->s_type = 0; + psock->s_conn = NULL; + + ret = usrsock_socket(domain, type, protocol, psock); + if (ret >= 0) + { + /* Successfully handled and opened by usrsock daemon. */ + + return OK; + } + else if (ret == -ENETDOWN) + { + /* Net down means that usrsock daemon is not running. + * Attempt to open socket with kernel networking stack. */ + } + else + { + errcode = -ret; + goto errout; + } + } + } +#endif /* CONFIG_NET_USRSOCK */ + /* Only PF_INET, PF_INET6 or PF_PACKET domains supported */ switch (domain) @@ -400,9 +442,13 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) if (ipdomain) #endif { +#ifdef NET_TCP_HAVE_STACK /* Allocate and attach the TCP connection structure */ ret = psock_tcp_alloc(psock); +#else + ret = -ENETDOWN; +#endif } #endif /* CONFIG_NET_TCP */ @@ -438,9 +484,13 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) if (ipdomain) #endif { +#ifdef NET_UDP_HAVE_STACK /* Allocate and attach the UDP connection structure */ ret = psock_udp_alloc(psock); +#else + ret = -ENETDOWN; +#endif } #endif /* CONFIG_NET_UDP */ diff --git a/net/socket/socket.h b/net/socket/socket.h index e9bfa161db3..4141cf7477d 100644 --- a/net/socket/socket.h +++ b/net/socket/socket.h @@ -49,6 +49,7 @@ #include #include +#include "tcp/tcp.h" /**************************************************************************** * Pre-processor Definitions @@ -152,7 +153,7 @@ extern "C" * Public Function Prototypes ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK struct tcp_conn_s; /* Forward reference */ #endif @@ -243,7 +244,7 @@ FAR struct socket *sockfd_socket(int sockfd); * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK int net_startmonitor(FAR struct socket *psock); #endif @@ -265,7 +266,7 @@ int net_startmonitor(FAR struct socket *psock); * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK void net_stopmonitor(FAR struct tcp_conn_s *conn); #endif @@ -287,7 +288,7 @@ void net_stopmonitor(FAR struct tcp_conn_s *conn); * ****************************************************************************/ -#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK void net_lostconnection(FAR struct socket *psock, uint16_t flags); #endif diff --git a/net/tcp/Kconfig b/net/tcp/Kconfig index 59fa04d018b..8ac6aab1288 100644 --- a/net/tcp/Kconfig +++ b/net/tcp/Kconfig @@ -9,9 +9,16 @@ config NET_TCP bool "TCP/IP Networking" default n ---help--- - TCP support on or off + Enable or disable TCP networking support. -if NET_TCP +config NET_TCP_NO_STACK + bool "Disable TCP/IP Stack" + default n + select NET_TCP + ---help--- + Build without TCP/IP stack even if TCP networking support enabled. + +if NET_TCP && !NET_TCP_NO_STACK config NET_TCPURGDATA bool "Urgent data" @@ -184,5 +191,5 @@ config NET_SENDFILE Support larger, higher performance sendfile() for transferring files out a TCP connection. -endif # NET_TCP +endif # NET_TCP && !NET_TCP_NO_STACK endmenu # TCP/IP Networking diff --git a/net/tcp/Make.defs b/net/tcp/Make.defs index 520e601f4c1..29b6167a65f 100644 --- a/net/tcp/Make.defs +++ b/net/tcp/Make.defs @@ -36,6 +36,7 @@ # TCP/IP source files ifeq ($(CONFIG_NET_TCP),y) +ifneq ($(CONFIG_NET_TCP_NO_STACK),y) # Socket layer @@ -73,4 +74,5 @@ endif DEPPATH += --dep-path tcp VPATH += :tcp +endif # !CONFIG_NET_TCP_NO_STACK endif # CONFIG_NET_TCP diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index c53475d75a4..f2a5115e53a 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -48,11 +48,14 @@ #include #include -#ifdef CONFIG_NET_TCP +#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK) /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + +#define NET_TCP_HAVE_STACK 1 + /* Conditions for support TCP poll/select operations */ #if !defined(CONFIG_DISABLE_POLL) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \ @@ -1306,5 +1309,5 @@ int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds); } #endif -#endif /* CONFIG_NET_TCP */ +#endif /* CONFIG_NET_TCP && !CONFIG_NET_TCP_NO_STACK */ #endif /* _NET_TCP_TCP_H */ diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c index 6c3688d85ad..5a2ccc98c42 100644 --- a/net/tcp/tcp_send_unbuffered.c +++ b/net/tcp/tcp_send_unbuffered.c @@ -129,7 +129,7 @@ struct send_s * TRUE:timeout FALSE:no timeout * * Assumptions: - * Running at the interrupt level + * The network is locked. * ****************************************************************************/ @@ -139,7 +139,7 @@ static inline int send_timeout(FAR struct send_s *pstate) FAR struct socket *psock; /* Check for a timeout configured via setsockopts(SO_SNDTIMEO). - * If none... we well let the send wait forever. + * If none... we will let the send wait forever. */ psock = pstate->snd_sock; @@ -173,7 +173,7 @@ static inline int send_timeout(FAR struct send_s *pstate) * None * * Assumptions: - * Running at the interrupt level + * The network is locked. * ****************************************************************************/ @@ -224,7 +224,7 @@ static inline void tcpsend_ipselect(FAR struct net_driver_s *dev, * None * * Assumptions: - * Running at the interrupt level + * The network is locked. * ****************************************************************************/ @@ -278,7 +278,7 @@ static inline bool psock_send_addrchck(FAR struct tcp_conn_s *conn) * None * * Assumptions: - * Running at the interrupt level + * The network is locked. * ****************************************************************************/ @@ -708,8 +708,6 @@ static inline void send_txnotify(FAR struct socket *psock, * In this case the process will also receive a SIGPIPE unless * MSG_NOSIGNAL is set. * - * Assumptions: - * ****************************************************************************/ ssize_t psock_tcp_send(FAR struct socket *psock, diff --git a/net/udp/Kconfig b/net/udp/Kconfig index a32f34534db..2c8e85d70b4 100644 --- a/net/udp/Kconfig +++ b/net/udp/Kconfig @@ -12,7 +12,14 @@ config NET_UDP ---help--- Enable or disable UDP networking support. -if NET_UDP +config NET_UDP_NO_STACK + bool "Disable UDP/IP Stack" + default n + select NET_UDP + ---help--- + Build without UDP/IP stack even if UDP networking support enabled. + +if NET_UDP && !NET_UDP_NO_STACK config NET_UDP_CHECKSUMS bool "UDP checksums" @@ -55,5 +62,5 @@ config NET_UDP_READAHEAD default y select NET_IOB -endif # NET_UDP +endif # NET_UDP && !NET_UDP_NO_STACK endmenu # UDP Networking diff --git a/net/udp/Make.defs b/net/udp/Make.defs index 76c72b33ab0..4b3992911df 100644 --- a/net/udp/Make.defs +++ b/net/udp/Make.defs @@ -36,6 +36,7 @@ # UDP source files ifeq ($(CONFIG_NET_UDP),y) +ifneq ($(CONFIG_NET_UDP_NO_STACK),y) # Socket layer @@ -57,4 +58,5 @@ NET_CSRCS += udp_callback.c udp_ipselect.c DEPPATH += --dep-path udp VPATH += :udp +endif # !CONFIG_NET_UDP_NO_STACK endif # CONFIG_NET_UDP diff --git a/net/udp/udp.h b/net/udp/udp.h index f8584bff0b9..1aac4a83280 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -51,11 +51,14 @@ # include #endif -#ifdef CONFIG_NET_UDP +#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK) /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + +#define NET_UDP_HAVE_STACK 1 + /* Conditions for support UDP poll/select operations */ #if !defined(CONFIG_DISABLE_POLL) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \ @@ -510,5 +513,5 @@ int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds); } #endif -#endif /* CONFIG_NET_UDP */ +#endif /* CONFIG_NET_UDP && !CONFIG_NET_UDP_NO_STACK */ #endif /* __NET_UDP_UDP_H */ diff --git a/net/usrsock/Kconfig b/net/usrsock/Kconfig new file mode 100644 index 00000000000..677200cb678 --- /dev/null +++ b/net/usrsock/Kconfig @@ -0,0 +1,39 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +menu "User-space networking stack API" + +config NET_USRSOCK + bool "User-space networking stack API" + default n + depends on NET + ---help--- + Enable or disable user-space networking stack support. + +if NET_USRSOCK + +config NET_USRSOCK_CONNS + int "Number of usrsock connections" + default 6 + ---help--- + Maximum number of usrsock connections (all tasks). + + Note: Usrsock daemon can impose additional restrictions for + maximum number of concurrent connections supported. + +config NET_USRSOCK_UDP + bool "User-space daemon provides UDP sockets" + default n + select NET_UDP + ---help--- + +config NET_USRSOCK_TCP + bool "User-space daemon provides TCP sockets" + default n + select NET_TCP + ---help--- + +endif # NET_USRSOCK +endmenu # User-space networking stack API diff --git a/net/usrsock/Make.defs b/net/usrsock/Make.defs new file mode 100644 index 00000000000..2aa069b077f --- /dev/null +++ b/net/usrsock/Make.defs @@ -0,0 +1,51 @@ +############################################################################ +# net/usrsock/Make.defs +# +# Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. +# Author: Jussi Kivilinna +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# User Socket source files + +ifeq ($(CONFIG_NET_USRSOCK),y) + +NET_CSRCS += usrsock_close.c usrsock_conn.c usrsock_bind.c usrsock_connect.c +NET_CSRCS += usrsock_dev.c +NET_CSRCS += usrsock_event.c usrsock_getsockname.c usrsock_getsockopt.c +NET_CSRCS += usrsock_poll.c usrsock_recvfrom.c usrsock_sendto.c +NET_CSRCS += usrsock_setsockopt.c usrsock_socket.c + +# Include User Socket build support + +DEPPATH += --dep-path usrsock +VPATH += :usrsock + +endif # CONFIG_NET_USRSOCK diff --git a/net/usrsock/usrsock.h b/net/usrsock/usrsock.h new file mode 100644 index 00000000000..55d92187e28 --- /dev/null +++ b/net/usrsock/usrsock.h @@ -0,0 +1,553 @@ +/**************************************************************************** + * net/usrsock/usrsock.h + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NET_USRSOCK_USRSOCK_H +#define __NET_USRSOCK_USRSOCK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_NET_USRSOCK + +#include +#include +#include + +#include "devif/devif.h" +#include "socket/socket.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +/* Internal socket type/domain for marking usrsock sockets */ + +#define SOCK_USRSOCK_TYPE 0x7f +#define PF_USRSOCK_DOMAIN 0x7f + +/* Internal event flags */ + +#define USRSOCK_EVENT_REQ_COMPLETE (1 << 14) +#define USRSOCK_EVENT_CONNECT_RESP (1 << 15) +#define USRSOCK_EVENT_INTERNAL_MASK 0xf000U + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +struct usrsockdev_s; + +enum usrsock_conn_state_e +{ + USRSOCK_CONN_STATE_UNINITIALIZED = 0, + USRSOCK_CONN_STATE_ABORTED, + USRSOCK_CONN_STATE_READY, + USRSOCK_CONN_STATE_CONNECTING, +}; + +struct iovec +{ + FAR void *iov_base; /* Starting address */ + size_t iov_len; /* Number of bytes to transfer */ +}; + +struct usrsock_conn_s +{ + dq_entry_t node; /* Supports a doubly linked list */ + uint8_t crefs; /* Reference counts on this instance */ + + enum usrsock_conn_state_e state; /* State of kernel<->daemon link for conn */ + bool connected; /* Socket has been connected */ + int8_t type; /* Socket type (SOCK_STREAM, etc) */ + int16_t usockid; /* Connection number used for kernel<->daemon */ + uint16_t flags; /* Socket state flags */ + struct usrsockdev_s *dev; /* Device node used for this conn */ + + struct + { + uint8_t xid; /* Expected message exchange id */ + bool inprogress; /* Request was received but daemon is still processing */ + uint16_t valuelen; /* Length of value from daemon */ + uint16_t valuelen_nontrunc; /* Actual length of value at daemon */ + int result; /* Result for request */ + + struct + { + FAR struct iovec *iov; /* Data request input buffers */ + int iovcnt; /* Number of input buffers */ + size_t total; /* Total length of buffers */ + size_t pos; /* Writer position on input buffer */ + } datain; + } resp; + + /* Defines the list of usrsock callbacks */ + + FAR struct devif_callback_s *list; +}; + +struct usrsock_reqstate_s +{ + FAR struct usrsock_conn_s *conn; /* Reference to connection structure */ + FAR struct devif_callback_s *cb; /* Reference to callback instance */ + sem_t recvsem; /* Semaphore signals recv completion */ + int result; /* OK on success, otherwise a negated errno. */ + bool completed; +}; + +struct usrsock_data_reqstate_s +{ + struct usrsock_reqstate_s reqstate; + uint16_t valuelen; + uint16_t valuelen_nontrunc; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +# define EXTERN extern "C" +extern "C" +{ +#else +# define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsock_initialize() + * + * Description: + * Initialize the User Socket connection structures. Called once and only + * from the networking layer. + * + ****************************************************************************/ + +void usrsock_initialize(void); + +/**************************************************************************** + * Name: usrsock_alloc() + * + * Description: + * Allocate a new, uninitialized usrsock connection structure. This is + * normally something done by the implementation of the socket() API + * + ****************************************************************************/ + +FAR struct usrsock_conn_s *usrsock_alloc(void); + +/**************************************************************************** + * Name: usrsock_free() + * + * Description: + * Free a usrsock connection structure that is no longer in use. This should + * be done by the implementation of close(). + * + ****************************************************************************/ + +void usrsock_free(FAR struct usrsock_conn_s *conn); + +/**************************************************************************** + * Name: usrsock_nextconn() + * + * Description: + * Traverse the list of allocated usrsock connections + * + * Assumptions: + * This function is called from usrsock device logic. + * + ****************************************************************************/ + +FAR struct usrsock_conn_s *usrsock_nextconn(FAR struct usrsock_conn_s *conn); + +/**************************************************************************** + * Name: usrsock_connidx() + ****************************************************************************/ + +int usrsock_connidx(FAR struct usrsock_conn_s *conn); + +/**************************************************************************** + * Name: usrsock_active() + * + * Description: + * Find a connection structure that is the appropriate + * connection for usrsock + * + * Assumptions: + * + ****************************************************************************/ + +FAR struct usrsock_conn_s *usrsock_active(int16_t usockid); + +/**************************************************************************** + * Name: usrsock_setup_request_callback() + ****************************************************************************/ + +int usrsock_setup_request_callback(FAR struct usrsock_conn_s *conn, + FAR struct usrsock_reqstate_s *pstate, + FAR devif_callback_event_t event, + uint16_t flags); + +/**************************************************************************** + * Name: usrsock_setup_data_request_callback() + ****************************************************************************/ + +int usrsock_setup_data_request_callback(FAR struct usrsock_conn_s *conn, + FAR struct usrsock_data_reqstate_s *pstate, + FAR devif_callback_event_t event, + uint16_t flags); + +/**************************************************************************** + * Name: usrsock_teardown_request_callback() + ****************************************************************************/ + +void usrsock_teardown_request_callback(FAR struct usrsock_reqstate_s *pstate); + +/**************************************************************************** + * Name: usrsock_teardown_data_request_callback() + ****************************************************************************/ + +#define usrsock_teardown_data_request_callback(datastate) \ + usrsock_teardown_request_callback(&(datastate)->reqstate) + +/**************************************************************************** + * Name: usrsock_event + * + * Description: + * Handler for received connection events + * + ****************************************************************************/ + +int usrsock_event(FAR struct usrsock_conn_s *conn, uint16_t events); + +/**************************************************************************** + * Name: usrsockdev_do_request + ****************************************************************************/ + +int usrsockdev_do_request(FAR struct usrsock_conn_s *conn, + FAR struct iovec *iov, unsigned int iovcnt); + +/**************************************************************************** + * Name: usrsockdev_register + * + * Description: + * Register /dev/usrsock + * + ****************************************************************************/ + +void usrsockdev_register(void); + +/**************************************************************************** + * Name: usrsock_socket + * + * Description: + * socket() creates an endpoint for communication and returns a socket + * structure. + * + * Input Parameters: + * domain (see sys/socket.h) + * type (see sys/socket.h) + * protocol (see sys/socket.h) + * psock A pointer to a user allocated socket structure to be initialized. + * + * Returned Value: + * 0 on success; negative error-code on error + * + * EACCES + * Permission to create a socket of the specified type and/or protocol + * is denied. + * EAFNOSUPPORT + * The implementation does not support the specified address family. + * EINVAL + * Unknown protocol, or protocol family not available. + * EMFILE + * Process file table overflow. + * ENFILE + * The system limit on the total number of open files has been reached. + * ENOBUFS or ENOMEM + * Insufficient memory is available. The socket cannot be created until + * sufficient resources are freed. + * EPROTONOSUPPORT + * The protocol type or the specified protocol is not supported within + * this domain. + * + * Assumptions: + * + ****************************************************************************/ + +int usrsock_socket(int domain, int type, int protocol, FAR struct socket *psock); + +/**************************************************************************** + * Name: usrsock_close + * + * Description: + * Performs the close operation on a usrsock connection instance + * + * Input Parameters: + * conn usrsock connection instance + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately. + * + * Assumptions: + * + ****************************************************************************/ + +int usrsock_close(FAR struct usrsock_conn_s *conn); + +/**************************************************************************** + * Name: usrsock_bind + * + * Description: + * usrsock_bind() gives the socket 'conn' the local address 'addr'. 'addr' + * is 'addrlen' bytes long. Traditionally, this is called "assigning a name + * to a socket." When a socket is created with socket, it exists in a name + * space (address family) but has no name assigned. + * + * Input Parameters: + * conn usrsock socket connection structure + * addr Socket local address + * addrlen Length of 'addr' + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately + * + * EACCES + * The address is protected, and the user is not the superuser. + * EADDRINUSE + * The given address is already in use. + * EINVAL + * The socket is already bound to an address. + * ENOTSOCK + * psock is a descriptor for a file, not a socket. + * + * Assumptions: + * + ****************************************************************************/ + +int usrsock_bind(FAR struct usrsock_conn_s *conn, + FAR const struct sockaddr *addr, + socklen_t addrlen); + +/**************************************************************************** + * Name: usrsock_connect + * + * Description: + * Perform a usrsock connection + * + * Input Parameters: + * psock A reference to the socket structure of the socket to be connected + * addr The address of the remote server to connect to + * addrlen Length of address buffer + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +int usrsock_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen); + +/**************************************************************************** + * Name: usrsock_poll + * + * Description: + * The standard poll() operation redirects operations on socket descriptors + * to this function. + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * fds - The structure describing the events to be monitored. + * setup - true: Setup up the poll; false: Teardown the poll + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +int usrsock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup); +#endif + +/**************************************************************************** + * Name: usrsock_sendto + * + * Description: + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Input Parameters: + * psock A reference to the socket structure of the socket to be connected + * buf Data to send + * len Length of data to send + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +ssize_t usrsock_sendto(FAR struct socket *psock, FAR const void *buf, + size_t len, FAR const struct sockaddr *to, + socklen_t tolen); + +/**************************************************************************** + * Name: usrsock_recvfrom + * + * Description: + * recvfrom() receives messages from a socket, and may be used to receive + * data on a socket whether or not it is connection-oriented. + * + * If from is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument fromlen + * initialized to the size of the buffer associated with from, and modified + * on return to indicate the actual size of the address stored there. + * + * Input Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + ****************************************************************************/ + +ssize_t usrsock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, + FAR struct sockaddr *from, FAR socklen_t *fromlen); + +/**************************************************************************** + * Name: usrsock_getsockopt + * + * Description: + * getsockopt() retrieve thse value for the option specified by the + * 'option' argument for the socket specified by the 'psock' argument. If + * the size of the option value is greater than 'value_len', the value + * stored in the object pointed to by the 'value' argument will be silently + * truncated. Otherwise, the length pointed to by the 'value_len' argument + * will be modified to indicate the actual length of the'value'. + * + * The 'level' argument specifies the protocol level of the option. To + * retrieve options at the socket level, specify the level argument as + * SOL_SOCKET. + * + * See a complete list of values for the 'option' argument. + * + * Input Parameters: + * conn usrsock socket connection structure + * level Protocol level to set the option + * option identifies the option to get + * value Points to the argument value + * value_len The length of the argument value + * + ****************************************************************************/ + +int usrsock_getsockopt(FAR struct usrsock_conn_s *conn, int level, int option, + FAR void *value, FAR socklen_t *value_len); + +/**************************************************************************** + * Name: usrsock_setsockopt + * + * Description: + * psock_setsockopt() sets the option specified by the 'option' argument, + * at the protocol level specified by the 'level' argument, to the value + * pointed to by the 'value' argument for the socket on the 'psock' argument. + * + * The 'level' argument specifies the protocol level of the option. To set + * options at the socket level, specify the level argument as SOL_SOCKET. + * + * See a complete list of values for the 'option' argument. + * + * Input Parameters: + * conn usrsock socket connection structure + * level Protocol level to set the option + * option identifies the option to set + * value Points to the argument value + * value_len The length of the argument value + * + ****************************************************************************/ + +int usrsock_setsockopt(FAR struct usrsock_conn_s *conn, int level, int option, + FAR const void *value, FAR socklen_t value_len); + +/**************************************************************************** + * Name: usrsock_getsockname + * + * Description: + * The getsockname() function retrieves the locally-bound name of the + * specified socket, stores this address in the sockaddr structure pointed + * to by the 'addr' argument, and stores the length of this address in the + * object pointed to by the 'addrlen' argument. + * + * If the actual length of the address is greater than the length of the + * supplied sockaddr structure, the stored address will be truncated. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Input Parameters: + * conn usrsock socket connection structure + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + ****************************************************************************/ + +int usrsock_getsockname(FAR struct usrsock_conn_s *conn, + FAR struct sockaddr *addr, FAR socklen_t *addrlen); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_NET_USRSOCK */ +#endif /* __NET_USRSOCK_USRSOCK_H */ diff --git a/net/usrsock/usrsock_bind.c b/net/usrsock/usrsock_bind.c new file mode 100644 index 00000000000..8ce21f07623 --- /dev/null +++ b/net/usrsock/usrsock_bind.c @@ -0,0 +1,221 @@ +/**************************************************************************** + * net/usrsock/usrsock_bind.c + * + * Copyright (C) 2015-2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t bind_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->result = -ECONNABORTED; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->result = conn->resp.result; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_bind_request + ****************************************************************************/ + +static int do_bind_request(FAR struct usrsock_conn_s *conn, + FAR const struct sockaddr *addr, + socklen_t addrlen) +{ + struct usrsock_request_bind_s req = {}; + struct iovec bufs[2]; + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_BIND; + req.usockid = conn->usockid; + req.addrlen = addrlen; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + bufs[1].iov_base = (FAR void *)addr; + bufs[1].iov_len = req.addrlen; + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsock_bind + * + * Description: + * usrsock_bind() gives the socket 'conn' the local address 'addr'. 'addr' + * is 'addrlen' bytes long. Traditionally, this is called "assigning a name + * to a socket." When a socket is created with socket, it exists in a name + * space (address family) but has no name assigned. + * + * Parameters: + * conn usrsock socket connection structure + * addr Socket local address + * addrlen Length of 'addr' + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately + * + * EACCES + * The address is protected, and the user is not the superuser. + * EADDRINUSE + * The given address is already in use. + * EINVAL + * The socket is already bound to an address. + * ENOTSOCK + * psock is a descriptor for a file, not a socket. + * + * Assumptions: + * + ****************************************************************************/ + +int usrsock_bind(FAR struct usrsock_conn_s *conn, + FAR const struct sockaddr *addr, + socklen_t addrlen) +{ + struct usrsock_reqstate_s state = {}; + ssize_t ret; + + DEBUGASSERT(conn); + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; connect() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; + goto errout_unlock; + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_request_callback(conn, &state, bind_event, + USRSOCK_EVENT_ABORT | + USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_unlock; + } + + /* Request user-space daemon to close socket. */ + + ret = do_bind_request(conn, addr, addrlen); + if (ret >= 0) + { + /* Wait for completion of request. */ + + while (net_lockedwait(&state.recvsem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + } + + ret = state.result; + } + + usrsock_teardown_request_callback(&state); + +errout_unlock: + net_unlock(); + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_close.c b/net/usrsock/usrsock_close.c new file mode 100644 index 00000000000..bb6f052732f --- /dev/null +++ b/net/usrsock/usrsock_close.c @@ -0,0 +1,205 @@ +/**************************************************************************** + * net/usrsock/usrsock_close.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t close_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + conn->state = USRSOCK_CONN_STATE_ABORTED; + pstate->result = -ECONNABORTED; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->result = conn->resp.result; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_close_request + ****************************************************************************/ + +static int do_close_request(FAR struct usrsock_conn_s *conn) +{ + struct usrsock_request_close_s req = {}; + struct iovec bufs[1]; + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_CLOSE; + req.usockid = conn->usockid; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: usrsock_close + * + * Description: + * + ****************************************************************************/ + +int usrsock_close(FAR struct usrsock_conn_s *conn) +{ + struct usrsock_reqstate_s state = {}; + int ret; + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Already closed? */ + + ninfo("usockid=%d; already closed.\n", conn->usockid); + + ret = OK; + goto close_out; + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_request_callback(conn, &state, close_event, + USRSOCK_EVENT_ABORT | + USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout; + } + + /* Request user-space daemon to close socket. */ + + ret = do_close_request(conn); + if (ret < 0) + { + ret = OK; /* Error? return OK for close. */ + } + else + { + /* Wait for completion of request. */ + + while (net_lockedwait(&state.recvsem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + } + + ret = state.result; + if (ret < 0) + { + /* TODO: Error handling for close? Mark closed anyway? There is not + * much we can do if this happens. + */ + ninfo("user-space daemon reported error %d for usockid=%d\n", + state.result, conn->usockid); + + ret = OK; + } + } + + usrsock_teardown_request_callback(&state); + +close_out: + conn->state = USRSOCK_CONN_STATE_UNINITIALIZED; + conn->usockid = -1; + +errout: + net_unlock(); + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_conn.c b/net/usrsock/usrsock_conn.c new file mode 100644 index 00000000000..0b022762467 --- /dev/null +++ b/net/usrsock/usrsock_conn.c @@ -0,0 +1,347 @@ +/**************************************************************************** + * net/usrsock/usrsock_conn.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The array containing all usrsock connections. */ + +struct usrsock_conn_s g_usrsock_connections[CONFIG_NET_USRSOCK_CONNS]; + +/* A list of all free usrsock connections */ + +static dq_queue_t g_free_usrsock_connections; +static sem_t g_free_sem; + +/* A list of all allocated usrsock connections */ + +static dq_queue_t g_active_usrsock_connections; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: _usrsock_semtake() and _usrsock_semgive() + * + * Description: + * Take/give semaphore + * + ****************************************************************************/ + +static void _usrsock_semtake(FAR sem_t *sem) +{ + /* Take the semaphore (perhaps waiting) */ + + while (net_lockedwait(sem) != 0) + { + /* The only case that an error should occur here is if + * the wait was awakened by a signal. + */ + + DEBUGASSERT(*get_errno_ptr() == EINTR); + } +} + +static void _usrsock_semgive(FAR sem_t *sem) +{ + (void)sem_post(sem); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsock_alloc() + * + * Description: + * Allocate a new, uninitialized usrsock connection structure. This is + * normally something done by the implementation of the socket() API + * + ****************************************************************************/ + +FAR struct usrsock_conn_s *usrsock_alloc(void) +{ + FAR struct usrsock_conn_s *conn; + + /* The free list is only accessed from user, non-interrupt level and + * is protected by a semaphore (that behaves like a mutex). + */ + + _usrsock_semtake(&g_free_sem); + conn = (FAR struct usrsock_conn_s *)dq_remfirst(&g_free_usrsock_connections); + if (conn) + { + /* Make sure that the connection is marked as uninitialized */ + + memset(conn, 0, sizeof(*conn)); + conn->dev = NULL; + conn->usockid = -1; + conn->state = USRSOCK_CONN_STATE_UNINITIALIZED; + conn->list = NULL; + conn->connected = false; + + /* Enqueue the connection into the active list */ + + dq_addlast(&conn->node, &g_active_usrsock_connections); + } + + _usrsock_semgive(&g_free_sem); + return conn; +} + +/**************************************************************************** + * Name: usrsock_free() + * + * Description: + * Free a usrsock connection structure that is no longer in use. This should + * be done by the implementation of close(). + * + ****************************************************************************/ + +void usrsock_free(FAR struct usrsock_conn_s *conn) +{ + /* The free list is only accessed from user, non-interrupt level and + * is protected by a semaphore (that behaves like a mutex). + */ + + DEBUGASSERT(conn->crefs == 0); + + _usrsock_semtake(&g_free_sem); + + /* Remove the connection from the active list */ + + dq_rem(&conn->node, &g_active_usrsock_connections); + + /* Reset structure */ + + memset(conn, 0, sizeof(*conn)); + conn->dev = NULL; + conn->usockid = -1; + conn->state = USRSOCK_CONN_STATE_UNINITIALIZED; + conn->list = NULL; + + /* Free the connection */ + + dq_addlast(&conn->node, &g_free_usrsock_connections); + _usrsock_semgive(&g_free_sem); +} + +/**************************************************************************** + * Name: usrsock_nextconn() + * + * Description: + * Traverse the list of allocated usrsock connections + * + * Assumptions: + * This function is called from usrsock device logic. + * + ****************************************************************************/ + +FAR struct usrsock_conn_s *usrsock_nextconn(FAR struct usrsock_conn_s *conn) +{ + if (!conn) + { + return (FAR struct usrsock_conn_s *)g_active_usrsock_connections.head; + } + else + { + return (FAR struct usrsock_conn_s *)conn->node.flink; + } +} + +/**************************************************************************** + * Name: usrsock_connidx() + ****************************************************************************/ + +int usrsock_connidx(FAR struct usrsock_conn_s *conn) +{ + int idx = conn - g_usrsock_connections; + + DEBUGASSERT(idx >= 0); + DEBUGASSERT(idx < ARRAY_SIZE(g_usrsock_connections)); + + return idx; +} + +/**************************************************************************** + * Name: usrsock_active() + * + * Description: + * Find a connection structure that is the appropriate + * connection for usrsock + * + * Assumptions: + * + ****************************************************************************/ + +FAR struct usrsock_conn_s *usrsock_active(int16_t usockid) +{ + FAR struct usrsock_conn_s *conn = NULL; + + while ((conn = usrsock_nextconn(conn)) != NULL) + { + if (conn->usockid == usockid) + return conn; + } + + return NULL; +} + +/**************************************************************************** + * Name: usrsock_setup_request_callback() + ****************************************************************************/ + +int usrsock_setup_request_callback(FAR struct usrsock_conn_s *conn, + FAR struct usrsock_reqstate_s *pstate, + FAR devif_callback_event_t event, + uint16_t flags) +{ + int ret = -EBUSY; + + (void)sem_init(&pstate->recvsem, 0, 0); + pstate->conn = conn; + pstate->result = -EAGAIN; + pstate->completed = false; + + /* Set up the callback in the connection */ + + pstate->cb = devif_callback_alloc(NULL, &conn->list); + if (pstate->cb) + { + /* Set up the connection "interrupt" handler */ + + pstate->cb->flags = flags; + pstate->cb->priv = (FAR void *)pstate; + pstate->cb->event = event; + + ret = OK; + } + + return ret; +} + +/**************************************************************************** + * Name: usrsock_setup_data_request_callback() + ****************************************************************************/ + +int usrsock_setup_data_request_callback(FAR struct usrsock_conn_s *conn, + FAR struct usrsock_data_reqstate_s *pstate, + FAR devif_callback_event_t event, + uint16_t flags) +{ + pstate->valuelen = 0; + pstate->valuelen_nontrunc = 0; + return usrsock_setup_request_callback(conn, &pstate->reqstate, event, flags); +} + +/**************************************************************************** + * Name: usrsock_teardown_request_callback() + ****************************************************************************/ + +void usrsock_teardown_request_callback(FAR struct usrsock_reqstate_s *pstate) +{ + FAR struct usrsock_conn_s *conn = pstate->conn; + + /* Make sure that no further events are processed */ + + devif_conn_callback_free(NULL, pstate->cb, &conn->list); + + pstate->cb = NULL; +} + +/**************************************************************************** + * Name: usrsock_initialize() + * + * Description: + * Initialize the User Socket connection structures. Called once and only + * from the networking layer. + * + ****************************************************************************/ + +void usrsock_initialize(void) +{ + int i; + + /* Initialize the queues */ + + dq_init(&g_free_usrsock_connections); + dq_init(&g_active_usrsock_connections); + sem_init(&g_free_sem, 0, 1); + + for (i = 0; i < CONFIG_NET_USRSOCK_CONNS; i++) + { + FAR struct usrsock_conn_s *conn = &g_usrsock_connections[i]; + + /* Mark the connection closed and move it to the free list */ + + memset(conn, 0, sizeof(*conn)); + conn->dev = NULL; + conn->usockid = -1; + conn->state = USRSOCK_CONN_STATE_UNINITIALIZED; + conn->list = NULL; + conn->flags = 0; + dq_addlast(&conn->node, &g_free_usrsock_connections); + } + + /* Register /dev/usrsock character device. */ + + usrsockdev_register(); +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_connect.c b/net/usrsock/usrsock_connect.c new file mode 100644 index 00000000000..45ed8c1dd64 --- /dev/null +++ b/net/usrsock/usrsock_connect.c @@ -0,0 +1,257 @@ +/**************************************************************************** + * net/usrsock/usrsock_connect.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t connect_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->result = -ECONNABORTED; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->result = conn->resp.result; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_connect_request + ****************************************************************************/ + +static int do_connect_request(FAR struct usrsock_conn_s *conn, + FAR const struct sockaddr *addr, + socklen_t addrlen) +{ + struct usrsock_request_connect_s req = {}; + struct iovec bufs[2]; + + if (addrlen > UINT16_MAX) + { + addrlen = UINT16_MAX; + } + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_CONNECT; + req.usockid = conn->usockid; + req.addrlen = addrlen; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + bufs[1].iov_base = (FAR void *)addr; + bufs[1].iov_len = addrlen; + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsock_connect + * + * Description: + * Perform a usrsock connection + * + * Parameters: + * psock - A reference to the socket structure of the socket to be connected + * addr The address of the remote server to connect to + * addrlen Length of address buffer + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +int usrsock_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen) +{ + FAR struct usrsock_conn_s *conn = psock->s_conn; + struct usrsock_reqstate_s state = {}; + int ret; + + DEBUGASSERT(conn); + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; connect() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNREFUSED; + goto errout_unlock; + } + + if (conn->connected && + (conn->type == SOCK_STREAM || conn->type == SOCK_SEQPACKET)) + { + /* Already connected. */ + + ret = -EISCONN; + goto errout_unlock; + } + + if (conn->state == USRSOCK_CONN_STATE_CONNECTING) + { + /* Already connecting. */ + + ninfo("usockid=%d; socket already connecting.\n", + conn->usockid); + + ret = -EALREADY; + goto errout_unlock; + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_request_callback(conn, &state, connect_event, + USRSOCK_EVENT_ABORT | + USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + + goto errout_unlock; + } + + /* Mark conn as connecting one. */ + + conn->state = USRSOCK_CONN_STATE_CONNECTING; + + /* Send request. */ + + ret = do_connect_request(conn, addr, addrlen); + if (ret < 0) + { + goto errout_teardown; + } + + /* Do not block on waiting for request completion if nonblocking socket. */ + + if (!conn->resp.inprogress || !_SS_ISNONBLOCK(psock->s_flags)) + { + /* Wait for completion of request (or signal). */ + + if (net_lockedwait(&state.recvsem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + + /* Wait interrupted, exit early. */ + + ret = -EINTR; + goto errout_teardown; + } + + ret = state.result; + } + else + { + /* Request not completed and socket is non-blocking. */ + + ret = -EINPROGRESS; + } + +errout_teardown: + usrsock_teardown_request_callback(&state); +errout_unlock: + net_unlock(); + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_dev.c b/net/usrsock/usrsock_dev.c new file mode 100644 index 00000000000..11b915e0d84 --- /dev/null +++ b/net/usrsock/usrsock_dev.c @@ -0,0 +1,1271 @@ +/**************************************************************************** + * net/usrsock/usrsock_dev.c + * + * Copyright (C) 2015-2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "devif/devif.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifndef CONFIG_NET_USRSOCKDEV_NPOLLWAITERS +# define CONFIG_NET_USRSOCKDEV_NPOLLWAITERS 1 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct usrsockdev_s +{ + sem_t devsem; /* Lock for device node */ + uint8_t ocount; /* The number of times the device has been opened */ + + struct + { + FAR const struct iovec *iov; /* Pending request buffers */ + int iovcnt; /* Number of request buffers */ + size_t pos; /* Reader position on request buffer */ + sem_t sem; /* Request semaphore (only one outstanding + * request) */ + sem_t acksem; /* Request acknowledgment notification */ + uint8_t ack_xid; /* Exchange id for which waiting ack */ + uint16_t nbusy; /* Number of requests blocked from different + threads */ + } req; + + FAR struct usrsock_conn_s *datain_conn; /* Connection instance to receive + * data buffers. */ + +#ifndef CONFIG_DISABLE_POLL + struct pollfd *pollfds[CONFIG_NET_USRSOCKDEV_NPOLLWAITERS]; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Character driver methods */ + +static ssize_t usrsockdev_read(FAR struct file *filep, FAR char *buffer, + size_t len); + +static ssize_t usrsockdev_write(FAR struct file *filep, + FAR const char *buffer, size_t len); + +static off_t usrsockdev_seek(FAR struct file *filep, off_t offset, + int whence); + +static int usrsockdev_open(FAR struct file *filep); + +static int usrsockdev_close(FAR struct file *filep); + +#ifndef CONFIG_DISABLE_POLL +static int usrsockdev_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_usrsockdevops = +{ + usrsockdev_open, /* open */ + usrsockdev_close, /* close */ + usrsockdev_read, /* read */ + usrsockdev_write, /* write */ + usrsockdev_seek, /* seek */ + NULL /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , usrsockdev_poll /* poll */ +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , NULL /* unlink */ +#endif +}; + +static struct usrsockdev_s g_usrsockdev; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: iovec_do() - copy to/from iovec from/to buffer. + ****************************************************************************/ + +static ssize_t iovec_do(FAR void *srcdst, size_t srcdstlen, + FAR struct iovec *iov, int iovcnt, size_t pos, + bool from_iov) +{ + ssize_t total; + size_t srclen; + FAR uint8_t *ioout = srcdst; + FAR uint8_t *iovbuf; + + /* Rewind to correct position. */ + + while (pos > 0 && iovcnt > 0) + { + if (iov->iov_len <= pos) + { + pos -= iov->iov_len; + iov++; + iovcnt--; + } + else + { + break; + } + } + + if (iovcnt == 0) + { + /* Position beyond iovec. */ + + return -1; + } + + iovbuf = iov->iov_base; + srclen = iov->iov_len; + iovbuf += pos; + srclen -= pos; + iov++; + iovcnt--; + total = 0; + + while ((srclen > 0 || iovcnt > 0) && srcdstlen > 0) + { + size_t clen = srclen; + + if (srclen == 0) + { + /* Skip empty iovec. */ + + iovbuf = iov->iov_base; + srclen = iov->iov_len; + iov++; + iovcnt--; + + continue; + } + + if (clen > srcdstlen) + { + clen = srcdstlen; + } + + if (from_iov) + { + memmove(ioout, iovbuf, clen); + } + else + { + memmove(iovbuf, ioout, clen); + } + + ioout += clen; + srcdstlen -= clen; + iovbuf += clen; + srclen -= clen; + total += clen; + + if (srclen == 0) + { + if (iovcnt == 0) + { + break; + } + + iovbuf = iov->iov_base; + srclen = iov->iov_len; + iov++; + iovcnt--; + } + } + + return total; +} + +/**************************************************************************** + * Name: iovec_get() - copy from iovec to buffer. + ****************************************************************************/ + +static ssize_t iovec_get(FAR void *dst, size_t dstlen, + FAR const struct iovec *iov, int iovcnt, size_t pos) +{ + return iovec_do(dst, dstlen, (FAR struct iovec *)iov, iovcnt, pos, true); +} + +/**************************************************************************** + * Name: iovec_put() - copy to iovec from buffer. + ****************************************************************************/ + +static ssize_t iovec_put(FAR struct iovec *iov, int iovcnt, size_t pos, + FAR const void *src, size_t srclen) +{ + return iovec_do((FAR void *)src, srclen, iov, iovcnt, pos, false); +} + +/**************************************************************************** + * Name: usrsockdev_get_xid() + ****************************************************************************/ + +static uint8_t usrsockdev_get_xid(FAR struct usrsock_conn_s *conn) +{ + int conn_idx; + +#if CONFIG_NET_USRSOCK_CONNS > 255 +# error "CONFIG_NET_USRSOCK_CONNS too large (over 255)" +#endif + + /* Each connection can one only one request/response pending. So map + * connection structure index to xid value. */ + + conn_idx = usrsock_connidx(conn); + + DEBUGASSERT(1 <= conn_idx + 1); + DEBUGASSERT(conn_idx + 1 <= UINT8_MAX); + + return conn_idx + 1; +} + +/**************************************************************************** + * Name: usrsockdev_semtake() and usrsockdev_semgive() + * + * Description: + * Take/give semaphore + * + ****************************************************************************/ + +static void usrsockdev_semtake(FAR sem_t *sem) +{ + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(sem) != 0) + { + /* The only case that an error should occur here is if + * the wait was awakened by a signal. + */ + + DEBUGASSERT(*get_errno_ptr() == EINTR); + } +} + +static void usrsockdev_semgive(FAR sem_t *sem) +{ + (void)sem_post(sem); +} + +/**************************************************************************** + * Name: usrsockdev_is_opened + ****************************************************************************/ + +static bool usrsockdev_is_opened(FAR struct usrsockdev_s *dev) +{ + bool ret = true; + + if (dev->ocount == 0) + { + ret = false; /* No usrsock daemon running. */ + } + + return ret; +} + +/**************************************************************************** + * Name: usrsockdev_pollnotify + ****************************************************************************/ + +static void usrsockdev_pollnotify(FAR struct usrsockdev_s *dev, pollevent_t eventset) +{ +#ifndef CONFIG_DISABLE_POLL + int i; + for (i = 0; i < ARRAY_SIZE(dev->pollfds); i++) + { + struct pollfd *fds = dev->pollfds[i]; + if (fds) + { + fds->revents |= (fds->events & eventset); + if (fds->revents != 0) + { + ninfo("Report events: %02x\n", fds->revents); + sem_post(fds->sem); + } + } + } +#endif +} + +/**************************************************************************** + * Name: usrsockdev_read + ****************************************************************************/ + +static ssize_t usrsockdev_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct usrsockdev_s *dev; + + if (len == 0) + { + return 0; + } + + if (buffer == NULL) + { + return -EINVAL; + } + + DEBUGASSERT(inode); + + dev = inode->i_private; + + DEBUGASSERT(dev); + + usrsockdev_semtake(&dev->devsem); + net_lock(); + + /* Is request available? */ + + if (dev->req.iov) + { + ssize_t rlen; + + /* Copy request to user-space. */ + + rlen = iovec_get(buffer, len, dev->req.iov, dev->req.iovcnt, + dev->req.pos); + if (rlen < 0) + { + /* Tried reading beyond buffer. */ + + len = 0; + } + else + { + dev->req.pos += rlen; + len = rlen; + } + } + else + { + len = 0; + } + + net_unlock(); + usrsockdev_semgive(&dev->devsem); + + return len; +} + +/**************************************************************************** + * Name: usrsockdev_seek + ****************************************************************************/ + +static off_t usrsockdev_seek(FAR struct file *filep, off_t offset, int whence) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct usrsockdev_s *dev; + off_t pos; + + if (whence != SEEK_CUR && whence != SEEK_SET) + { + return -EINVAL; + } + + DEBUGASSERT(inode); + + dev = inode->i_private; + + DEBUGASSERT(dev); + + usrsockdev_semtake(&dev->devsem); + net_lock(); + + /* Is request available? */ + + if (dev->req.iov) + { + ssize_t rlen; + + if (whence == SEEK_CUR) + { + pos = dev->req.pos + offset; + } + else if (whence == SEEK_SET) + { + pos = offset; + } + + /* Copy request to user-space. */ + + rlen = iovec_get(NULL, 0, dev->req.iov, dev->req.iovcnt, pos); + if (rlen < 0) + { + /* Tried seek beyond buffer. */ + + pos = -EINVAL; + } + else + { + dev->req.pos = pos; + } + } + else + { + pos = 0; + } + + net_unlock(); + usrsockdev_semgive(&dev->devsem); + + return pos; +} + +/**************************************************************************** + * Name: usrsockdev_handle_event + ****************************************************************************/ + +static ssize_t usrsockdev_handle_event(FAR struct usrsockdev_s *dev, + FAR const void *buffer, + size_t len) +{ + FAR const struct usrsock_message_common_s *common = buffer; + + switch (common->msgid) + { + case USRSOCK_MESSAGE_SOCKET_EVENT: + { + FAR const struct usrsock_message_socket_event_s *hdr = buffer; + FAR struct usrsock_conn_s *conn; + int ret; + + if (len < sizeof(*hdr)) + { + nwarn("message too short, %d < %d.\n", len, sizeof(*hdr)); + + return -EINVAL; + } + + /* Get corresponding usrsock connection. */ + + conn = usrsock_active(hdr->usockid); + if (!conn) + { + nwarn("no active connection for usockid=%d.\n", hdr->usockid); + + return -ENOENT; + } + +#ifdef CONFIG_DEV_RANDOM + /* Add randomness. */ + + add_sw_randomness((hdr->events << 16) - hdr->usockid); +#endif + + /* Handle event. */ + + ret = usrsock_event(conn, hdr->events & ~USRSOCK_EVENT_INTERNAL_MASK); + if (ret < 0) + { + return ret; + } + + len = sizeof(*hdr); + } + break; + + default: + nwarn("Unknown event type: %d\n", common->msgid); + return -EINVAL; + } + + return len; +} + +/**************************************************************************** + * Name: usrsockdev_handle_response + ****************************************************************************/ + +static ssize_t usrsockdev_handle_response(FAR struct usrsockdev_s *dev, + FAR struct usrsock_conn_s *conn, + FAR const void *buffer) +{ + FAR const struct usrsock_message_req_ack_s *hdr = buffer; + + if (USRSOCK_MESSAGE_REQ_IN_PROGRESS(hdr->head.flags)) + { + /* In-progress response is acknowledgment that response was + * received. */ + + conn->resp.inprogress = true; + } + else + { + conn->resp.inprogress = false; + conn->resp.xid = 0; + + /* Get result for common request. */ + + conn->resp.result = hdr->result; + + /* Done with request/response. */ + + (void)usrsock_event(conn, USRSOCK_EVENT_REQ_COMPLETE); + } + + return sizeof(*hdr); +} + +/**************************************************************************** + * Name: usrsockdev_handle_datareq_response + ****************************************************************************/ + +static ssize_t +usrsockdev_handle_datareq_response(FAR struct usrsockdev_s *dev, + FAR struct usrsock_conn_s *conn, + FAR const void *buffer) +{ + FAR const struct usrsock_message_datareq_ack_s *datahdr = buffer; + FAR const struct usrsock_message_req_ack_s *hdr = &datahdr->reqack; + int num_inbufs, iovpos; + ssize_t ret; + + if (USRSOCK_MESSAGE_REQ_IN_PROGRESS(hdr->head.flags)) + { + if (datahdr->reqack.result > 0) + { + ninfo("error: request in progress, and result > 0.\n"); + ret = -EINVAL; + goto unlock_out; + } + else if (datahdr->valuelen > 0) + { + ninfo("error: request in progress, and valuelen > 0.\n"); + ret = -EINVAL; + goto unlock_out; + } + + /* In-progress response is acknowledgment that response was + * received. */ + + conn->resp.inprogress = true; + + ret = sizeof(*datahdr); + goto unlock_out; + } + + conn->resp.inprogress = false; + conn->resp.xid = 0; + + /* Prepare to read buffers. */ + + conn->resp.result = hdr->result; + conn->resp.valuelen = datahdr->valuelen; + conn->resp.valuelen_nontrunc = datahdr->valuelen_nontrunc; + + if (conn->resp.result < 0) + { + /* Error, valuelen must be zero. */ + + if (datahdr->valuelen > 0 || datahdr->valuelen_nontrunc > 0) + { + nerr("error: response result negative, and valuelen or valuelen_nontrunc non-zero.\n"); + + ret = -EINVAL; + goto unlock_out; + } + + /* Done with request/response. */ + + (void)usrsock_event(conn, USRSOCK_EVENT_REQ_COMPLETE); + + ret = sizeof(*datahdr); + goto unlock_out; + } + + /* Check that number of buffers match available. */ + + num_inbufs = (hdr->result > 0) + 1; + + if (conn->resp.datain.iovcnt < num_inbufs) + { + nwarn("not enough recv buffers (need: %d, have: %d).\n", num_inbufs, + conn->resp.datain.iovcnt); + + ret = -EINVAL; + goto unlock_out; + } + + /* Adjust length of receiving buffers. */ + + conn->resp.datain.total = 0; + iovpos = 0; + + /* Value buffer is always the first */ + + if (conn->resp.datain.iov[iovpos].iov_len < datahdr->valuelen) + { + nwarn("%dth buffer not large enough (need: %d, have: %d).\n", + iovpos, + datahdr->valuelen, + conn->resp.datain.iov[iovpos].iov_len); + + ret = -EINVAL; + goto unlock_out; + } + + /* Adjust read size. */ + + conn->resp.datain.iov[iovpos].iov_len = datahdr->valuelen; + conn->resp.datain.total += conn->resp.datain.iov[iovpos].iov_len; + iovpos++; + + if (hdr->result > 0) + { + /* Value buffer is always the first */ + + if (conn->resp.datain.iov[iovpos].iov_len < hdr->result) + { + nwarn("%dth buffer not large enough (need: %d, have: %d).\n", + iovpos, + hdr->result, + conn->resp.datain.iov[iovpos].iov_len); + + ret = -EINVAL; + goto unlock_out; + } + + /* Adjust read size. */ + + conn->resp.datain.iov[iovpos].iov_len = hdr->result; + conn->resp.datain.total += conn->resp.datain.iov[iovpos].iov_len; + iovpos++; + } + + DEBUGASSERT(num_inbufs == iovpos); + + conn->resp.datain.iovcnt = num_inbufs; + + /* Next written buffers are redirected to data buffers. */ + + dev->datain_conn = conn; + ret = sizeof(*datahdr); + +unlock_out: + return ret; +} + +/**************************************************************************** + * Name: usrsockdev_handle_req_response + ****************************************************************************/ + +static ssize_t usrsockdev_handle_req_response(FAR struct usrsockdev_s *dev, + FAR const void *buffer, + size_t len) +{ + FAR const struct usrsock_message_req_ack_s *hdr = buffer; + FAR struct usrsock_conn_s *conn; + unsigned int hdrlen; + ssize_t ret; + ssize_t (* handle_response)(FAR struct usrsockdev_s *dev, + FAR struct usrsock_conn_s *conn, + FAR const void *buffer); + + switch (hdr->head.msgid) + { + case USRSOCK_MESSAGE_RESPONSE_ACK: + hdrlen = sizeof(struct usrsock_message_req_ack_s); + handle_response = &usrsockdev_handle_response; + break; + + case USRSOCK_MESSAGE_RESPONSE_DATA_ACK: + hdrlen = sizeof(struct usrsock_message_datareq_ack_s); + handle_response = &usrsockdev_handle_datareq_response; + break; + + default: + nwarn("unknown message type: %d, flags: %d, xid: %02x, result: %d\n", + hdr->head.msgid, hdr->head.flags, hdr->xid, hdr->result); + return -EINVAL; + } + + if (len < hdrlen) + { + nwarn("message too short, %d < %d.\n", len, hdrlen); + + return -EINVAL; + } + + net_lock(); + + /* Get corresponding usrsock connection for this transfer */ + + conn = usrsock_nextconn(NULL); + while (conn) + { + if (conn->resp.xid == hdr->xid) + break; + + conn = usrsock_nextconn(conn); + } + + if (!conn) + { + /* No connection waiting for this message. */ + + nwarn("Could find connection waiting for response with xid=%d\n", + hdr->xid); + + ret = -EINVAL; + goto unlock_out; + } + + if (dev->req.ack_xid == hdr->xid && dev->req.iov) + { + /* Signal that request was received and read by daemon and acknowledgment + * response was received. */ + + dev->req.iov = NULL; + + sem_post(&dev->req.acksem); + } + + ret = handle_response(dev, conn, buffer); + +unlock_out: + net_unlock(); + return ret; +} + +/**************************************************************************** + * Name: usrsockdev_handle_message + ****************************************************************************/ + +static ssize_t usrsockdev_handle_message(FAR struct usrsockdev_s *dev, + FAR const void *buffer, + size_t len) +{ + FAR const struct usrsock_message_common_s *common = buffer; + + if (USRSOCK_MESSAGE_IS_EVENT(common->flags)) + { + return usrsockdev_handle_event(dev, buffer, len); + } + + if (USRSOCK_MESSAGE_IS_REQ_RESPONSE(common->flags)) + { + return usrsockdev_handle_req_response(dev, buffer, len); + } + + return -EINVAL; +} + +/**************************************************************************** + * Name: usrsockdev_write + ****************************************************************************/ + +static ssize_t usrsockdev_write(FAR struct file *filep, FAR const char *buffer, + size_t len) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct usrsock_conn_s *conn; + FAR struct usrsockdev_s *dev; + size_t origlen = len; + ssize_t ret = 0; + + if (len == 0) + { + return 0; + } + + if (buffer == NULL) + { + return -EINVAL; + } + + DEBUGASSERT(inode); + + dev = inode->i_private; + + DEBUGASSERT(dev); + + usrsockdev_semtake(&dev->devsem); + + if (!dev->datain_conn) + { + /* Start of message, buffer length should be at least size of common + * message header. */ + + if (len < sizeof(struct usrsock_message_common_s)) + { + nwarn("message too short, %d < %d.\n", len, + sizeof(struct usrsock_message_common_s)); + + ret = -EINVAL; + goto errout; + } + + /* Handle message. */ + + ret = usrsockdev_handle_message(dev, buffer, len); + if (ret >= 0) + { + buffer += ret; + len -= ret; + ret = origlen - len; + } + } + + /* Data input handling. */ + + if (dev->datain_conn) + { + conn = dev->datain_conn; + + /* Copy data from user-space. */ + + ret = iovec_put(conn->resp.datain.iov, conn->resp.datain.iovcnt, + conn->resp.datain.pos, buffer, len); + if (ret < 0) + { + /* Tried writing beyond buffer. */ + + ret = -EINVAL; + conn->resp.result = -EINVAL; + conn->resp.datain.pos = + conn->resp.datain.total; + } + else + { + conn->resp.datain.pos += ret; + buffer += ret; + len -= ret; + ret = origlen - len; + } + + if (conn->resp.datain.pos == conn->resp.datain.total) + { + dev->datain_conn = NULL; + + /* Done with data response. */ + + (void)usrsock_event(conn, USRSOCK_EVENT_REQ_COMPLETE); + } + } + +errout: + usrsockdev_semgive(&dev->devsem); + return ret; +} + +/**************************************************************************** + * Name: usrsockdev_open + ****************************************************************************/ + +static int usrsockdev_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct usrsockdev_s *dev; + int ret, tmp; + + DEBUGASSERT(inode); + + dev = inode->i_private; + + DEBUGASSERT(dev); + + usrsockdev_semtake(&dev->devsem); + + ninfo("opening /usr/usrsock\n"); + + /* Increment the count of references to the device. */ + + tmp = dev->ocount + 1; + if (tmp > 1) + { + /* Only one reference is allowed. */ + + nwarn("failed to open\n"); + + ret = -EPERM; + } + else + { + dev->ocount = tmp; + ret = OK; + } + + usrsockdev_semgive(&dev->devsem); + + return ret; +} + +/**************************************************************************** + * Name: usrsockdev_close + ****************************************************************************/ + +static int usrsockdev_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct usrsockdev_s *dev; + FAR struct usrsock_conn_s *conn; + struct timespec abstime; + int ret; + + DEBUGASSERT(inode); + + dev = inode->i_private; + + DEBUGASSERT(dev); + + usrsockdev_semtake(&dev->devsem); + + ninfo("closing /dev/usrsock\n"); + + /* Set active usrsock sockets to aborted state. */ + + conn = usrsock_nextconn(NULL); + while (conn) + { + net_lock(); + + conn->resp.inprogress = false; + conn->resp.xid = 0; + usrsock_event(conn, USRSOCK_EVENT_ABORT); + + net_unlock(); + + conn = usrsock_nextconn(conn); + } + + net_lock(); + + /* Decrement the references to the driver. */ + + dev->ocount--; + DEBUGASSERT(dev->ocount == 0); + ret = OK; + + do + { + /* Give other threads short time window to complete recently completed + * requests. + */ + + DEBUGVERIFY(clock_gettime(CLOCK_REALTIME, &abstime)); + + abstime.tv_sec += 0; + abstime.tv_nsec += 10 * NSEC_PER_MSEC; + if (abstime.tv_nsec >= NSEC_PER_SEC) + { + abstime.tv_sec++; + abstime.tv_nsec -= NSEC_PER_SEC; + } + + ret = net_timedwait(&dev->req.sem, &abstime); + if (ret < 0) + { + ret = *get_errno_ptr(); + + if (ret != ETIMEDOUT && ret != EINTR) + { + ninfo("net_timedwait errno: %d\n", ret); + DEBUGASSERT(false); + } + } + else + { + usrsockdev_semgive(&dev->req.sem); + } + + /* Wake-up pending requests. */ + + if (dev->req.nbusy == 0) + { + break; + } + + dev->req.iov = NULL; + sem_post(&dev->req.acksem); + } + while (true); + + net_unlock(); + + /* Check if request line is active */ + + if (dev->req.iov != NULL) + { + dev->req.iov = NULL; + } + + usrsockdev_semgive(&dev->devsem); + + return ret; +} + +/**************************************************************************** + * Name: pipecommon_poll + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +static int usrsockdev_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct usrsockdev_s *dev; + pollevent_t eventset; + int ret = OK; + int i; + + DEBUGASSERT(inode); + + dev = inode->i_private; + + DEBUGASSERT(dev); + + /* Some sanity checking */ + + if (!dev || !fds) + { + return -ENODEV; + } + + /* Are we setting up the poll? Or tearing it down? */ + + usrsockdev_semtake(&dev->devsem); + net_lock(); + if (setup) + { + /* This is a request to set up the poll. Find an available + * slot for the poll structure reference + */ + + for (i = 0; i < ARRAY_SIZE(dev->pollfds); i++) + { + /* Find an available slot */ + + if (!dev->pollfds[i]) + { + /* Bind the poll structure and this slot */ + + dev->pollfds[i] = fds; + fds->priv = &dev->pollfds[i]; + break; + } + } + + if (i >= ARRAY_SIZE(dev->pollfds)) + { + fds->priv = NULL; + ret = -EBUSY; + goto errout; + } + + /* Should immediately notify on any of the requested events? */ + + eventset = 0; + + /* Notify the POLLIN event if pending request. */ + + if (dev->req.iov != NULL && + !(iovec_get(NULL, 0, dev->req.iov, + dev->req.iovcnt, dev->req.pos) < 0)) + { + eventset |= POLLIN; + } + + if (eventset) + { + usrsockdev_pollnotify(dev, eventset); + } + } + else + { + /* This is a request to tear down the poll. */ + + FAR struct pollfd **slot = (FAR struct pollfd **)fds->priv; + + if (!slot) + { + ret = -EIO; + goto errout; + } + + /* Remove all memory of the poll setup */ + + *slot = NULL; + fds->priv = NULL; + } + +errout: + net_unlock(); + usrsockdev_semgive(&dev->devsem); + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsockdev_do_request + ****************************************************************************/ + +int usrsockdev_do_request(FAR struct usrsock_conn_s *conn, + FAR struct iovec *iov, unsigned int iovcnt) +{ + FAR struct usrsockdev_s *dev = conn->dev; + FAR struct usrsock_request_common_s *req_head = iov[0].iov_base; + + if (!dev) + { + /* Setup conn for new usrsock device. */ + + DEBUGASSERT(req_head->reqid == USRSOCK_REQUEST_SOCKET); + dev = &g_usrsockdev; + conn->dev = dev; + } + + if (!usrsockdev_is_opened(dev)) + { + ninfo("usockid=%d; daemon has closed /usr/usrsock.\n", conn->usockid); + + return -ENETDOWN; + } + + /* Get exchange id. */ + + req_head->xid = usrsockdev_get_xid(conn); + + /* Prepare connection for response. */ + + conn->resp.xid = req_head->xid; + conn->resp.result = -EACCES; + + ++dev->req.nbusy; /* net_lock held. */ + + /* Set outstanding request for daemon to handle. */ + + while (net_lockedwait(&dev->req.sem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + } + + if (usrsockdev_is_opened(dev)) + { + DEBUGASSERT(dev->req.iov == NULL); + dev->req.ack_xid = req_head->xid; + dev->req.iov = iov; + dev->req.pos = 0; + dev->req.iovcnt = iovcnt; + + /* Notify daemon of new request. */ + + usrsockdev_pollnotify(dev, POLLIN); + + /* Wait ack for request. */ + + while (net_lockedwait(&dev->req.acksem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + } + } + else + { + ninfo("usockid=%d; daemon abruptly closed /usr/usrsock.\n", conn->usockid); + } + + /* Free request line for next command. */ + + usrsockdev_semgive(&dev->req.sem); + + --dev->req.nbusy; /* net_lock held. */ + + return OK; +} + +/**************************************************************************** + * Name: usrsockdev_register + * + * Description: + * Register /dev/usrsock + * + ****************************************************************************/ + +void usrsockdev_register(void) +{ + /* Initialize device private structure. */ + + g_usrsockdev.ocount = 0; + g_usrsockdev.req.nbusy = 0; + sem_init(&g_usrsockdev.devsem, 0, 1); + sem_init(&g_usrsockdev.req.sem, 0, 1); + sem_init(&g_usrsockdev.req.acksem, 0, 0); + + (void)register_driver("/dev/usrsock", &g_usrsockdevops, 0666, &g_usrsockdev); +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_event.c b/net/usrsock/usrsock_event.c new file mode 100644 index 00000000000..d16fb04fc9c --- /dev/null +++ b/net/usrsock/usrsock_event.c @@ -0,0 +1,136 @@ +/**************************************************************************** + * net/usrsock/usrsock_event.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "devif/devif.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: usrsock_event + * + * Description: + * Handler for received connection events + * + ****************************************************************************/ + +int usrsock_event(FAR struct usrsock_conn_s *conn, uint16_t events) +{ + ninfo("events: %04X\n", events); + + if (!events) + { + return OK; + } + + net_lock(); + + /* Generic state updates. */ + + if (events & USRSOCK_EVENT_REQ_COMPLETE) + { + if (conn->state == USRSOCK_CONN_STATE_CONNECTING) + { + conn->state = USRSOCK_CONN_STATE_READY; + events |= USRSOCK_EVENT_CONNECT_RESP; + + if (conn->resp.result == 0) + { + conn->connected = true; + } + } + } + + if (events & USRSOCK_EVENT_ABORT) + { + conn->state = USRSOCK_CONN_STATE_ABORTED; + } + + if (events & USRSOCK_EVENT_REMOTE_CLOSED) + { + /* After reception of remote close event, clear input/output flags. */ + + conn->flags &= ~(USRSOCK_EVENT_SENDTO_READY | + USRSOCK_EVENT_RECVFROM_AVAIL); + + conn->flags |= USRSOCK_EVENT_REMOTE_CLOSED; + } + + if ((conn->state == USRSOCK_CONN_STATE_READY || + conn->state == USRSOCK_CONN_STATE_CONNECTING) && + !(conn->flags & USRSOCK_EVENT_REMOTE_CLOSED)) + { + if (events & USRSOCK_EVENT_SENDTO_READY) + { + conn->flags |= USRSOCK_EVENT_SENDTO_READY; + } + + if (events & USRSOCK_EVENT_RECVFROM_AVAIL) + { + conn->flags |= USRSOCK_EVENT_RECVFROM_AVAIL; + } + } + + /* Send events to callbacks */ + + (void)devif_conn_event(NULL, conn, events, conn->list); + net_unlock(); + + return OK; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_getsockname.c b/net/usrsock/usrsock_getsockname.c new file mode 100644 index 00000000000..5049ab8d213 --- /dev/null +++ b/net/usrsock/usrsock_getsockname.c @@ -0,0 +1,265 @@ +/**************************************************************************** + * net/usrsock/usrsock_getsockname.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t getsockname_event(FAR struct net_driver_s *dev, + FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_data_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->reqstate.result = -ECONNABORTED; + pstate->valuelen = 0; + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->reqstate.recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->reqstate.result = conn->resp.result; + if (pstate->reqstate.result < 0) + { + pstate->valuelen = 0; + pstate->valuelen_nontrunc = 0; + } + else + { + pstate->valuelen = conn->resp.valuelen; + pstate->valuelen_nontrunc = conn->resp.valuelen_nontrunc; + } + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->reqstate.recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_getsockopt_request + ****************************************************************************/ + +static int do_getsockname_request(FAR struct usrsock_conn_s *conn, + socklen_t addrlen) +{ + struct usrsock_request_getsockname_s req = {}; + struct iovec bufs[1]; + + if (addrlen > UINT16_MAX) + { + addrlen = UINT16_MAX; + } + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_GETSOCKNAME; + req.usockid = conn->usockid; + req.max_addrlen = addrlen; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Name: setup_conn_getsockopt + ****************************************************************************/ + +static void setup_conn_getsockname(FAR struct usrsock_conn_s *conn, + FAR struct iovec *iov, + unsigned int iovcnt) +{ + unsigned int i; + + conn->resp.datain.iov = iov; + conn->resp.datain.pos = 0; + conn->resp.datain.total = 0; + conn->resp.datain.iovcnt = iovcnt; + + for (i = 0; i < iovcnt; i++) + { + conn->resp.datain.total += iov[i].iov_len; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: usrsock_getsockname + * + * Description: + * The getsockname() function retrieves the locally-bound name of the + * specified socket, stores this address in the sockaddr structure pointed + * to by the 'addr' argument, and stores the length of this address in the + * object pointed to by the 'addrlen' argument. + * + * If the actual length of the address is greater than the length of the + * supplied sockaddr structure, the stored address will be truncated. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Parameters: + * conn usrsock socket connection structure + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + ****************************************************************************/ + +int usrsock_getsockname(FAR struct usrsock_conn_s *conn, + FAR struct sockaddr *addr, FAR socklen_t *addrlen) +{ + struct usrsock_data_reqstate_s state = {}; + struct iovec inbufs[1]; + ssize_t ret; + socklen_t outaddrlen = 0; + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; connect() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; + goto errout_unlock; + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_data_request_callback( + conn, &state, getsockname_event, + USRSOCK_EVENT_ABORT | USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_unlock; + } + + inbufs[0].iov_base = (FAR void *)addr; + inbufs[0].iov_len = *addrlen; + + setup_conn_getsockname(conn, inbufs, ARRAY_SIZE(inbufs)); + + /* Request user-space daemon to close socket. */ + + ret = do_getsockname_request(conn, *addrlen); + if (ret >= 0) + { + /* Wait for completion of request. */ + + while (net_lockedwait(&state.reqstate.recvsem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + } + + ret = state.reqstate.result; + + DEBUGASSERT(state.valuelen <= *addrlen); + DEBUGASSERT(state.valuelen <= state.valuelen_nontrunc); + + if (ret >= 0) + { + /* Store length of data that was written to 'value' buffer. */ + + outaddrlen = state.valuelen_nontrunc; + } + } + + setup_conn_getsockname(conn, NULL, 0); + usrsock_teardown_data_request_callback(&state); + +errout_unlock: + net_unlock(); + + *addrlen = outaddrlen; + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_getsockopt.c b/net/usrsock/usrsock_getsockopt.c new file mode 100644 index 00000000000..f4a8ccb0d46 --- /dev/null +++ b/net/usrsock/usrsock_getsockopt.c @@ -0,0 +1,275 @@ +/**************************************************************************** + * net/usrsock/usrsock_getsockopt.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) && \ + defined(CONFIG_NET_SOCKOPTS) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t getsockopt_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_data_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->reqstate.result = -ECONNABORTED; + pstate->valuelen = 0; + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->reqstate.recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->reqstate.result = conn->resp.result; + if (pstate->reqstate.result < 0) + { + pstate->valuelen = 0; + } + else + { + pstate->valuelen = conn->resp.valuelen; + } + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->reqstate.recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_getsockopt_request + ****************************************************************************/ + +static int do_getsockopt_request(FAR struct usrsock_conn_s *conn, int level, + int option, socklen_t value_len) +{ + struct usrsock_request_getsockopt_s req = {}; + struct iovec bufs[1]; + + if (level < INT16_MIN || level > INT16_MAX) + { + return -EINVAL; + } + + if (option < INT16_MIN || option > INT16_MAX) + { + return -EINVAL; + } + + if (value_len > UINT16_MAX) + { + value_len = UINT16_MAX; + } + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_GETSOCKOPT; + req.usockid = conn->usockid; + req.level = level; + req.option = option; + req.max_valuelen = value_len; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Name: setup_conn_getsockopt + ****************************************************************************/ + +static void setup_conn_getsockopt(FAR struct usrsock_conn_s *conn, + FAR struct iovec *iov, unsigned int iovcnt) +{ + unsigned int i; + + conn->resp.datain.iov = iov; + conn->resp.datain.pos = 0; + conn->resp.datain.total = 0; + conn->resp.datain.iovcnt = iovcnt; + + for (i = 0; i < iovcnt; i++) + { + conn->resp.datain.total += iov[i].iov_len; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: usrsock_getsockopt + * + * Description: + * getsockopt() retrieve thse value for the option specified by the + * 'option' argument for the socket specified by the 'psock' argument. If + * the size of the option value is greater than 'value_len', the value + * stored in the object pointed to by the 'value' argument will be silently + * truncated. Otherwise, the length pointed to by the 'value_len' argument + * will be modified to indicate the actual length of the'value'. + * + * The 'level' argument specifies the protocol level of the option. To + * retrieve options at the socket level, specify the level argument as + * SOL_SOCKET. + * + * See a complete list of values for the 'option' argument. + * + * Parameters: + * conn usrsock socket connection structure + * level Protocol level to set the option + * option identifies the option to get + * value Points to the argument value + * value_len The length of the argument value + * + ****************************************************************************/ + +int usrsock_getsockopt(FAR struct usrsock_conn_s *conn, int level, int option, + FAR void *value, FAR socklen_t *value_len) +{ + struct usrsock_data_reqstate_s state = {}; + struct iovec inbufs[1]; + ssize_t ret; + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; connect() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; + goto errout_unlock; + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_data_request_callback( + conn, &state, getsockopt_event, + USRSOCK_EVENT_ABORT | USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_unlock; + } + + inbufs[0].iov_base = (FAR void *)value; + inbufs[0].iov_len = *value_len; + + setup_conn_getsockopt(conn, inbufs, ARRAY_SIZE(inbufs)); + + /* Request user-space daemon to close socket. */ + + ret = do_getsockopt_request(conn, level, option, *value_len); + if (ret >= 0) + { + /* Wait for completion of request. */ + + while (net_lockedwait(&state.reqstate.recvsem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + } + + ret = state.reqstate.result; + + DEBUGASSERT(state.valuelen <= *value_len); + + if (ret >= 0) + { + /* Store length of data that was written to 'value' buffer. */ + + *value_len = state.valuelen; + } + } + + setup_conn_getsockopt(conn, NULL, 0); + usrsock_teardown_data_request_callback(&state); + +errout_unlock: + net_unlock(); + + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK && CONFIG_NET_SOCKOPTS */ diff --git a/net/usrsock/usrsock_poll.c b/net/usrsock/usrsock_poll.c new file mode 100644 index 00000000000..41860f4d7f8 --- /dev/null +++ b/net/usrsock/usrsock_poll.c @@ -0,0 +1,388 @@ +/**************************************************************************** + * net/usrsock/usrsock_poll.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) && \ + !defined(CONFIG_DISABLE_POLL) + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct usrsock_poll_s +{ + FAR struct socket *psock; /* Needed to handle loss of connection */ + struct pollfd *fds; /* Needed to handle poll events */ + FAR struct devif_callback_s *cb; /* Needed to teardown the poll */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t poll_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_poll_s *info = (FAR struct usrsock_poll_s *)pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + pollevent_t eventset = 0; + + DEBUGASSERT(!info || (info->psock && info->fds)); + + if (!info) + return flags; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + /* Socket forcefully terminated. */ + + eventset |= (POLLERR | POLLHUP); + } + else if ((flags & USRSOCK_EVENT_CONNECT_RESP) && !conn->connected) + { + ninfo("socket connect failed.\n"); + + /* Non-blocking connect failed. */ + + eventset |= (POLLERR | POLLHUP); + } + else if (flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ninfo("remote closed.\n"); + + /* Remote closed. */ + + eventset |= (POLLHUP | POLLIN); + } + else + { + /* Check data events. */ + + if (flags & USRSOCK_EVENT_RECVFROM_AVAIL) + { + ninfo("socket recv avail.\n"); + + eventset |= POLLIN; + } + + if (flags & USRSOCK_EVENT_SENDTO_READY) + { + ninfo("socket send ready.\n"); + + eventset |= POLLOUT; + } + } + + /* Filter I/O events depending on requested events. */ + + eventset &= (~(POLLOUT | POLLIN) | info->fds->events); + + /* POLLOUT and PULLHUP are mutually exclusive. */ + + if ((eventset & POLLOUT) && (eventset & POLLHUP)) + { + eventset &= ~POLLOUT; + } + + /* Awaken the caller of poll() is requested event occurred. */ + + if (eventset) + { + info->fds->revents |= eventset; + sem_post(info->fds->sem); + } + + return flags; +} + +/**************************************************************************** + * Function: usrsock_poll + * + * Description: + * Setup to monitor events on an usrsock socket + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * fds - The structure describing the events to be monitored. + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +static int usrsock_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) +{ + FAR struct usrsock_conn_s *conn = psock->s_conn; + FAR struct usrsock_poll_s *info; + FAR struct devif_callback_s *cb; + int ret = OK; + + /* Sanity check */ + +#ifdef CONFIG_DEBUG + if (!conn || !fds) + { + return -EINVAL; + } +#endif + + /* Allocate a container to hold the poll information */ + + info = (FAR struct usrsock_poll_s *)kmm_malloc(sizeof(struct usrsock_poll_s)); + if (!info) + { + return -ENOMEM; + } + + net_lock(); + + /* Allocate a usrsock callback structure */ + + cb = devif_callback_alloc(NULL, &conn->list); + if (!cb) + { + ret = -EBUSY; + kmm_free(info); /* fds->priv not set, so we need to free info here. */ + goto errout_unlock; + } + + /* Initialize the poll info container */ + + info->psock = psock; + info->fds = fds; + info->cb = cb; + + /* Initialize the callback structure. Save the reference to the info + * structure as callback private data so that it will be available during + * callback processing. + */ + + cb->flags = USRSOCK_EVENT_ABORT | USRSOCK_EVENT_CONNECT_RESP | + USRSOCK_EVENT_SENDTO_READY | USRSOCK_EVENT_RECVFROM_AVAIL | + USRSOCK_EVENT_REMOTE_CLOSED; + cb->priv = (FAR void *)info; + cb->event = poll_event; + + /* Save the reference in the poll info structure as fds private as well + * for use during poll teardown as well. + */ + + fds->priv = (FAR void *)info; + + /* Check if socket is in error state */ + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + ninfo("socket %s.\n", + conn->state == USRSOCK_CONN_STATE_UNINITIALIZED ? + "uninitialized" : "aborted"); + + fds->revents |= (POLLERR | POLLHUP); + } + + /* Stream sockets need to be connected or connecting (or listening). */ + + else if ((conn->type == SOCK_STREAM || conn->type == SOCK_SEQPACKET) && + !(conn->connected || conn->state == USRSOCK_CONN_STATE_CONNECTING)) + { + ninfo("stream socket not connected and not connecting.\n"); + + fds->revents |= (POLLOUT | POLLIN | POLLHUP); + } + else if (conn->flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ninfo("socket remote closed.\n"); + + /* Remote closed. */ + + fds->revents |= (POLLHUP | POLLIN); + } + else + { + /* Check if daemon has room for send data or has data to receive. */ + + if (conn->flags & USRSOCK_EVENT_SENDTO_READY) + { + ninfo("socket send ready.\n"); + + fds->revents |= (POLLOUT & fds->events); + } + + if (conn->flags & USRSOCK_EVENT_RECVFROM_AVAIL) + { + ninfo("socket recv avail.\n"); + + fds->revents |= (POLLIN & fds->events); + } + } + + /* Filter I/O events depending on requested events. */ + + fds->revents &= (~(POLLOUT | POLLIN) | info->fds->events); + + /* POLLOUT and PULLHUP are mutually exclusive. */ + + if ((fds->revents & POLLOUT) && (fds->revents & POLLHUP)) + { + fds->revents &= ~POLLOUT; + } + + /* Check if any requested events are already in effect */ + + if (fds->revents != 0) + { + /* Yes.. then signal the poll logic */ + + sem_post(fds->sem); + } + +errout_unlock: + net_unlock(); + return ret; +} + +/**************************************************************************** + * Function: usrsock_pollteardown + * + * Description: + * Teardown monitoring of events on an usrsock socket + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * fds - The structure describing the events to be stopped being monitored. + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +static int usrsock_pollteardown(FAR struct socket *psock, + FAR struct pollfd *fds) +{ + FAR struct usrsock_conn_s *conn = psock->s_conn; + FAR struct usrsock_poll_s *info; + + /* Sanity check */ + +#ifdef CONFIG_DEBUG + if (!conn || !fds->priv) + { + return -EINVAL; + } +#endif + + /* Recover the socket descriptor poll state info from the poll structure */ + + info = (FAR struct usrsock_poll_s *)fds->priv; + DEBUGASSERT(info && info->fds && info->cb); + if (info) + { + /* Release the callback */ + + net_lock(); + devif_conn_callback_free(NULL, info->cb, &conn->list); + net_unlock(); + + /* Release the poll/select data slot */ + + info->fds->priv = NULL; + + /* Then free the poll info container */ + + kmm_free(info); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: usrsock_poll + * + * Description: + * The standard poll() operation redirects operations on socket descriptors + * to this function. + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * fds - The structure describing the events to be monitored. + * setup - true: Setup up the poll; false: Teardown the poll + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +int usrsock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup) +{ + if (setup) + { + return usrsock_pollsetup(psock, fds); + } + else + { + return usrsock_pollteardown(psock, fds); + } +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK && !CONFIG_DISABLE_POLL */ diff --git a/net/usrsock/usrsock_recvfrom.c b/net/usrsock/usrsock_recvfrom.c new file mode 100644 index 00000000000..d97cba5c3a9 --- /dev/null +++ b/net/usrsock/usrsock_recvfrom.c @@ -0,0 +1,485 @@ +/**************************************************************************** + * net/usrsock/usrsock_recvfrom.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t recvfrom_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_data_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->reqstate.result = -ECONNABORTED; + pstate->valuelen = 0; + pstate->valuelen_nontrunc = 0; + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->reqstate.recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->reqstate.result = conn->resp.result; + if (pstate->reqstate.result < 0) + { + pstate->valuelen = 0; + pstate->valuelen_nontrunc = 0; + } + else + { + pstate->valuelen = conn->resp.valuelen; + pstate->valuelen_nontrunc = conn->resp.valuelen_nontrunc; + } + + if (pstate->reqstate.result >= 0 || + pstate->reqstate.result == -EAGAIN) + { + /* After reception of data, mark input not ready. Daemon will + * send event to restore this flag. */ + + conn->flags &= ~USRSOCK_EVENT_RECVFROM_AVAIL; + } + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->reqstate.recvsem); + } + else if (flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ninfo("remote closed.\n"); + + pstate->reqstate.result = -EPIPE; + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->reqstate.recvsem); + } + else if (flags & USRSOCK_EVENT_RECVFROM_AVAIL) + { + ninfo("recvfrom avail.\n"); + + flags &= ~USRSOCK_EVENT_RECVFROM_AVAIL; + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->reqstate.recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_recvfrom_request + ****************************************************************************/ + +static int do_recvfrom_request(FAR struct usrsock_conn_s *conn, size_t buflen, + socklen_t addrlen) +{ + struct usrsock_request_recvfrom_s req = {}; + struct iovec bufs[1]; + + if (addrlen > UINT16_MAX) + { + addrlen = UINT16_MAX; + } + + if (buflen > UINT16_MAX) + { + buflen = UINT16_MAX; + } + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_RECVFROM; + req.usockid = conn->usockid; + req.max_addrlen = addrlen; + req.max_buflen = buflen; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Name: setup_conn_recvfrom + ****************************************************************************/ + +static void setup_conn_recvfrom(FAR struct usrsock_conn_s *conn, + FAR struct iovec *iov, unsigned int iovcnt) +{ + unsigned int i; + + conn->resp.datain.iov = iov; + conn->resp.datain.pos = 0; + conn->resp.datain.total = 0; + conn->resp.datain.iovcnt = iovcnt; + + for (i = 0; i < iovcnt; i++) + { + conn->resp.datain.total += iov[i].iov_len; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: usrsock_recvfrom + * + * Description: + * recvfrom() receives messages from a socket, and may be used to receive + * data on a socket whether or not it is connection-oriented. + * + * If from is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument fromlen + * initialized to the size of the buffer associated with from, and modified + * on return to indicate the actual size of the address stored there. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Buffer to receive data + * len Length of buffer + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + ****************************************************************************/ + +ssize_t usrsock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, + FAR struct sockaddr *from, FAR socklen_t *fromlen) +{ + FAR struct usrsock_conn_s *conn = psock->s_conn; + struct usrsock_data_reqstate_s state = {}; + struct iovec inbufs[2]; + socklen_t addrlen = 0; + socklen_t outaddrlen = 0; + ssize_t ret; +#ifdef CONFIG_NET_SOCKOPTS + struct timespec abstime; +#endif + struct timespec *ptimeo = NULL; + + DEBUGASSERT(conn); + + if (fromlen) + { + if (*fromlen > 0 && from == NULL) + { + return -EINVAL; + } + + addrlen = *fromlen; + } + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; connect() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; + goto errout_unlock; + } + + if (conn->type == SOCK_STREAM || conn->type == SOCK_SEQPACKET) + { + if (!conn->connected) + { + if (conn->state == USRSOCK_CONN_STATE_CONNECTING) + { + /* Connecting. */ + + ninfo("usockid=%d; socket still connecting.\n", + conn->usockid); + + ret = -EAGAIN; + goto errout_unlock; + } + else + { + /* Not connected. */ + + ninfo("usockid=%d; socket not connected.\n", + conn->usockid); + + ret = -ENOTCONN; + goto errout_unlock; + } + } + } + + if (conn->state == USRSOCK_CONN_STATE_CONNECTING) + { + /* Non-blocking connecting. */ + + ninfo("usockid=%d; socket still connecting.\n", + conn->usockid); + + ret = -EAGAIN; + goto errout_unlock; + } + +#ifdef CONFIG_NET_SOCKOPTS + if (psock->s_rcvtimeo != 0) + { + DEBUGVERIFY(clock_gettime(CLOCK_REALTIME, &abstime)); + + /* Prepare timeout value for recvfrom. */ + + abstime.tv_sec += psock->s_rcvtimeo / DSEC_PER_SEC; + abstime.tv_nsec += (psock->s_rcvtimeo % DSEC_PER_SEC) * NSEC_PER_DSEC; + if (abstime.tv_nsec >= NSEC_PER_SEC) + { + abstime.tv_sec++; + abstime.tv_nsec -= NSEC_PER_SEC; + } + + ptimeo = &abstime; + } +#endif + + do + { + /* Check if remote end has closed connection. */ + + if (conn->flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ninfo("usockid=%d; remote closed (EOF).\n", conn->usockid); + + ret = 0; + goto errout_unlock; + } + + /* Check if need to wait for receive data to become available. */ + + if (!(conn->flags & USRSOCK_EVENT_RECVFROM_AVAIL)) + { + if (_SS_ISNONBLOCK(psock->s_flags)) + { + /* Nothing to receive from daemon side. */ + + ret = -EAGAIN; + goto errout_unlock; + } + + /* Wait recv to become avail. */ + + ret = usrsock_setup_data_request_callback( + conn, &state, recvfrom_event, + USRSOCK_EVENT_ABORT | USRSOCK_EVENT_RECVFROM_AVAIL | + USRSOCK_EVENT_REMOTE_CLOSED); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_unlock; + } + + /* Wait for receive-avail (or abort, or timeout, or signal). */ + + ret = 0; + if (net_timedwait(&state.reqstate.recvsem, ptimeo) != OK) + { + ret = *get_errno_ptr(); + + if (ret == ETIMEDOUT) + { + ninfo("recvfrom timedout\n"); + + ret = -EAGAIN; + } + else if (ret == EINTR) + { + ninfo("recvfrom interrupted\n"); + + ret = -EINTR; + } + else + { + nerr("net_timedwait errno: %d\n", ret); + DEBUGASSERT(false); + } + } + + usrsock_teardown_data_request_callback(&state); + + /* Did wait timeout or got signal? */ + + if (ret != 0) + { + goto errout_unlock; + } + + /* Was socket aborted? */ + + if (conn->state == USRSOCK_CONN_STATE_ABORTED) + { + ret = -EPIPE; + goto errout_unlock; + } + + /* Did remote disconnect? */ + + if (conn->flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ret = 0; + goto errout_unlock; + } + + DEBUGASSERT(conn->flags & USRSOCK_EVENT_RECVFROM_AVAIL); + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_data_request_callback( + conn, &state, recvfrom_event, + USRSOCK_EVENT_ABORT | USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_unlock; + } + + inbufs[0].iov_base = (FAR void *)from; + inbufs[0].iov_len = addrlen; + inbufs[1].iov_base = (FAR void *)buf; + inbufs[1].iov_len = len; + + setup_conn_recvfrom(conn, inbufs, ARRAY_SIZE(inbufs)); + + /* Request user-space daemon to close socket. */ + + ret = do_recvfrom_request(conn, len, addrlen); + if (ret >= 0) + { + /* Wait for completion of request. */ + + while (net_lockedwait(&state.reqstate.recvsem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + } + + ret = state.reqstate.result; + + DEBUGASSERT(ret <= (ssize_t)len); + DEBUGASSERT(state.valuelen <= addrlen); + DEBUGASSERT(state.valuelen <= state.valuelen_nontrunc); + + if (ret >= 0) + { + /* Store length of 'from' address that was available at + * daemon-side. */ + + outaddrlen = state.valuelen_nontrunc; + } + } + + setup_conn_recvfrom(conn, NULL, 0); + usrsock_teardown_data_request_callback(&state); + } + while (ret == -EAGAIN); + +errout_unlock: + net_unlock(); + + if (fromlen) + { + *fromlen = outaddrlen; + } + + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_sendto.c b/net/usrsock/usrsock_sendto.c new file mode 100644 index 00000000000..dc747d451cf --- /dev/null +++ b/net/usrsock/usrsock_sendto.c @@ -0,0 +1,426 @@ +/**************************************************************************** + * net/usrsock/usrsock_sendto.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t sendto_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->result = -ECONNABORTED; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->result = conn->resp.result; + + if (pstate->result >= 0 || pstate->result == -EAGAIN) + { + /* After reception of data, mark input not ready. Daemon will + * send event to restore this flag. */ + + conn->flags &= ~USRSOCK_EVENT_SENDTO_READY; + } + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + else if (flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ninfo("remote closed.\n"); + + pstate->result = -EPIPE; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + else if (flags & USRSOCK_EVENT_SENDTO_READY) + { + ninfo("sendto ready.\n"); + + /* Do not let other waiters to claim new data. */ + + flags &= ~USRSOCK_EVENT_SENDTO_READY; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_sendto_request + ****************************************************************************/ + +static int do_sendto_request(FAR struct usrsock_conn_s *conn, + FAR const void *buf, size_t buflen, + FAR const struct sockaddr *addr, + socklen_t addrlen) +{ + struct usrsock_request_sendto_s req = {}; + struct iovec bufs[3]; + + if (addrlen > UINT16_MAX) + { + addrlen = UINT16_MAX; + } + + if (buflen > UINT16_MAX) + { + buflen = UINT16_MAX; + } + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_SENDTO; + req.usockid = conn->usockid; + req.addrlen = addrlen; + req.buflen = buflen; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + bufs[1].iov_base = (FAR void *)addr; + bufs[1].iov_len = addrlen; + bufs[2].iov_base = (FAR void *)buf; + bufs[2].iov_len = buflen; + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: usrsock_sendto + * + * Description: + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + ****************************************************************************/ + +ssize_t usrsock_sendto(FAR struct socket *psock, FAR const void *buf, + size_t len, FAR const struct sockaddr *to, + socklen_t tolen) +{ + FAR struct usrsock_conn_s *conn = psock->s_conn; + struct usrsock_reqstate_s state = {}; + ssize_t ret; +#ifdef CONFIG_NET_SOCKOPTS + struct timespec abstime; +#endif + struct timespec *ptimeo = NULL; + + DEBUGASSERT(conn); + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; connect() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; + goto errout_unlock; + } + + if (conn->type == SOCK_STREAM || conn->type == SOCK_SEQPACKET) + { + if (!conn->connected) + { + if (conn->state == USRSOCK_CONN_STATE_CONNECTING) + { + /* Connecting. */ + + ninfo("usockid=%d; socket still connecting.\n", + conn->usockid); + + ret = -EAGAIN; + goto errout_unlock; + } + else + { + /* Not connected. */ + + ret = -ENOTCONN; + goto errout_unlock; + } + } + + if (to || tolen) + { + /* Address provided for connection-mode socket */ + + ret = -EISCONN; + goto errout_unlock; + } + } + + if (conn->state == USRSOCK_CONN_STATE_CONNECTING) + { + /* Non-blocking connecting. */ + + ninfo("usockid=%d; socket still connecting.\n", conn->usockid); + + ret = -EAGAIN; + goto errout_unlock; + } + +#ifdef CONFIG_NET_SOCKOPTS + if (psock->s_sndtimeo != 0) + { + DEBUGVERIFY(clock_gettime(CLOCK_REALTIME, &abstime)); + + /* Prepare timeout value for sendto. */ + + abstime.tv_sec += psock->s_sndtimeo / DSEC_PER_SEC; + abstime.tv_nsec += (psock->s_sndtimeo % DSEC_PER_SEC) * NSEC_PER_DSEC; + if (abstime.tv_nsec >= NSEC_PER_SEC) + { + abstime.tv_sec++; + abstime.tv_nsec -= NSEC_PER_SEC; + } + + ptimeo = &abstime; + } +#endif + + do + { + /* Check if remote end has closed connection. */ + + if (conn->flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ninfo("usockid=%d; remote closed.\n", conn->usockid); + + ret = -EPIPE; + goto errout_unlock; + } + + /* Check if need to wait for send to become ready. */ + + if (!(conn->flags & USRSOCK_EVENT_SENDTO_READY)) + { + if (_SS_ISNONBLOCK(psock->s_flags)) + { + /* Send busy at daemon side. */ + + ret = -EAGAIN; + goto errout_unlock; + } + + /* Wait send to become ready. */ + + ret = usrsock_setup_request_callback(conn, &state, sendto_event, + USRSOCK_EVENT_ABORT | + USRSOCK_EVENT_SENDTO_READY | + USRSOCK_EVENT_REMOTE_CLOSED); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_unlock; + } + + /* Wait for send-ready (or abort, or timeout, or signal). */ + + ret = 0; + if (net_timedwait(&state.recvsem, ptimeo) != OK) + { + ret = *get_errno_ptr(); + + if (ret == ETIMEDOUT) + { + ninfo("sendto timedout\n"); + + ret = -EAGAIN; + } + else if (ret == EINTR) + { + ninfo("sendto interrupted\n"); + + ret = -EINTR; + } + else + { + nerr("net_timedwait errno: %d\n", ret); + DEBUGASSERT(false); + } + } + + usrsock_teardown_request_callback(&state); + + /* Did wait timeout or got signal? */ + + if (ret != 0) + { + goto errout_unlock; + } + + /* Was socket aborted? */ + + if (conn->state == USRSOCK_CONN_STATE_ABORTED) + { + ret = -EPIPE; + goto errout_unlock; + } + + /* Did remote disconnect? */ + + if (conn->flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ret = -EPIPE; + goto errout_unlock; + } + + DEBUGASSERT(conn->flags & USRSOCK_EVENT_SENDTO_READY); + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_request_callback(conn, &state, sendto_event, + USRSOCK_EVENT_ABORT | + USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_unlock; + } + + /* Request user-space daemon to close socket. */ + + ret = do_sendto_request(conn, buf, len, to, tolen); + if (ret >= 0) + { + /* Wait for completion of request. */ + + while (net_lockedwait(&state.recvsem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + } + + ret = state.result; + + DEBUGASSERT(ret <= (ssize_t)len); + } + + usrsock_teardown_request_callback(&state); + } + while (ret == -EAGAIN); + +errout_unlock: + net_unlock(); + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_setsockopt.c b/net/usrsock/usrsock_setsockopt.c new file mode 100644 index 00000000000..5795fdee948 --- /dev/null +++ b/net/usrsock/usrsock_setsockopt.c @@ -0,0 +1,230 @@ +/**************************************************************************** + * net/usrsock/usrsock_setsockopt.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) && \ + defined(CONFIG_NET_SOCKOPTS) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t setsockopt_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->result = -ECONNABORTED; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->result = conn->resp.result; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_setsockopt_request + ****************************************************************************/ + +static int do_setsockopt_request(FAR struct usrsock_conn_s *conn, + int level, int option, FAR const void *value, + socklen_t value_len) +{ + struct usrsock_request_setsockopt_s req = {}; + struct iovec bufs[2]; + + if (level < INT16_MIN || level > INT16_MAX) + { + return -EINVAL; + } + + if (option < INT16_MIN || option > INT16_MAX) + { + return -EINVAL; + } + + if (value_len > UINT16_MAX) + { + value_len = UINT16_MAX; + } + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_SETSOCKOPT; + req.usockid = conn->usockid; + req.level = level; + req.option = option; + req.valuelen = value_len; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + bufs[1].iov_base = (FAR void *)value; + bufs[1].iov_len = req.valuelen; + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: usrsock_setsockopt + * + * Description: + * psock_setsockopt() sets the option specified by the 'option' argument, + * at the protocol level specified by the 'level' argument, to the value + * pointed to by the 'value' argument for the socket on the 'psock' argument. + * + * The 'level' argument specifies the protocol level of the option. To set + * options at the socket level, specify the level argument as SOL_SOCKET. + * + * See a complete list of values for the 'option' argument. + * + * Parameters: + * conn usrsock socket connection structure + * level Protocol level to set the option + * option identifies the option to set + * value Points to the argument value + * value_len The length of the argument value + * + ****************************************************************************/ + +int usrsock_setsockopt(FAR struct usrsock_conn_s *conn, int level, int option, + FAR const void *value, FAR socklen_t value_len) +{ + struct usrsock_reqstate_s state = {}; + ssize_t ret; + + DEBUGASSERT(conn); + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; connect() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; + goto errout_unlock; + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_request_callback(conn, &state, setsockopt_event, + USRSOCK_EVENT_ABORT | + USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_unlock; + } + + /* Request user-space daemon to close socket. */ + + ret = do_setsockopt_request(conn, level, option, value, value_len); + if (ret >= 0) + { + /* Wait for completion of request. */ + + while (net_lockedwait(&state.recvsem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + } + + ret = state.result; + } + + usrsock_teardown_request_callback(&state); + +errout_unlock: + net_unlock(); + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK && CONFIG_NET_SOCKOPTS */ diff --git a/net/usrsock/usrsock_socket.c b/net/usrsock/usrsock_socket.c new file mode 100644 index 00000000000..71764befea6 --- /dev/null +++ b/net/usrsock/usrsock_socket.c @@ -0,0 +1,265 @@ +/**************************************************************************** + * net/usrsock/usrsock_socket.c + * + * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "devif/devif.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t socket_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->result = -ENETDOWN; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->result = conn->resp.result; + if (pstate->result >= 0) + { + /* We might start getting events for this socket right after + * returning to daemon, so setup 'conn' already here. */ + + conn->state = USRSOCK_CONN_STATE_READY; + conn->usockid = pstate->result; + } + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_socket_request + ****************************************************************************/ + +static int do_socket_request(FAR struct usrsock_conn_s *conn, int domain, + int type, int protocol) +{ + struct usrsock_request_socket_s req = {}; + struct iovec bufs[1]; + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_SOCKET; + req.domain = domain; + req.type = type; + req.protocol = protocol; + + if (req.domain != domain) + { + return -EINVAL; + } + + if (req.type != type) + { + return -EINVAL; + } + + if (req.protocol != protocol) + { + return -EINVAL; + } + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: usrsock_socket + * + * Description: + * socket() creates an endpoint for communication and returns a socket + * structure. + * + * Parameters: + * domain (see sys/socket.h) + * type (see sys/socket.h) + * protocol (see sys/socket.h) + * psock A pointer to a user allocated socket structure to be initialized. + * + * Returned Value: + * 0 on success; negative error-code on error + * + * EACCES + * Permission to create a socket of the specified type and/or protocol + * is denied. + * EAFNOSUPPORT + * The implementation does not support the specified address family. + * EINVAL + * Unknown protocol, or protocol family not available. + * EMFILE + * Process file table overflow. + * ENFILE + * The system limit on the total number of open files has been reached. + * ENOBUFS or ENOMEM + * Insufficient memory is available. The socket cannot be created until + * sufficient resources are freed. + * EPROTONOSUPPORT + * The protocol type or the specified protocol is not supported within + * this domain. + * + * Assumptions: + * + ****************************************************************************/ + +int usrsock_socket(int domain, int type, int protocol, FAR struct socket *psock) +{ + struct usrsock_reqstate_s state = {}; + FAR struct usrsock_conn_s *conn; + int err; + + /* Allocate the usrsock socket connection structure and save in the new + * socket instance. + */ + + conn = usrsock_alloc(); + if (!conn) + { + /* Failed to reserve a connection structure */ + + return -ENOMEM; + } + + net_lock(); + + /* Set up event callback for usrsock. */ + + err = usrsock_setup_request_callback(conn, &state, socket_event, + USRSOCK_EVENT_ABORT | + USRSOCK_EVENT_REQ_COMPLETE); + if (err < 0) + { + goto errout_free_conn; + } + + /* Request user-space daemon for new socket. */ + + err = do_socket_request(conn, domain, type, protocol); + if (err < 0) + { + goto errout_teardown_callback; + } + + /* Wait for completion of request. */ + + while (net_lockedwait(&state.recvsem) != OK) + { + DEBUGASSERT(*get_errno_ptr() == EINTR); + } + + if (state.result < 0) + { + err = state.result; + goto errout_teardown_callback; + } + + psock->s_type = SOCK_USRSOCK_TYPE; + psock->s_domain = PF_USRSOCK_DOMAIN; + conn->type = type; + psock->s_conn = conn; + conn->crefs = 1; + + usrsock_teardown_request_callback(&state); + + net_unlock(); + + return OK; + +errout_teardown_callback: + usrsock_teardown_request_callback(&state); +errout_free_conn: + usrsock_free(conn); + net_unlock(); + + return err; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */