Introduction of sequential-API build variant, better thread safety (lwIP only)

This commit is contained in:
Joseph Henry
2017-09-27 02:29:04 -07:00
parent e4620e4c85
commit 5f1e9fe795
176 changed files with 16494 additions and 20406 deletions

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_ARCH_CC_H
#define LWIP_ARCH_CC_H
/* see https://sourceforge.net/p/predef/wiki/OperatingSystems/ */
#if defined __ANDROID__
#define LWIP_UNIX_ANDROID
#elif defined __linux__
#define LWIP_UNIX_LINUX
#elif defined __APPLE__
#define LWIP_UNIX_MACH
#elif defined __OpenBSD__
#define LWIP_UNIX_OPENBSD
#elif defined __CYGWIN__
#define LWIP_UNIX_CYGWIN
#endif
#define LWIP_TIMEVAL_PRIVATE 0
#include <sys/time.h>
#define LWIP_ERRNO_INCLUDE <errno.h>
#define LWIP_RAND() ((u32_t)rand())
/* different handling for unit test, normally not needed */
#ifdef LWIP_NOASSERT_ON_ERROR
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
handler;}} while(0)
#endif
#if defined(LWIP_UNIX_ANDROID) && defined(FD_SET)
typedef __kernel_fd_set fd_set;
#endif
struct sio_status_s;
typedef struct sio_status_s sio_status_t;
#define sio_fd_t sio_status_t*
#define __sio_fd_t_defined
#endif /* LWIP_ARCH_CC_H */

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_ARCH_PERF_H
#define LWIP_ARCH_PERF_H
#include <sys/times.h>
#ifdef PERF
#define PERF_START { \
unsigned long __c1l, __c1h, __c2l, __c2h; \
__asm__(".byte 0x0f, 0x31" : "=a" (__c1l), "=d" (__c1h))
#define PERF_STOP(x) __asm__(".byte 0x0f, 0x31" : "=a" (__c2l), "=d" (__c2h)); \
perf_print(__c1l, __c1h, __c2l, __c2h, x);}
/*#define PERF_START do { \
struct tms __perf_start, __perf_end; \
times(&__perf_start)
#define PERF_STOP(x) times(&__perf_end); \
perf_print_times(&__perf_start, &__perf_end, x);\
} while(0)*/
#else /* PERF */
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */
#endif /* PERF */
void perf_print(unsigned long c1l, unsigned long c1h,
unsigned long c2l, unsigned long c2h,
char *key);
void perf_print_times(struct tms *start, struct tms *end, char *key);
void perf_init(char *fname);
#endif /* LWIP_ARCH_PERF_H */

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_ARCH_SYS_ARCH_H
#define LWIP_ARCH_SYS_ARCH_H
#define SYS_MBOX_NULL NULL
#define SYS_SEM_NULL NULL
typedef u32_t sys_prot_t;
struct sys_sem;
typedef struct sys_sem * sys_sem_t;
#define sys_sem_valid(sem) (((sem) != NULL) && (*(sem) != NULL))
#define sys_sem_valid_val(sem) ((sem) != NULL)
#define sys_sem_set_invalid(sem) do { if((sem) != NULL) { *(sem) = NULL; }}while(0)
#define sys_sem_set_invalid_val(sem) do { (sem) = NULL; }while(0)
struct sys_mutex;
typedef struct sys_mutex * sys_mutex_t;
#define sys_mutex_valid(mutex) sys_sem_valid(mutex)
#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex)
struct sys_mbox;
typedef struct sys_mbox * sys_mbox_t;
#define sys_mbox_valid(mbox) sys_sem_valid(mbox)
#define sys_mbox_valid_val(mbox) sys_sem_valid_val(mbox)
#define sys_mbox_set_invalid(mbox) sys_sem_set_invalid(mbox)
#define sys_mbox_set_invalid_val(mbox) sys_sem_set_invalid_val(mbox)
struct sys_thread;
typedef struct sys_thread * sys_thread_t;
#endif /* LWIP_ARCH_SYS_ARCH_H */

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_DELIF_H
#define LWIP_DELIF_H
#include "lwip/netif.h"
#include "lwip/pbuf.h"
err_t delif_init(struct netif *netif);
err_t delif_init_thread(struct netif *netif);
#endif /* LWIP_DELIF_H */

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_DROPIF_H
#define LWIP_DROPIF_H
#include "lwip/netif.h"
#include "lwip/pbuf.h"
err_t dropif_init(struct netif *netif);
#endif /* LWIP_DROPIF_H */

View File

@@ -0,0 +1,54 @@
#ifndef FIFO_H
#define FIFO_H
#include "lwip/sys.h"
/** How many bytes in fifo */
#define FIFOSIZE 2048
/** fifo data structure, this one is passed to all fifo functions */
typedef struct fifo_t {
u8_t data[FIFOSIZE+10]; /* data segment, +10 is a hack probably not needed.. FIXME! */
int dataslot; /* index to next char to be read */
int emptyslot; /* index to next empty slot */
int len; /* len probably not needed, may be calculated from dataslot and emptyslot in conjunction with FIFOSIZE */
sys_sem_t sem; /* semaphore protecting simultaneous data manipulation */
sys_sem_t getSem; /* sepaphore used to signal new data if getWaiting is set */
u8_t getWaiting; /* flag used to indicate that fifoget is waiting for data. fifoput is suposed to clear */
/* this flag prior to signaling the getSem semaphore */
} fifo_t;
/**
* Get a character from fifo
* Blocking call.
* @param fifo pointer to fifo data structure
* @return character read from fifo
*/
u8_t fifoGet(fifo_t * fifo);
/**
* Get a character from fifo
* Non blocking call.
* @param fifo pointer to fifo data structure
* @return character read from fifo, or < zero if non was available
*/
s16_t fifoGetNonBlock(fifo_t * fifo);
/**
* fifoput is called by the signalhandler when new data has arrived (or some other event is indicated)
* fifoput reads directly from the serialport and is thus highly dependent on unix arch at this moment
* @param fifo pointer to fifo data structure
* @param fd unix file descriptor
*/
void fifoPut(fifo_t * fifo, int fd);
/**
* fifoinit initiate fifo
* @param fifo pointer to fifo data structure, allocated by the user
*/
void fifoInit(fifo_t * fifo);
#endif

View File

@@ -0,0 +1,26 @@
#ifndef LWIP_LIST_H
#define LWIP_LIST_H
struct elem;
struct list {
struct elem *first, *last;
int size, elems;
};
struct elem {
struct elem *next;
void *data;
};
struct list *list_new(int size);
int list_push(struct list *list, void *data);
void *list_pop(struct list *list);
void *list_first(struct list *list);
int list_elems(struct list *list);
void list_delete(struct list *list);
int list_remove(struct list *list, void *elem);
void list_map(struct list *list, void (* func)(void *arg));
#endif

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_PCAPIF_H
#define LWIP_PCAPIF_H
#include "lwip/netif.h"
err_t pcapif_init(struct netif *netif);
#endif /* LWIP_PCAPIF_H */

View File

@@ -0,0 +1,60 @@
#ifndef SIO_UNIX_H
#define SIO_UNIX_H
#include "lwip/sys.h"
#include "lwip/netif.h"
#include "netif/fifo.h"
/*#include "netif/pppif.h"*/
struct sio_status_s {
int fd;
fifo_t myfifo;
};
/* BAUDRATE is defined in sio.c as it is implementation specific */
/** Baudrates */
typedef enum sioBaudrates {
SIO_BAUD_9600,
SIO_BAUD_19200,
SIO_BAUD_38400,
SIO_BAUD_57600,
SIO_BAUD_115200
} sioBaudrates;
/**
* Poll for a new character from incoming data stream
* @param siostat siostatus struct, contains sio instance data, given by sio_open
* @return char read from input stream, or < 0 if no char was available
*/
s16_t sio_poll(sio_status_t * siostat);
/**
* Parse incoming characters until a string str is recieved, blocking call
* @param str zero terminated string to expect
* @param siostat siostatus struct, contains sio instance data, given by sio_open
*/
void sio_expect_string(u8_t *str, sio_status_t * siostat);
/**
* Write a char to output data stream
* @param str pointer to a zero terminated string
* @param siostat siostatus struct, contains sio instance data, given by sio_open
*/
void sio_send_string(u8_t *str, sio_status_t * siostat);
/**
* Flush outbuffer (send everything in buffer now), useful if some layer below is
* holding on to data, waitng to fill a buffer
* @param siostat siostatus struct, contains sio instance data, given by sio_open
*/
void sio_flush( sio_status_t * siostat );
/**
* Change baudrate of port, may close and reopen port
* @param baud new baudrate
* @param siostat siostatus struct, contains sio instance data, given by sio_open
*/
void sio_change_baud( sioBaudrates baud, sio_status_t * siostat );
#endif

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_TAPIF_H
#define LWIP_TAPIF_H
#include "lwip/netif.h"
err_t tapif_init(struct netif *netif);
#if NO_SYS
int tapif_select(struct netif *netif);
#endif /* NO_SYS */
#endif /* LWIP_TAPIF_H */

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_NETIF_TCPDUMP_H
#define LWIP_NETIF_TCPDUMP_H
struct pbuf;
struct netif;
void tcpdump_init(void);
void tcpdump(struct pbuf *p, struct netif *netif);
#endif /* LWIP_NETIF_TCPDUMP_H */

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_TUNIF_H
#define LWIP_TUNIF_H
#include "lwip/netif.h"
#include "lwip/pbuf.h"
err_t tunif_init(struct netif *netif);
#endif /* LWIP_TUNIF_H */

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_UNIXIF_H
#define LWIP_UNIXIF_H
#include "lwip/netif.h"
err_t unixif_init_server(struct netif *netif);
err_t unixif_init_client(struct netif *netif);
#endif /* LWIP_UNIXIF_H */

View File

@@ -0,0 +1,384 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#if !NO_SYS
#include "lwip/debug.h"
#include <stdlib.h>
#include "lwip/def.h"
#include "netif/delif.h"
#ifdef LWIP_UNIX_LINUX
#include "netif/tapif.h"
#else /* LWIP_UNIX_LINUX */
#include "netif/tunif.h"
#endif /* LWIP_UNIX_LINUX */
#include "lwip/sys.h"
#include "lwip/timeouts.h"
#ifndef DELIF_DEBUG
#define DELIF_DEBUG LWIP_DBG_OFF
#endif
#define DELIF_INPUT_DROPRATE 0.1
#define DELIF_OUTPUT_DROPRATE 0.1
#define DELIF_INPUT_DELAY 500 /* Miliseconds. */
#define DELIF_OUTPUT_DELAY 500 /* Miliseconds. */
#define DELIF_TIMEOUT 10
struct delif {
err_t (* input)(struct pbuf *p, struct netif *inp);
struct netif *netif;
};
struct delif_pbuf {
struct delif_pbuf *next;
struct pbuf *p;
ip_addr_t ipaddr;
unsigned int time;
};
static struct delif_pbuf *input_list = NULL;
static struct delif_pbuf *output_list = NULL;
/*-----------------------------------------------------------------------------------*/
static void
delif_input_timeout(void *arg)
{
struct netif *netif;
struct delif *delif;
struct delif_pbuf *dp;
unsigned int timeout, now;
timeout = DELIF_TIMEOUT;
netif = (struct netif*)arg;
delif = (struct delif*)netif->state;
/* Check if there is anything on the input list. */
dp = input_list;
while (dp != NULL) {
now = sys_now();
if (dp->time <= now) {
delif->input(dp->p, netif);
if (dp->next != NULL) {
if (dp->next->time > now) {
timeout = dp->next->time - now;
} else {
timeout = 0;
}
LWIP_DEBUGF(DELIF_DEBUG, ("delif_output_timeout: timeout %u.\n", timeout));
}
input_list = dp->next;
free(dp);
dp = input_list;
} else {
dp = dp->next;
}
}
sys_timeout(timeout, delif_input_timeout, arg);
}
/*-----------------------------------------------------------------------------------*/
static void
delif_output_timeout(void *arg)
{
struct netif *netif;
struct delif *delif;
struct delif_pbuf *dp;
unsigned int timeout, now;
timeout = DELIF_TIMEOUT;
netif = (struct netif*)arg;
delif = (struct delif*)netif->state;
/* Check if there is anything on the output list. */
dp = output_list;
while (dp != NULL) {
now = sys_now();
if (dp->time <= now) {
LWIP_DEBUGF(DELIF_DEBUG, ("delif_output_timeout: now %u dp->time %u\n",
now, dp->time));
#if LWIP_IPV4
if(!IP_IS_V6_VAL(dp->ipaddr)) {
delif->netif->output(delif->netif, dp->p, ip_2_ip4(&dp->ipaddr));
}
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
if(IP_IS_V6_VAL(dp->ipaddr)) {
delif->netif->output_ip6(delif->netif, dp->p, ip_2_ip6(&dp->ipaddr));
}
#endif /* LWIP_IPV6 */
if (dp->next != NULL) {
if (dp->next->time > now) {
timeout = dp->next->time - now;
} else {
timeout = 0;
}
LWIP_DEBUGF(DELIF_DEBUG, ("delif_output_timeout: timeout %u.\n", timeout));
}
pbuf_free(dp->p);
output_list = dp->next;
free(dp);
dp = output_list;
} else {
dp = dp->next;
}
}
sys_timeout(timeout, delif_output_timeout, arg);
}
/*-----------------------------------------------------------------------------------*/
static err_t
delif_output(struct netif *netif, struct pbuf *p, const ip_addr_t *ipaddr)
{
struct delif_pbuf *dp, *np;
char *data;
LWIP_UNUSED_ARG(netif);
LWIP_DEBUGF(DELIF_DEBUG, ("delif_output\n"));
#ifdef DELIF_OUTPUT_DROPRATE
if (((double)rand()/(double)RAND_MAX) < DELIF_OUTPUT_DROPRATE) {
LWIP_DEBUGF(DELIF_DEBUG, ("delif_output: Packet dropped\n"));
return ERR_BUF;
}
#endif /* DELIF_OUTPUT_DROPRATE */
LWIP_DEBUGF(DELIF_DEBUG, ("delif_output\n"));
dp = (struct delif_pbuf*)malloc(sizeof(struct delif_pbuf));
data = (char*)malloc(p->tot_len);
pbuf_copy_partial(p, data, p->tot_len, 0);
dp->p = pbuf_alloc(PBUF_LINK, 0, PBUF_ROM);
dp->p->payload = data;
dp->p->len = p->tot_len;
dp->p->tot_len = p->tot_len;
dp->ipaddr = *ipaddr;
dp->time = sys_now() + DELIF_OUTPUT_DELAY;
dp->next = NULL;
if (output_list == NULL) {
output_list = dp;
} else {
for(np = output_list; np->next != NULL; np = np->next);
np->next = dp;
}
return ERR_OK;
}
#if LWIP_IPV4
static err_t
delif_output4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
{
ip_addr_t ip;
if (ipaddr != NULL) {
ip_addr_copy_from_ip4(ip, *ipaddr);
} else {
ip = *IP_ADDR_ANY;
}
return delif_output(netif, p, &ip);
}
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
static err_t
delif_output6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr)
{
ip_addr_t ip;
if (ipaddr != NULL) {
ip_addr_copy_from_ip6(ip, *ipaddr);
} else {
ip = *IP6_ADDR_ANY;
}
return delif_output(netif, p, &ip);
}
#endif /* LWIP_IPV6 */
/*-----------------------------------------------------------------------------------*/
static err_t
delif_input(struct pbuf *p, struct netif *inp)
{
struct delif_pbuf *dp, *np;
LWIP_UNUSED_ARG(inp);
LWIP_DEBUGF(DELIF_DEBUG, ("delif_input\n"));
#ifdef DELIF_INPUT_DROPRATE
if (((double)rand()/(double)RAND_MAX) < DELIF_INPUT_DROPRATE) {
LWIP_DEBUGF(DELIF_DEBUG, ("delif_input: Packet dropped\n"));
pbuf_free(p);
return ERR_OK;
}
#endif /* DELIF_INPUT_DROPRATE */
dp = (struct delif_pbuf*)malloc(sizeof(struct delif_pbuf));
dp->p = p;
dp->time = sys_now() + DELIF_INPUT_DELAY;
dp->next = NULL;
if (input_list == NULL) {
input_list = dp;
} else {
for(np = input_list; np->next != NULL; np = np->next);
np->next = dp;
}
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
err_t
delif_init(struct netif *netif)
{
struct delif *del;
del = (struct delif*)malloc(sizeof(struct delif));
if (!del) {
return ERR_MEM;
}
netif->state = del;
netif->name[0] = 'd';
netif->name[1] = 'e';
#if LWIP_IPV4
netif->output = delif_output4;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
netif->output_ip6 = delif_output6;
#endif /* LWIP_IPV6 */
del->netif = (struct netif*)malloc(sizeof(struct netif));
if (!del->netif) {
free(del);
return ERR_MEM;
}
#ifdef LWIP_UNIX_LINUX
tapif_init(del->netif);
#else /* LWIP_UNIX_LINUX */
tunif_init(del->netif);
#endif /* LWIP_UNIX_LINUX */
del->input = netif->input;
del->netif->input = delif_input;
sys_timeout(DELIF_TIMEOUT, delif_input_timeout, netif);
sys_timeout(DELIF_TIMEOUT, delif_output_timeout, netif);
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
static void
delif_thread(void *arg)
{
struct netif *netif = (struct netif*)arg;
struct delif *del;
sys_sem_t sem;
del = (struct delif*)netif->state;
#ifdef LWIP_UNIX_LINUX
tapif_init(del->netif);
#else /* LWIP_UNIX_LINUX */
tunif_init(del->netif);
#endif /* LWIP_UNIX_LINUX */
sys_timeout(DELIF_TIMEOUT, delif_input_timeout, netif);
sys_timeout(DELIF_TIMEOUT, delif_output_timeout, netif);
if(sys_sem_new(&sem, 0) != ERR_OK) {
LWIP_ASSERT("Failed to create semaphore", 0);
}
sys_sem_wait(&sem);
}
/*-----------------------------------------------------------------------------------*/
err_t
delif_init_thread(struct netif *netif)
{
struct delif *del;
LWIP_DEBUGF(DELIF_DEBUG, ("delif_init_thread\n"));
del = (struct delif*)malloc(sizeof(struct delif));
if (!del) {
return ERR_MEM;
}
netif->state = del;
netif->name[0] = 'd';
netif->name[1] = 'e';
del->netif = (struct netif*)malloc(sizeof(struct netif));
if (!del->netif) {
free(del);
return ERR_MEM;
}
#if LWIP_IPV4
netif->output = delif_output4;
netif_set_addr(del->netif, netif_ip4_addr(netif), netif_ip4_netmask(netif), netif_ip4_gw(netif));
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
{
s8_t i;
netif->output_ip6 = delif_output6;
for(i=0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
netif_ip6_addr_set(del->netif, i, netif_ip6_addr(netif, i));
}
}
#endif /* LWIP_IPV6 */
del->input = netif->input;
del->netif->input = delif_input;
sys_thread_new("delif_thread", delif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
#endif /* !NO_SYS */

View File

@@ -0,0 +1,139 @@
/* Author: Magnus Ivarsson <magnus.ivarsson@volvo.com> */
/* ---------------------------------------------- */
/* --- fifo 4 unix ------------------------------ */
/* ---------------------------------------------- */
#include "lwip/err.h"
#include "netif/fifo.h"
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/arch.h"
#include <unistd.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef SIO_FIFO_DEBUG
#define SIO_FIFO_DEBUG LWIP_DBG_OFF
#endif
u8_t fifoGet(fifo_t * fifo)
{
u8_t c;
sys_sem_wait(&fifo->sem); /* enter critical section */
if (fifo->dataslot == fifo->emptyslot)
{
fifo->getWaiting = TRUE; /* tell putFifo to signal us when data is available */
sys_sem_signal(&fifo->sem); /* leave critical section (allow input from serial port..) */
sys_sem_wait(&fifo->getSem); /* wait 4 data */
sys_sem_wait(&fifo->sem); /* reenter critical section */
}
c = fifo->data[fifo->dataslot++];
fifo->len--;
if (fifo->dataslot == FIFOSIZE)
{
fifo->dataslot = 0;
}
sys_sem_signal(&fifo->sem); /* leave critical section */
return c;
}
s16_t fifoGetNonBlock(fifo_t * fifo)
{
u16_t c;
sys_sem_wait(&fifo->sem); /* enter critical section */
if (fifo->dataslot == fifo->emptyslot)
{
/* empty fifo */
c = -1;
}
else
{
c = fifo->data[fifo->dataslot++];
fifo->len--;
if (fifo->dataslot == FIFOSIZE)
{
fifo->dataslot = 0;
}
}
sys_sem_signal(&fifo->sem); /* leave critical section */
return c;
}
void fifoPut(fifo_t * fifo, int fd)
{
/* FIXME: mutex around struct data.. */
int cnt=0;
sys_sem_wait(&fifo->sem ); /* enter critical */
LWIP_DEBUGF( SIO_FIFO_DEBUG,("fifoput: len%d dat%d empt%d --> ", fifo->len, fifo->dataslot, fifo->emptyslot ) );
if ( fifo->emptyslot < fifo->dataslot )
{
cnt = read( fd, &fifo->data[fifo->emptyslot], fifo->dataslot - fifo->emptyslot );
}
else
{
cnt = read( fd, &fifo->data[fifo->emptyslot], FIFOSIZE-fifo->emptyslot );
}
fifo->emptyslot += cnt;
fifo->len += cnt;
LWIP_DEBUGF( SIO_FIFO_DEBUG,("len%d dat%d empt%d\n", fifo->len, fifo->dataslot, fifo->emptyslot ) );
if ( fifo->len > FIFOSIZE )
{
printf( "ERROR: fifo overrun detected len=%d, flushing\n", fifo->len );
fifo->dataslot = 0;
fifo->emptyslot = 0;
fifo->len = 0;
}
if ( fifo->emptyslot == FIFOSIZE )
{
fifo->emptyslot = 0;
LWIP_DEBUGF( SIO_FIFO_DEBUG, ("(WRAP) ") );
sys_sem_signal(&fifo->sem ); /* leave critical */
fifoPut( fifo, fd );
return;
}
if ( fifo->getWaiting )
{
fifo->getWaiting = FALSE;
sys_sem_signal(&fifo->getSem );
}
sys_sem_signal(&fifo->sem ); /* leave critical */
return;
}
void fifoInit(fifo_t * fifo)
{
fifo->dataslot = 0;
fifo->emptyslot = 0;
fifo->len = 0;
if(sys_sem_new(&fifo->sem, 1) != ERR_OK) { /* critical section 1=free to enter */
LWIP_ASSERT("Failed to create semaphore", 0);
}
if(sys_sem_new(&fifo->getSem, 0) != ERR_OK) { /* 0 = no one waiting */
LWIP_ASSERT("Failed to create semaphore", 0);
}
fifo->getWaiting = FALSE;
}

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include <stdlib.h>
#include <netif/list.h>
/*-----------------------------------------------------------------------------------*/
struct list *
list_new(int size)
{
struct list *list;
list = (struct list *)malloc(sizeof(struct list));
list->first = list->last = NULL;
list->size = size;
list->elems = 0;
return list;
}
/*-----------------------------------------------------------------------------------*/
int
list_push(struct list *list, void *data)
{
struct elem *elem;
if (list->elems < list->size) {
elem = (struct elem *)malloc(sizeof(struct elem));
elem->data = data;
elem->next = NULL;
if (list->last != NULL) {
list->last->next = elem;
}
list->last = elem;
if (list->first == NULL) {
list->first = elem;
}
list->elems++;
return 1;
}
return 0;
}
/*-----------------------------------------------------------------------------------*/
void *
list_pop(struct list *list)
{
struct elem *elem;
void *data;
if (list->elems > 0) {
elem = list->first;
if (elem == list->last) {
list->last = elem->next;
}
list->first = elem->next;
list->elems--;
data = elem->data;
free(elem);
return data;
}
return NULL;
}
/*-----------------------------------------------------------------------------------*/
void *
list_first(struct list *list)
{
return list->first;
}
/*-----------------------------------------------------------------------------------*/
int
list_elems(struct list *list)
{
return list->elems;
}
/*-----------------------------------------------------------------------------------*/
void
list_delete(struct list *list)
{
while (list_pop(list) != NULL);
free(list);
}
/*-----------------------------------------------------------------------------------*/
int
list_remove(struct list *list, void *elem)
{
struct elem *e, *p;
p = NULL;
for(e = list->first; e != NULL; e = e->next) {
if (e->data == elem) {
if (p != NULL) {
p->next = e->next;
} else {
list->first = e->next;
}
if (list->last == e) {
list->last = p;
if (p != NULL) {
p->next = NULL;
}
}
free(e);
list->elems--;
return 1;
}
p = e;
}
return 0;
}
/*-----------------------------------------------------------------------------------*/
void
list_map(struct list *list, void (* func)(void *arg))
{
struct elem *e;
for(e = list->first; e != NULL; e = e->next) {
func(e->data);
}
}
/*-----------------------------------------------------------------------------------*/

View File

@@ -0,0 +1,216 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef linux /* Apparently, this doesn't work under Linux. */
#include "lwip/debug.h"
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pcap.h>
#include "netif/etharp.h"
#include "lwip/stats.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "netif/unixif.h"
#include "lwip/sys.h"
#include "lwip/ip.h"
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
#include "netif/tcpdump.h"
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
struct pcapif {
pcap_t *pd;
sys_sem_t sem;
u8_t pkt[2048];
u32_t len;
u32_t lasttime;
struct pbuf *p;
struct eth_addr *ethaddr;
};
static char errbuf[PCAP_ERRBUF_SIZE];
/*-----------------------------------------------------------------------------------*/
static err_t
pcapif_output(struct netif *netif, struct pbuf *p,
ip_addr_t *ipaddr)
{
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
static void
timeout(void *arg)
{
struct netif *netif;
struct pcapif *pcapif;
struct pbuf *p;
struct eth_hdr *ethhdr;
netif = (struct netif *)arg;
pcapif = netif->state;
ethhdr = (struct eth_hdr *)pcapif->pkt;
if (lwip_htons(ethhdr->type) != ETHTYPE_IP ||
ip_lookup(pcapif->pkt + 14, netif)) {
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_LINK, pcapif->len, PBUF_POOL);
if (p != NULL) {
pbuf_take(p, pcapif->pkt, pcapif->len);
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
tcpdump(p, netif);
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
ethhdr = p->payload;
switch (lwip_htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
case ETHTYPE_PPPOEDISC:
case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
p = NULL;
}
break;
default:
pbuf_free(p);
break;
}
}
} else {
printf("ip_lookup dropped\n");
}
sys_sem_signal(&pcapif->sem);
}
/*-----------------------------------------------------------------------------------*/
static void
callback(u_char *arg, const struct pcap_pkthdr *hdr, const u_char *pkt)
{
struct netif *netif;
struct pcapif *pcapif;
u32_t time, lasttime;
netif = (struct netif *)arg;
pcapif = netif->state;
pcapif->len = hdr->len;
bcopy(pkt, pcapif->pkt, hdr->len);
time = hdr->ts.tv_sec * 1000 + hdr->ts.tv_usec / 1000;
lasttime = pcapif->lasttime;
pcapif->lasttime = time;
if (lasttime == 0) {
sys_timeout(1000, timeout, netif);
} else {
sys_timeout(time - lasttime, timeout, netif);
}
}
/*-----------------------------------------------------------------------------------*/
static void
pcapif_thread(void *arg)
{
struct netif *netif;
struct pcapif *pcapif;
netif = arg;
pcapif = netif->state;
while (1) {
pcap_loop(pcapif->pd, 1, callback, (u_char *)netif);
sys_sem_wait(&pcapif->sem);
if (pcapif->p != NULL) {
netif->input(pcapif->p, netif);
}
}
}
/*-----------------------------------------------------------------------------------*/
err_t
pcapif_init(struct netif *netif)
{
struct pcapif *p;
p = malloc(sizeof(struct pcapif));
if (p == NULL)
return ERR_MEM;
netif->state = p;
netif->name[0] = 'p';
netif->name[1] = 'c';
netif->output = pcapif_output;
p->pd = pcap_open_offline("pcapdump", errbuf);
if (p->pd == NULL) {
printf("pcapif_init: failed %s\n", errbuf);
return ERR_IF;
}
if(sys_sem_new(&p->sem, 0) != ERR_OK) {
LWIP_ASSERT("Failed to create semaphore", 0);
}
p->p = NULL;
p->lasttime = 0;
sys_thread_new("pcapif_thread", pcapif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
#endif /* linux */

View File

@@ -0,0 +1,481 @@
/* Author: Magnus Ivarsson <magnus.ivarsson@volvo.com> */
/* to get rid of implicit function declarations */
#define _XOPEN_SOURCE 600
#define _GNU_SOURCE
#include "netif/sio.h"
#include "netif/fifo.h"
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/arch.h"
#include "lwip/sio.h"
#include "netif/ppp/ppp_opts.h"
/* Following #undefs are here to keep compiler from issuing warnings
about them being double defined. (They are defined in lwip/inet.h
as well as the Unix #includes below.) */
#undef htonl
#undef ntohl
#undef htons
#undef ntohs
#undef HTONL
#undef NTOHL
#undef HTONS
#undef NTOHS
#include <stdlib.h>
#include <stdio.h>
#if defined(LWIP_UNIX_OPENBSD)
#include <util.h>
#endif
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <sys/signal.h>
#include <sys/types.h>
#ifndef LWIP_HAVE_SLIPIF
#define LWIP_HAVE_SLIPIF 0
#endif
#if (PPP_SUPPORT || LWIP_HAVE_SLIPIF) && defined(LWIP_UNIX_LINUX)
#include <pty.h>
#endif
/*#define BAUDRATE B19200 */
/*#define BAUDRATE B57600 */
#define BAUDRATE B115200
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* for all of you who dont define SIO_DEBUG in debug.h */
#ifndef SIO_DEBUG
#define SIO_DEBUG 0
#endif
/* typedef struct siostruct_t */
/* { */
/* sio_status_t *sio; */
/* } siostruct_t; */
/** array of ((siostruct*)netif->state)->sio structs */
static sio_status_t statusar[4];
#if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
/* --private-functions----------------------------------------------------------------- */
/**
* Signal handler for ttyXX0 to indicate bytes received
* one per interface is needed since we cannot send a instance number / pointer as callback argument (?)
*/
static void signal_handler_IO_0( int status )
{
LWIP_UNUSED_ARG(status);
LWIP_DEBUGF(SIO_DEBUG, ("SigHand: rxSignal channel 0\n"));
fifoPut( &statusar[0].myfifo, statusar[0].fd );
}
/**
* Signal handler for ttyXX1 to indicate bytes received
* one per interface is needed since we cannot send a instance number / pointer as callback argument (?)
*/
static void signal_handler_IO_1( int status )
{
LWIP_UNUSED_ARG(status);
LWIP_DEBUGF(SIO_DEBUG, ("SigHand: rxSignal channel 1\n"));
fifoPut( &statusar[1].myfifo, statusar[1].fd );
}
#endif /* ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */
/**
* Initiation of serial device
* @param device string with the device name and path, eg. "/dev/ttyS0"
* @param devnum device number
* @param siostat status
* @return file handle to serial dev.
*/
static int sio_init( char * device, int devnum, sio_status_t * siostat )
{
struct termios oldtio,newtio;
#if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
struct sigaction saio; /* definition of signal action */
#endif
int fd;
LWIP_UNUSED_ARG(siostat);
LWIP_UNUSED_ARG(devnum);
/* open the device to be non-blocking (read will return immediately) */
fd = open( device, O_RDWR | O_NOCTTY | O_NONBLOCK );
if ( fd < 0 )
{
perror( device );
exit( -1 );
}
#if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
/* install the signal handler before making the device asynchronous */
switch ( devnum )
{
case 0:
LWIP_DEBUGF( SIO_DEBUG, ("sioinit, signal_handler_IO_0\n") );
saio.sa_handler = signal_handler_IO_0;
break;
case 1:
LWIP_DEBUGF( SIO_DEBUG, ("sioinit, signal_handler_IO_1\n") );
saio.sa_handler = signal_handler_IO_1;
break;
default:
LWIP_DEBUGF( SIO_DEBUG,("sioinit, devnum not allowed\n") );
break;
}
saio.sa_flags = 0;
#if defined(LWIP_UNIX_LINUX)
saio.sa_restorer = NULL;
#endif /* LWIP_UNIX_LINUX */
sigaction( SIGIO,&saio,NULL );
/* allow the process to receive SIGIO */
if ( fcntl( fd, F_SETOWN, getpid( ) ) != 0)
{
perror( device );
exit( -1 );
}
/* Make the file descriptor asynchronous (the manual page says only
O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
if ( fcntl( fd, F_SETFL, FASYNC ) != 0)
{
perror( device );
exit( -1 );
}
#else
if ( fcntl( fd, F_SETFL, 0 ) != 0)
{
perror( device );
exit( -1 );
}
#endif /* ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */
tcgetattr( fd,&oldtio ); /* save current port settings */
/* set new port settings */
/* see 'man termios' for further settings */
memset(&newtio, 0, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD | CRTSCTS;
newtio.c_iflag = 0;
newtio.c_oflag = 0;
newtio.c_lflag = 0; /*ECHO; */
newtio.c_cc[VMIN] = 1; /* Read 1 byte at a time, no timer */
newtio.c_cc[VTIME] = 0;
tcsetattr( fd,TCSANOW,&newtio );
tcflush( fd, TCIOFLUSH );
return fd;
}
/**
*
*/
static void sio_speed( int fd, int speed )
{
struct termios oldtio,newtio;
/* int fd; */
LWIP_DEBUGF(SIO_DEBUG, ("sio_speed[%d]: baudcode:%d enter\n", fd, speed));
if ( fd < 0 )
{
LWIP_DEBUGF(SIO_DEBUG, ("sio_speed[%d]: fd ERROR\n", fd));
exit( -1 );
}
tcgetattr( fd,&oldtio ); /* get current port settings */
/* set new port settings
* see 'man termios' for further settings */
memset(&newtio, 0, sizeof(newtio));
newtio.c_cflag = speed | CS8 | CLOCAL | CREAD; /* | CRTSCTS; */
newtio.c_iflag = 0;
newtio.c_oflag = 0;
newtio.c_lflag = 0; /*ECHO; */
newtio.c_cc[VMIN] = 1; /* Read 1 byte at a time, no timer */
newtio.c_cc[VTIME] = 0;
tcsetattr( fd,TCSANOW,&newtio );
tcflush( fd, TCIOFLUSH );
LWIP_DEBUGF(SIO_DEBUG, ("sio_speed[%d]: leave\n", fd));
}
/* --public-functions----------------------------------------------------------------------------- */
void sio_send( u8_t c, sio_status_t * siostat )
{
/* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */
if ( write( siostat->fd, &c, 1 ) <= 0 )
{
LWIP_DEBUGF(SIO_DEBUG, ("sio_send[%d]: write refused\n", siostat->fd));
}
}
void sio_send_string( u8_t *str, sio_status_t * siostat )
{
/* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */
int len = strlen( (const char *)str );
if ( write( siostat->fd, str, len ) <= 0 )
{
LWIP_DEBUGF(SIO_DEBUG, ("sio_send_string[%d]: write refused\n", siostat->fd));
}
LWIP_DEBUGF(SIO_DEBUG, ("sio_send_string[%d]: sent: %s\n", siostat->fd, str));
}
void sio_flush( sio_status_t * siostat )
{
LWIP_UNUSED_ARG(siostat);
/* not implemented in unix as it is not needed */
/*sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */
}
#if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
/*u8_t sio_recv( struct netif * netif )*/
u8_t sio_recv( sio_status_t * siostat )
{
/* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */
return fifoGet( &(siostat->myfifo) );
}
s16_t sio_poll(sio_status_t * siostat)
{
/* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/
return fifoGetNonBlock( &(siostat->myfifo) );
}
void sio_expect_string( u8_t *str, sio_status_t * siostat )
{
/* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/
u8_t c;
int finger=0;
LWIP_DEBUGF(SIO_DEBUG, ("sio_expect_string[%d]: %s\n", siostat->fd, str));
while ( 1 )
{
c=fifoGet( &(siostat->myfifo) );
LWIP_DEBUGF(SIO_DEBUG, ("_%c", c));
if ( c==str[finger] )
{
finger++;
} else if ( finger > 0 )
{
/*it might fit in the beginning? */
if ( str[0] == c )
{
finger = 1;
}
}
if ( 0 == str[finger] )
break; /* done, we have a match */
}
LWIP_DEBUGF(SIO_DEBUG, ("sio_expect_string[%d]: [match]\n", siostat->fd));
}
#endif /* ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */
#if (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
u32_t sio_write(sio_status_t * siostat, u8_t *buf, u32_t size)
{
ssize_t wsz = write( siostat->fd, buf, size );
return wsz < 0 ? 0 : wsz;
}
u32_t sio_read(sio_status_t * siostat, u8_t *buf, u32_t size)
{
ssize_t rsz = read( siostat->fd, buf, size );
return rsz < 0 ? 0 : rsz;
}
void sio_read_abort(sio_status_t * siostat)
{
LWIP_UNUSED_ARG(siostat);
printf("sio_read_abort[%d]: not yet implemented for unix\n", siostat->fd);
}
#endif /* (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */
sio_fd_t sio_open(u8_t devnum)
{
char dev[20];
/* would be nice with dynamic memory alloc */
sio_status_t * siostate = &statusar[ devnum ];
/* siostruct_t * tmp; */
/* tmp = (siostruct_t*)(netif->state); */
/* tmp->sio = siostate; */
/* tmp = (siostruct_t*)(netif->state); */
/* ((sio_status_t*)(tmp->sio))->fd = 0; */
LWIP_DEBUGF(SIO_DEBUG, ("sio_open: for devnum %d\n", devnum));
#if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
fifoInit( &siostate->myfifo );
#endif /* ! PPP_SUPPORT */
snprintf( dev, sizeof(dev), "/dev/ttyS%d", devnum );
if ( (devnum == 1) || (devnum == 0) )
{
if ( ( siostate->fd = sio_init( dev, devnum, siostate ) ) == 0 )
{
LWIP_DEBUGF(SIO_DEBUG, ("sio_open: ERROR opening serial device dev=%s\n", dev));
abort( );
return NULL;
}
LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: dev=%s open.\n", siostate->fd, dev));
}
#if PPP_SUPPORT
else if (devnum == 2) {
pid_t childpid;
char name[256];
childpid = forkpty(&siostate->fd, name, NULL, NULL);
if(childpid < 0) {
perror("forkpty");
exit (1);
}
if(childpid == 0) {
execl("/usr/sbin/pppd", "pppd",
"ms-dns", "198.168.100.7",
"local", "crtscts",
"debug",
#ifdef LWIP_PPP_CHAP_TEST
"auth",
"require-chap",
"remotename", "lwip",
#else
"noauth",
#endif
#if LWIP_IPV6
"+ipv6",
#endif
"192.168.1.1:192.168.1.2",
NULL);
perror("execl pppd");
exit (1);
} else {
LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: spawned pppd pid %d on %s\n",
siostate->fd, childpid, name));
}
}
#endif
#if LWIP_HAVE_SLIPIF
else if (devnum == 3) {
pid_t childpid;
/* create PTY pair */
siostate->fd = posix_openpt(O_RDWR | O_NOCTTY);
if (siostate->fd < 0) {
perror("open pty master");
exit (1);
}
if (grantpt(siostate->fd) != 0) {
perror("grant pty master");
exit (1);
}
if (unlockpt(siostate->fd) != 0) {
perror("unlock pty master");
exit (1);
}
LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: for %s\n",
siostate->fd, ptsname(siostate->fd)));
/* fork for slattach */
childpid = fork();
if(childpid < 0) {
perror("fork");
exit (1);
}
if(childpid == 0) {
/* esteblish SLIP interface on host side connected to PTY slave */
execl("/sbin/slattach", "slattach",
"-d", "-v", "-L", "-p", "slip",
ptsname(siostate->fd),
NULL);
perror("execl slattach");
exit (1);
} else {
int ret;
char buf[1024];
LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: spawned slattach pid %d on %s\n",
siostate->fd, childpid, ptsname(siostate->fd)));
/* wait a moment for slattach startup */
sleep(1);
/* configure SLIP interface on host side as P2P interface */
snprintf(buf, sizeof(buf),
"/sbin/ifconfig sl0 mtu %d %s pointopoint %s up",
SLIP_MAX_SIZE, "192.168.2.1", "192.168.2.2");
LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: system(\"%s\");\n", siostate->fd, buf));
ret = system(buf);
if (ret < 0) {
perror("ifconfig failed");
exit(1);
}
}
}
#endif /* LWIP_HAVE_SLIPIF */
else
{
LWIP_DEBUGF(SIO_DEBUG, ("sio_open: device %s (%d) is not supported\n", dev, devnum));
return NULL;
}
return siostate;
}
/**
*
*/
void sio_change_baud( sioBaudrates baud, sio_status_t * siostat )
{
/* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/
LWIP_DEBUGF(SIO_DEBUG, ("sio_change_baud[%d]\n", siostat->fd));
switch ( baud )
{
case SIO_BAUD_9600:
sio_speed( siostat->fd, B9600 );
break;
case SIO_BAUD_19200:
sio_speed( siostat->fd, B19200 );
break;
case SIO_BAUD_38400:
sio_speed( siostat->fd, B38400 );
break;
case SIO_BAUD_57600:
sio_speed( siostat->fd, B57600 );
break;
case SIO_BAUD_115200:
sio_speed( siostat->fd, B115200 );
break;
default:
LWIP_DEBUGF(SIO_DEBUG, ("sio_change_baud[%d]: Unknown baudrate, code:%d\n",
siostat->fd, baud));
break;
}
}

View File

@@ -0,0 +1,424 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include "lwip/opt.h"
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/ip.h"
#include "lwip/mem.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/timeouts.h"
#include "netif/etharp.h"
#include "lwip/ethip6.h"
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
#include "netif/tcpdump.h"
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
#include "netif/tapif.h"
#define IFCONFIG_BIN "/sbin/ifconfig "
#if defined(LWIP_UNIX_LINUX)
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
/*
* Creating a tap interface requires special privileges. If the interfaces
* is created in advance with `tunctl -u <user>` it can be opened as a regular
* user. The network must already be configured. If DEVTAP_IF is defined it
* will be opened instead of creating a new tap device.
*
* You can also use PRECONFIGURED_TAPIF environment variable to do so.
*/
#ifndef DEVTAP_DEFAULT_IF
#define DEVTAP_DEFAULT_IF "tap0"
#endif
#ifndef DEVTAP
#define DEVTAP "/dev/net/tun"
#endif
#define NETMASK_ARGS "netmask %d.%d.%d.%d"
#define IFCONFIG_ARGS "tap0 inet %d.%d.%d.%d " NETMASK_ARGS
#elif defined(LWIP_UNIX_OPENBSD)
#define DEVTAP "/dev/tun0"
#define NETMASK_ARGS "netmask %d.%d.%d.%d"
#define IFCONFIG_ARGS "tun0 inet %d.%d.%d.%d " NETMASK_ARGS " link0"
#else /* others */
#define DEVTAP "/dev/tap0"
#define NETMASK_ARGS "netmask %d.%d.%d.%d"
#define IFCONFIG_ARGS "tap0 inet %d.%d.%d.%d " NETMASK_ARGS
#endif
/* Define those to better describe your network interface. */
#define IFNAME0 't'
#define IFNAME1 'p'
#ifndef TAPIF_DEBUG
#define TAPIF_DEBUG LWIP_DBG_OFF
#endif
struct tapif {
/* Add whatever per-interface state that is needed here. */
int fd;
};
/* Forward declarations. */
static void tapif_input(struct netif *netif);
#if !NO_SYS
static void tapif_thread(void *arg);
#endif /* !NO_SYS */
/*-----------------------------------------------------------------------------------*/
static void
low_level_init(struct netif *netif)
{
struct tapif *tapif;
#if LWIP_IPV4
int ret;
char buf[1024];
#endif /* LWIP_IPV4 */
char *preconfigured_tapif = getenv("PRECONFIGURED_TAPIF");
tapif = (struct tapif *)netif->state;
/* Obtain MAC address from network interface. */
/* (We just fake an address...) */
netif->hwaddr[0] = 0x02;
netif->hwaddr[1] = 0x12;
netif->hwaddr[2] = 0x34;
netif->hwaddr[3] = 0x56;
netif->hwaddr[4] = 0x78;
netif->hwaddr[5] = 0xab;
netif->hwaddr_len = 6;
/* device capabilities */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP;
tapif->fd = open(DEVTAP, O_RDWR);
LWIP_DEBUGF(TAPIF_DEBUG, ("tapif_init: fd %d\n", tapif->fd));
if (tapif->fd == -1) {
#ifdef LWIP_UNIX_LINUX
perror("tapif_init: try running \"modprobe tun\" or rebuilding your kernel with CONFIG_TUN; cannot open "DEVTAP);
#else /* LWIP_UNIX_LINUX */
perror("tapif_init: cannot open "DEVTAP);
#endif /* LWIP_UNIX_LINUX */
exit(1);
}
#ifdef LWIP_UNIX_LINUX
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
if (preconfigured_tapif) {
strncpy(ifr.ifr_name, preconfigured_tapif, sizeof(ifr.ifr_name));
} else {
strncpy(ifr.ifr_name, DEVTAP_DEFAULT_IF, sizeof(ifr.ifr_name));
}
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0; /* ensure \0 termination */
ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
if (ioctl(tapif->fd, TUNSETIFF, (void *) &ifr) < 0) {
perror("tapif_init: "DEVTAP" ioctl TUNSETIFF");
exit(1);
}
}
#endif /* LWIP_UNIX_LINUX */
netif_set_link_up(netif);
if (preconfigured_tapif == NULL) {
#if LWIP_IPV4
snprintf(buf, 1024, IFCONFIG_BIN IFCONFIG_ARGS,
ip4_addr1(netif_ip4_gw(netif)),
ip4_addr2(netif_ip4_gw(netif)),
ip4_addr3(netif_ip4_gw(netif)),
ip4_addr4(netif_ip4_gw(netif))
#ifdef NETMASK_ARGS
,
ip4_addr1(netif_ip4_netmask(netif)),
ip4_addr2(netif_ip4_netmask(netif)),
ip4_addr3(netif_ip4_netmask(netif)),
ip4_addr4(netif_ip4_netmask(netif))
#endif /* NETMASK_ARGS */
);
LWIP_DEBUGF(TAPIF_DEBUG, ("tapif_init: system(\"%s\");\n", buf));
ret = system(buf);
if (ret < 0) {
perror("ifconfig failed");
exit(1);
}
if (ret != 0) {
printf("ifconfig returned %d\n", ret);
}
#else /* LWIP_IPV4 */
perror("todo: support IPv6 support for non-preconfigured tapif");
exit(1);
#endif /* LWIP_IPV4 */
}
#if !NO_SYS
sys_thread_new("tapif_thread", tapif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
#endif /* !NO_SYS */
}
/*-----------------------------------------------------------------------------------*/
/*
* low_level_output():
*
* Should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
*/
/*-----------------------------------------------------------------------------------*/
static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
struct tapif *tapif = (struct tapif *)netif->state;
char buf[1514];
ssize_t written;
#if 0
if (((double)rand()/(double)RAND_MAX) < 0.2) {
printf("drop output\n");
return ERR_OK;
}
#endif
/* initiate transfer(); */
pbuf_copy_partial(p, buf, p->tot_len, 0);
/* signal that packet should be sent(); */
written = write(tapif->fd, buf, p->tot_len);
if (written < 0) {
MIB2_STATS_NETIF_INC(netif, ifoutdiscards);
perror("tapif: write");
}
else {
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, (u32_t)written);
}
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/*
* low_level_input():
*
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
*/
/*-----------------------------------------------------------------------------------*/
static struct pbuf *
low_level_input(struct netif *netif)
{
struct pbuf *p;
u16_t len;
ssize_t readlen;
char buf[1514];
struct tapif *tapif = (struct tapif *)netif->state;
/* Obtain the size of the packet and put it into the "len"
variable. */
readlen = read(tapif->fd, buf, sizeof(buf));
if (readlen < 0) {
perror("read returned -1");
exit(1);
}
len = (u16_t)readlen;
MIB2_STATS_NETIF_ADD(netif, ifinoctets, len);
#if 0
if (((double)rand()/(double)RAND_MAX) < 0.2) {
printf("drop\n");
return NULL;
}
#endif
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL) {
pbuf_take(p, buf, len);
/* acknowledge that packet has been read(); */
} else {
/* drop packet(); */
MIB2_STATS_NETIF_INC(netif, ifindiscards);
LWIP_DEBUGF(NETIF_DEBUG, ("tapif_input: could not allocate pbuf\n"));
}
return p;
}
/*-----------------------------------------------------------------------------------*/
/*
* tapif_input():
*
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface.
*
*/
/*-----------------------------------------------------------------------------------*/
static void
tapif_input(struct netif *netif)
{
struct pbuf *p = low_level_input(netif);
if (p == NULL) {
#if LINK_STATS
LINK_STATS_INC(link.recv);
#endif /* LINK_STATS */
LWIP_DEBUGF(TAPIF_DEBUG, ("tapif_input: low_level_input returned NULL\n"));
return;
}
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("tapif_input: netif input error\n"));
pbuf_free(p);
}
}
/*-----------------------------------------------------------------------------------*/
/*
* tapif_init():
*
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
*/
/*-----------------------------------------------------------------------------------*/
err_t
tapif_init(struct netif *netif)
{
struct tapif *tapif = (struct tapif *)mem_malloc(sizeof(struct tapif));
if (tapif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("tapif_init: out of memory for tapif\n"));
return ERR_MEM;
}
netif->state = tapif;
MIB2_INIT_NETIF(netif, snmp_ifType_other, 100000000);
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
#if LWIP_IPV4
netif->output = etharp_output;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = low_level_output;
netif->mtu = 1500;
low_level_init(netif);
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
#if NO_SYS
int
tapif_select(struct netif *netif)
{
fd_set fdset;
int ret;
struct timeval tv;
struct tapif *tapif;
u32_t msecs = sys_timeouts_sleeptime();
tapif = (struct tapif *)netif->state;
tv.tv_sec = msecs / 1000;
tv.tv_usec = (msecs % 1000) * 1000;
FD_ZERO(&fdset);
FD_SET(tapif->fd, &fdset);
ret = select(tapif->fd + 1, &fdset, NULL, NULL, &tv);
if (ret > 0) {
tapif_input(netif);
}
return ret;
}
#else /* NO_SYS */
static void
tapif_thread(void *arg)
{
struct netif *netif;
struct tapif *tapif;
fd_set fdset;
int ret;
netif = (struct netif *)arg;
tapif = (struct tapif *)netif->state;
while(1) {
FD_ZERO(&fdset);
FD_SET(tapif->fd, &fdset);
/* Wait for a packet to arrive. */
ret = select(tapif->fd + 1, &fdset, NULL, NULL, NULL);
if(ret == 1) {
/* Handle incoming packet. */
tapif_input(netif);
} else if(ret == -1) {
perror("tapif_thread: select");
}
}
}
#endif /* NO_SYS */

View File

@@ -0,0 +1,216 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include <stdio.h>
#include "lwip/opt.h"
#if (LWIP_IPV4 || LWIP_IPV6) && LWIP_TCP /* @todo: fix IPv6 */
#include <string.h> /* memcpy */
#include "netif/tcpdump.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/ip4.h"
#include "lwip/ip6.h"
#include "lwip/ip_addr.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/udp.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#ifndef TCPDUMP_DEBUG
#define TCPDUMP_DEBUG LWIP_DBG_OFF
#endif
static FILE *file = NULL;
/*-----------------------------------------------------------------------------------*/
void
tcpdump_init(void)
{
#define TCPDUMP_FNAME "/tmp/tcpdump"
file = fopen(TCPDUMP_FNAME, "w");
if (file == NULL) {
perror("tcpdump_init: cannot open \""TCPDUMP_FNAME"\" for writing");
}
LWIP_DEBUGF(TCPDUMP_DEBUG, ("tcpdump: file %s\n", TCPDUMP_FNAME));
}
/*-----------------------------------------------------------------------------------*/
void
tcpdump(struct pbuf *p, struct netif* netif)
{
#if LWIP_IPV4
ip_addr_t src, dst;
struct ip_hdr *iphdr;
#if LWIP_UDP
struct udp_hdr *udphdr;
#endif
#if LWIP_TCP
struct tcp_hdr *tcphdr;
char flags[5];
int i;
int len;
int offset;
#endif
LWIP_UNUSED_ARG(netif); /* in case IPv6 is disabled */
if (file == NULL) {
return;
}
iphdr = (struct ip_hdr *)p->payload;
#if LWIP_IPV6
if(IPH_V(iphdr) == 6) {
struct ip6_hdr *ip6hdr = (struct ip6_hdr*)iphdr;
/* create aligned copies if IPv6 src/dest addr */
ip6_addr_copy_from_packed(*ip_2_ip6(&src), ip6hdr->src);
ip6_addr_assign_zone(ip_2_ip6(&src), IP6_UNKNOWN, netif);
IP_SET_TYPE_VAL(src, IPADDR_TYPE_V6);
ip6_addr_copy_from_packed(*ip_2_ip6(&dst), ip6hdr->dest);
ip6_addr_assign_zone(ip_2_ip6(&dst), IP6_UNKNOWN, netif);
IP_SET_TYPE_VAL(dst, IPADDR_TYPE_V6);
fprintf(file, "%s > %s: (IPv6, unsupported) ",
ip_ntoa(&src),
ip_ntoa(&dst));
return; /* not supported */
}
#endif
if(IPH_V(iphdr) == 4) {
ip_addr_copy_from_ip4(src, iphdr->src);
ip_addr_copy_from_ip4(dst, iphdr->dest);
}
switch (IPH_PROTO(iphdr)) {
#if LWIP_TCP
case IP_PROTO_TCP:
tcphdr = (struct tcp_hdr *)((char *)iphdr + IPH_HL(iphdr));
pbuf_header(p, -IP_HLEN);
if (ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, &src, &dst) != 0) {
LWIP_DEBUGF(TCPDUMP_DEBUG, ("tcpdump: IP checksum failed!\n"));
/*
fprintf(file, "chksum 0x%lx ", tcphdr->chksum);
tcphdr->chksum = 0;
fprintf(file, "should be 0x%lx ", inet_chksum_pseudo(p, (ip_addr_t *)&(iphdr->src),
(ip_addr_t *)&(iphdr->dest), IP_PROTO_TCP, p->tot_len));*/
fprintf(file, "!chksum ");
}
i = 0;
if (TCPH_FLAGS(tcphdr) & TCP_SYN) {
flags[i++] = 'S';
}
if (TCPH_FLAGS(tcphdr) & TCP_PSH) {
flags[i++] = 'P';
}
if (TCPH_FLAGS(tcphdr) & TCP_FIN) {
flags[i++] = 'F';
}
if (TCPH_FLAGS(tcphdr) & TCP_RST) {
flags[i++] = 'R';
}
if (i == 0) {
flags[i++] = '.';
}
flags[i++] = 0;
fprintf(file, "%s.%u > %s.%u: ",
ip_ntoa(&src),
lwip_ntohs(tcphdr->src),
ip_ntoa(&dst),
lwip_ntohs(tcphdr->dest));
offset = TCPH_HDRLEN(tcphdr);
len = lwip_ntohs(IPH_LEN(iphdr)) - offset * 4 - IP_HLEN;
if (len != 0 || flags[0] != '.') {
fprintf(file, "%s %u:%u(%u) ", flags, lwip_ntohl(tcphdr->seqno),
lwip_ntohl(tcphdr->seqno) + (u32_t)len, len);
}
if (TCPH_FLAGS(tcphdr) & TCP_ACK) {
fprintf(file, "ack %u ", lwip_ntohl(tcphdr->ackno));
}
fprintf(file, "wnd %u\n", lwip_ntohs(tcphdr->wnd));
fflush(file);
pbuf_header(p, IP_HLEN);
break;
#endif /* LWIP_TCP */
#if LWIP_UDP
case IP_PROTO_UDP:
udphdr = (struct udp_hdr *)((char *)iphdr + IPH_HL(iphdr));
pbuf_header(p, -IP_HLEN);
if (ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, &src, &dst) != 0) {
LWIP_DEBUGF(TCPDUMP_DEBUG, ("tcpdump: IP checksum failed!\n"));
/*
fprintf(file, "chksum 0x%lx ", tcphdr->chksum);
tcphdr->chksum = 0;
fprintf(file, "should be 0x%lx ", ip_chksum_pseudo(p, &src, &dst, IP_PROTO_TCP, p->tot_len));*/
fprintf(file, "!chksum ");
}
fprintf(file, "%s.%u > %s.%u: ",
ip_ntoa(&src),
lwip_ntohs(udphdr->src),
ip_ntoa(&dst),
lwip_ntohs(udphdr->dest));
fprintf(file, "U ");
len = (int)(lwip_ntohs(IPH_LEN(iphdr)) - sizeof(struct udp_hdr) - IP_HLEN);
fprintf(file, " %d\n", len);
fflush(file);
pbuf_header(p, IP_HLEN);
break;
#endif /* LWIP_UDP */
default:
LWIP_DEBUGF(TCPDUMP_DEBUG, ("unhandled IP protocol: %d\n", (int)IPH_PROTO(iphdr)));
break;
}
#else
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(netif);
#endif
}
#endif /* LWIP_IPV4 && LWIP_TCP */
/*-----------------------------------------------------------------------------------*/

View File

@@ -0,0 +1,302 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "netif/tunif.h"
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include "lwip/debug.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/ip.h"
#include "lwip/mem.h"
#include "lwip/netif.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#if LWIP_IPV4 /* @todo: IPv6 */
#if !NO_SYS
#define IFNAME0 't'
#define IFNAME1 'n'
#ifndef TUNIF_DEBUG
#define TUNIF_DEBUG LWIP_DBG_OFF
#endif
#define IFCONFIG_CALL "/sbin/ifconfig tun0 inet %d.%d.%d.%d %d.%d.%d.%d"
struct tunif {
/* Add whatever per-interface state that is needed here. */
int fd;
};
/* Forward declarations. */
static void tunif_input(struct netif *netif);
static err_t tunif_output(struct netif *netif, struct pbuf *p,
const ip4_addr_t *ipaddr);
static void tunif_thread(void *data);
/*-----------------------------------------------------------------------------------*/
static void
low_level_init(struct netif *netif)
{
struct tunif *tunif;
char buf[sizeof(IFCONFIG_CALL) + 50];
tunif = (struct tunif *)netif->state;
/* Obtain MAC address from network interface. */
/* Do whatever else is needed to initialize interface. */
tunif->fd = open("/dev/tun0", O_RDWR);
LWIP_DEBUGF(TUNIF_DEBUG, ("tunif_init: fd %d\n", tunif->fd));
if (tunif->fd == -1) {
perror("tunif_init");
exit(1);
}
sprintf(buf, IFCONFIG_CALL,
ip4_addr1(netif_ip4_gw(netif)),
ip4_addr2(netif_ip4_gw(netif)),
ip4_addr3(netif_ip4_gw(netif)),
ip4_addr4(netif_ip4_gw(netif)),
ip4_addr1(netif_ip4_addr(netif)),
ip4_addr2(netif_ip4_addr(netif)),
ip4_addr3(netif_ip4_addr(netif)),
ip4_addr4(netif_ip4_addr(netif)));
LWIP_DEBUGF(TUNIF_DEBUG, ("tunif_init: system(\"%s\");\n", buf));
if (system(buf) == 0) {
sys_thread_new("tunif_thread", tunif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
}
}
/*-----------------------------------------------------------------------------------*/
/*
* low_level_output():
*
* Should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
*/
/*-----------------------------------------------------------------------------------*/
static err_t
low_level_output(struct tunif *tunif, struct pbuf *p)
{
char buf[1500];
int rnd_val;
/* initiate transfer(); */
rnd_val = rand();
if (((double)rnd_val/(double)RAND_MAX) < 0.4) {
printf("drop\n");
return ERR_OK;
}
pbuf_copy_partial(p, buf, p->tot_len, 0);
/* signal that packet should be sent(); */
if (write(tunif->fd, buf, p->tot_len) == -1) {
perror("tunif: write");
}
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/*
* low_level_input():
*
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
*/
/*-----------------------------------------------------------------------------------*/
static struct pbuf *
low_level_input(struct tunif *tunif)
{
struct pbuf *p;
ssize_t len;
char buf[1500];
/* Obtain the size of the packet and put it into the "len"
variable. */
len = read(tunif->fd, buf, sizeof(buf));
if((len <= 0) || (len > 0xffff)) {
return NULL;
}
/* if (((double)rand()/(double)RAND_MAX) < 0.1) {
printf("drop\n");
return NULL;
}*/
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_LINK, (u16_t)len, PBUF_POOL);
if (p != NULL) {
pbuf_take(p, buf, (u16_t)len);
/* acknowledge that packet has been read(); */
} else {
/* drop packet(); */
}
return p;
}
/*-----------------------------------------------------------------------------------*/
static void
tunif_thread(void *arg)
{
struct netif *netif;
struct tunif *tunif;
fd_set fdset;
int ret;
netif = (struct netif *)arg;
tunif = (struct tunif *)netif->state;
while (1) {
FD_ZERO(&fdset);
FD_SET(tunif->fd, &fdset);
/* Wait for a packet to arrive. */
ret = select(tunif->fd + 1, &fdset, NULL, NULL, NULL);
if (ret == 1) {
/* Handle incoming packet. */
tunif_input(netif);
} else if (ret == -1) {
perror("tunif_thread: select");
}
}
}
/*-----------------------------------------------------------------------------------*/
/*
* tunif_output():
*
* This function is called by the TCP/IP stack when an IP packet
* should be sent. It calls the function called low_level_output() to
* do the actuall transmission of the packet.
*
*/
/*-----------------------------------------------------------------------------------*/
static err_t
tunif_output(struct netif *netif, struct pbuf *p,
const ip4_addr_t *ipaddr)
{
struct tunif *tunif;
LWIP_UNUSED_ARG(ipaddr);
tunif = (struct tunif *)netif->state;
return low_level_output(tunif, p);
}
/*-----------------------------------------------------------------------------------*/
/*
* tunif_input():
*
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface.
*
*/
/*-----------------------------------------------------------------------------------*/
static void
tunif_input(struct netif *netif)
{
struct tunif *tunif;
struct pbuf *p;
tunif = (struct tunif *)netif->state;
p = low_level_input(tunif);
if (p == NULL) {
LWIP_DEBUGF(TUNIF_DEBUG, ("tunif_input: low_level_input returned NULL\n"));
return;
}
#if 0
/* CS: ip_lookup() was removed */
if (ip_lookup(p->payload, netif)) {
#endif
netif->input(p, netif);
#if 0
}
#endif
}
/*-----------------------------------------------------------------------------------*/
/*
* tunif_init():
*
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
*/
/*-----------------------------------------------------------------------------------*/
err_t
tunif_init(struct netif *netif)
{
struct tunif *tunif;
tunif = (struct tunif *)mem_malloc(sizeof(struct tunif));
if (!tunif) {
return ERR_MEM;
}
netif->state = tunif;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = tunif_output;
low_level_init(netif);
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
#endif /* !NO_SYS */
#endif /* LWIP_IPV4 */

View File

@@ -0,0 +1,500 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/debug.h"
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
/*#include <netinet/in.h> */
/*#include <arpa/inet.h> */
#include "lwip/stats.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "netif/list.h"
#include "netif/unixif.h"
#include "lwip/sys.h"
#include "lwip/timeouts.h"
#if LWIP_IPV4 /* @todo: IPv6 */
#if !NO_SYS
#include "netif/tcpdump.h"
#define UNIXIF_BPS 512000
#define UNIXIF_QUEUELEN 6
/*#define UNIXIF_DROP_FIRST */
#ifndef UNIXIF_DEBUG
#define UNIXIF_DEBUG LWIP_DBG_OFF
#endif
struct unixif_buf {
struct pbuf *p;
unsigned short len, tot_len;
void *payload;
};
struct unixif {
int fd;
sys_sem_t sem;
struct list *q;
};
static void unixif_thread(void *arg);
static void unixif_thread2(void *arg);
/*-----------------------------------------------------------------------------------*/
static int
unix_socket_client(const char *name)
{
int fd;
#if !defined(LWIP_UNIX_LINUX) && !defined(LWIP_UNIX_CYGWIN) && !defined(__CYGWIN__)
int len;
#endif
struct sockaddr_un unix_addr;
/* create a Unix domain stream socket */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("unixif: unix_socket_client: socket");
return(-1);
}
/* fill socket address structure w/our address */
memset(&unix_addr, 0, sizeof(unix_addr));
unix_addr.sun_family = AF_UNIX;
snprintf(unix_addr.sun_path, sizeof(unix_addr.sun_path), "%s%05d", "/var/tmp/", getpid());
#if !defined(LWIP_UNIX_LINUX) && !defined(LWIP_UNIX_CYGWIN) && !defined(__CYGWIN__)
len = sizeof(unix_addr.sun_len) + sizeof(unix_addr.sun_family) +
strlen(unix_addr.sun_path) + 1;
unix_addr.sun_len = len;
#endif /* LWIP_UNIX_LINUX */
unlink(unix_addr.sun_path); /* in case it already exists */
if (bind(fd, (struct sockaddr *) &unix_addr,
sizeof(struct sockaddr_un)) < 0) {
perror("unixif: unix_socket_client: socket");
return(-1);
}
if (chmod(unix_addr.sun_path, S_IRWXU | S_IRWXO) < 0) {
perror("unixif: unix_socket_client: socket");
return(-1);
}
/* fill socket address structure w/server's addr */
memset(&unix_addr, 0, sizeof(unix_addr));
unix_addr.sun_family = AF_UNIX;
strncpy(unix_addr.sun_path, name, sizeof(unix_addr.sun_path));
unix_addr.sun_path[sizeof(unix_addr.sun_path)-1] = 0; /* ensure \0 termination */
#if !defined(LWIP_UNIX_LINUX) && !defined(LWIP_UNIX_CYGWIN) && !defined(__CYGWIN__)
len = sizeof(unix_addr.sun_len) + sizeof(unix_addr.sun_family) +
strlen(unix_addr.sun_path) + 1;
unix_addr.sun_len = len;
#endif /* LWIP_UNIX_LINUX */
if (connect(fd, (struct sockaddr *) &unix_addr,
sizeof(struct sockaddr_un)) < 0) {
perror("unixif: unix_socket_client: socket");
return(-1);
}
return(fd);
}
/*-----------------------------------------------------------------------------------*/
static int
unix_socket_server(const char *name)
{
int fd;
#if !defined(LWIP_UNIX_LINUX) && !defined(LWIP_UNIX_CYGWIN) && !defined(__CYGWIN__)
int len;
#endif
struct sockaddr_un unix_addr;
/* create a Unix domain stream socket */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("unixif: unix_socket_server: socket");
return(-1);
}
unlink(name); /* in case it already exists */
/* fill in socket address structure */
memset(&unix_addr, 0, sizeof(unix_addr));
unix_addr.sun_family = AF_UNIX;
strncpy(unix_addr.sun_path, name, sizeof(unix_addr.sun_path));
unix_addr.sun_path[sizeof(unix_addr.sun_path)-1] = 0; /* ensure \0 termination */
#if !defined(LWIP_UNIX_LINUX) && !defined(LWIP_UNIX_CYGWIN) && !defined(__CYGWIN__)
len = sizeof(unix_addr.sun_len) + sizeof(unix_addr.sun_family) +
strlen(unix_addr.sun_path) + 1;
unix_addr.sun_len = len;
#endif /* LWIP_UNIX_LINUX */
/* bind the name to the descriptor */
if (bind(fd, (struct sockaddr *) &unix_addr,
sizeof(struct sockaddr_un)) < 0) {
perror("unixif: unix_socket_server: bind");
return(-1);
}
if (chmod(unix_addr.sun_path, S_IRWXU | S_IRWXO) < 0) {
perror("unixif: unix_socket_server: chmod");
return(-1);
}
if (listen(fd, 5) < 0) { /* tell kernel we're a server */
perror("unixif: unix_socket_server: listen");
return(-1);
}
return(fd);
}
/*-----------------------------------------------------------------------------------*/
static void
unixif_input_handler(void *data)
{
struct netif *netif;
struct unixif *unixif;
char buf[1532];
int plen;
ssize_t len;
u16_t len16;
struct pbuf *p;
netif = (struct netif *)data;
unixif = (struct unixif *)netif->state;
len = read(unixif->fd, &plen, sizeof(int));
if (len < 0) {
perror("unixif_irq_handler: read");
abort();
}
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: len == %d plen == %d bytes\n", (int)len, plen));
if (len == sizeof(int)) {
if (plen < 20 || plen > 1500) {
LWIP_DEBUGF(UNIXIF_DEBUG, ("plen %d!\n", plen));
return;
}
len = read(unixif->fd, buf, (size_t)plen);
if (len < 0) {
perror("unixif_irq_handler: read");
abort();
}
if (len != plen) {
perror("unixif_irq_handler: read len != plen");
abort();
}
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: read %d bytes\n", (int)len));
len16 = (u16_t)len;
p = pbuf_alloc(PBUF_LINK, len16, PBUF_POOL);
if (p != NULL) {
pbuf_take(p, buf, len16);
LINK_STATS_INC(link.recv);
#if LWIP_IPV4 && LWIP_TCP
tcpdump(p, netif);
#endif
netif->input(p, netif);
} else {
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: could not allocate pbuf\n"));
}
}
}
/*-----------------------------------------------------------------------------------*/
static void
unixif_thread(void *arg)
{
struct netif *netif;
struct unixif *unixif;
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_thread: started.\n"));
netif = (struct netif *)arg;
unixif = (struct unixif *)netif->state;
while (1) {
sys_sem_wait(&unixif->sem);
unixif_input_handler(netif);
}
}
/*-----------------------------------------------------------------------------------*/
static void
unixif_thread2(void *arg)
{
struct netif *netif;
struct unixif *unixif;
fd_set fdset;
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_thread2: started.\n"));
netif = (struct netif *)arg;
unixif = (struct unixif *)netif->state;
while (1) {
FD_ZERO(&fdset);
FD_SET(unixif->fd, &fdset);
if (select(unixif->fd + 1, &fdset, NULL, NULL, NULL) > 0) {
sys_sem_signal(&unixif->sem);
}
}
}
/*-----------------------------------------------------------------------------------*/
static void unixif_output_timeout(void *arg);
static err_t
unixif_output(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
{
struct unixif *unixif;
struct unixif_buf *buf;
LWIP_UNUSED_ARG(ipaddr);
unixif = (struct unixif *)netif->state;
buf = (struct unixif_buf *)malloc(sizeof(struct unixif_buf));
buf->p = p;
buf->len = p->len;
buf->tot_len = p->tot_len;
buf->payload = p->payload;
if (list_elems(unixif->q) == 0) {
pbuf_ref(p);
list_push(unixif->q, buf);
sys_timeout((u32_t)p->tot_len * 8000 / UNIXIF_BPS, unixif_output_timeout,
netif);
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_output: first on list\n"));
} else {
pbuf_ref(p);
if (list_push(unixif->q, buf) == 0) {
#ifdef UNIXIF_DROP_FIRST
struct unixif_buf *buf2;
buf2 = list_pop(unixif->q);
pbuf_free(buf2->p);
free(buf2);
list_push(unixif->q, buf);
#else
free(buf);
pbuf_free(p);
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_output: drop\n"));
#endif /* UNIXIF_DROP_FIRST */
LINK_STATS_INC(link.drop);
} else {
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_output: on list\n"));
}
}
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
static void
unixif_output_timeout(void *arg)
{
struct pbuf *p, *q;
int i, j, len;
unsigned short plen, ptot_len;
struct unixif_buf *buf;
void *payload;
struct netif *netif;
struct unixif *unixif;
char *data;
netif = (struct netif *)arg;
unixif = (struct unixif *)netif->state;
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_output_timeout\n"));
/* buf = unixif->q[0];
unixif->q[0] = unixif->q[1];
unixif->q[1] = NULL;*/
buf = (struct unixif_buf *)list_pop(unixif->q);
p = buf->p;
plen = p->len;
ptot_len = p->tot_len;
payload = p->payload;
p->len = buf->len;
p->tot_len = buf->tot_len;
p->payload = buf->payload;
if (p->tot_len == 0) {
LWIP_DEBUGF(UNIXIF_DEBUG, ("p->len!\n"));
abort();
}
data = (char *)malloc(p->tot_len);
i = 0;
for(q = p; q != NULL; q = q->next) {
for(j = 0; j < q->len; j++) {
data[i] = ((char *)q->payload)[j];
i++;
}
}
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_output: sending %d (%d) bytes\n",
p->len, p->tot_len));
len = p->tot_len;
if (write(unixif->fd, &len, sizeof(int)) == -1) {
perror("unixif_output: write");
abort();
}
if (write(unixif->fd, data, p->tot_len) == -1) {
perror("unixif_output: write");
abort();
}
#if LWIP_IPV4 && LWIP_TCP
tcpdump(p, netif);
#endif
LINK_STATS_INC(link.xmit);
free(data);
free(buf);
p->len = plen;
p->tot_len = ptot_len;
p->payload = payload;
pbuf_free(p);
/* if (unixif->q[0] != NULL) {
sys_timeout(unixif->q[0]->tot_len * 8000 / UNIXIF_BPS,
unixif_output_timeout, netif);
}*/
if (list_elems(unixif->q) > 0) {
sys_timeout(((struct unixif_buf *)list_first(unixif->q))->tot_len *
8000U / UNIXIF_BPS,
unixif_output_timeout, netif);
}
}
/*-----------------------------------------------------------------------------------*/
err_t
unixif_init_server(struct netif *netif)
{
int fd, fd2;
struct sockaddr_un addr;
socklen_t len;
struct unixif *unixif;
fd = unix_socket_server("/tmp/unixif");
if (fd == -1) {
perror("unixif_server");
abort();
}
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_server: fd %d\n", fd));
unixif = (struct unixif *)malloc(sizeof(struct unixif));
if (!unixif) {
return ERR_MEM;
}
netif->state = unixif;
netif->name[0] = 'u';
netif->name[1] = 'n';
netif->output = unixif_output;
unixif->q = list_new(UNIXIF_QUEUELEN);
printf("Now run ./simnode.\n");
len = sizeof(addr);
fd2 = accept(fd, (struct sockaddr *)&addr, &len);
if (fd2 == -1) {
perror("unixif_accept");
abort();
}
LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_accept: %d\n", fd2));
unixif->fd = fd2;
if(sys_sem_new(&unixif->sem, 0) != ERR_OK) {
LWIP_ASSERT("Failed to create semaphore", 0);
}
sys_thread_new("unixif_thread", unixif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
sys_thread_new("unixif_thread2", unixif_thread2, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
err_t
unixif_init_client(struct netif *netif)
{
struct unixif *unixif;
unixif = (struct unixif *)malloc(sizeof(struct unixif));
if (!unixif) {
return ERR_MEM;
}
netif->state = unixif;
netif->name[0] = 'u';
netif->name[1] = 'n';
netif->output = unixif_output;
unixif->fd = unix_socket_client("/tmp/unixif");
if (unixif->fd == -1) {
perror("unixif_init");
abort();
}
unixif->q = list_new(UNIXIF_QUEUELEN);
if(sys_sem_new(&unixif->sem, 0) != ERR_OK) {
LWIP_ASSERT("Failed to create semaphore", 0);
}
sys_thread_new("unixif_thread", unixif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
sys_thread_new("unixif_thread2", unixif_thread2, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
#endif /* !NO_SYS */
#endif /* LWIP_IPV4 */

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "arch/perf.h"
#include <stdio.h>
static FILE *f;
void
perf_print(unsigned long c1l, unsigned long c1h,
unsigned long c2l, unsigned long c2h,
char *key)
{
unsigned long sub_ms, sub_ls;
sub_ms = c2h - c1h;
sub_ls = c2l - c1l;
if (c2l < c1l) sub_ms--;
fprintf(f, "%s: %.8lu%.8lu\n", key, sub_ms, sub_ls);
fflush(NULL);
}
void
perf_print_times(struct tms *start, struct tms *end, char *key)
{
fprintf(f, "%s: %lu\n", key, end->tms_stime - start->tms_stime);
fflush(NULL);
}
void
perf_init(char *fname)
{
f = fopen(fname, "w");
}

View File

@@ -0,0 +1,649 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/*
* Wed Apr 17 16:05:29 EDT 2002 (James Roth)
*
* - Fixed an unlikely sys_thread_new() race condition.
*
* - Made current_thread() work with threads which where
* not created with sys_thread_new(). This includes
* the main thread and threads made with pthread_create().
*
* - Catch overflows where more than SYS_MBOX_SIZE messages
* are waiting to be read. The sys_mbox_post() routine
* will block until there is more room instead of just
* leaking messages.
*/
#include "lwip/debug.h"
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include "lwip/def.h"
#ifdef LWIP_UNIX_MACH
#include <mach/mach.h>
#include <mach/mach_time.h>
#endif
#include "lwip/sys.h"
#include "lwip/opt.h"
#include "lwip/stats.h"
static void
get_monotonic_time(struct timespec *ts)
{
#ifdef LWIP_UNIX_MACH
/* darwin impl (no CLOCK_MONOTONIC) */
uint64_t t = mach_absolute_time();
mach_timebase_info_data_t timebase_info = {0, 0};
mach_timebase_info(&timebase_info);
uint64_t nano = (t * timebase_info.numer) / (timebase_info.denom);
uint64_t sec = nano/1000000000L;
nano -= sec * 1000000000L;
ts->tv_sec = sec;
ts->tv_nsec = nano;
#else
clock_gettime(CLOCK_MONOTONIC, ts);
#endif
}
#if !NO_SYS
static struct sys_thread *threads = NULL;
static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER;
struct sys_mbox_msg {
struct sys_mbox_msg *next;
void *msg;
};
#define SYS_MBOX_SIZE 128
struct sys_mbox {
int first, last;
void *msgs[SYS_MBOX_SIZE];
struct sys_sem *not_empty;
struct sys_sem *not_full;
struct sys_sem *mutex;
int wait_send;
};
struct sys_sem {
unsigned int c;
pthread_condattr_t condattr;
pthread_cond_t cond;
pthread_mutex_t mutex;
};
struct sys_mutex {
pthread_mutex_t mutex;
};
struct sys_thread {
struct sys_thread *next;
pthread_t pthread;
};
#if SYS_LIGHTWEIGHT_PROT
static pthread_mutex_t lwprot_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_t lwprot_thread = (pthread_t)0xDEAD;
static int lwprot_count = 0;
#endif /* SYS_LIGHTWEIGHT_PROT */
static struct sys_sem *sys_sem_new_internal(u8_t count);
static void sys_sem_free_internal(struct sys_sem *sem);
static u32_t cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex,
u32_t timeout);
/*-----------------------------------------------------------------------------------*/
/* Threads */
static struct sys_thread *
introduce_thread(pthread_t id)
{
struct sys_thread *thread;
thread = (struct sys_thread *)malloc(sizeof(struct sys_thread));
if (thread != NULL) {
pthread_mutex_lock(&threads_mutex);
thread->next = threads;
thread->pthread = id;
threads = thread;
pthread_mutex_unlock(&threads_mutex);
}
return thread;
}
sys_thread_t
sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio)
{
int code;
pthread_t tmp;
struct sys_thread *st = NULL;
LWIP_UNUSED_ARG(name);
LWIP_UNUSED_ARG(stacksize);
LWIP_UNUSED_ARG(prio);
code = pthread_create(&tmp,
NULL,
(void *(*)(void *))
function,
arg);
if (0 == code) {
st = introduce_thread(tmp);
}
if (NULL == st) {
LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_create %d, st = 0x%lx",
code, (unsigned long)st));
abort();
}
return st;
}
/*-----------------------------------------------------------------------------------*/
/* Mailbox */
err_t
sys_mbox_new(struct sys_mbox **mb, int size)
{
struct sys_mbox *mbox;
LWIP_UNUSED_ARG(size);
mbox = (struct sys_mbox *)malloc(sizeof(struct sys_mbox));
if (mbox == NULL) {
return ERR_MEM;
}
mbox->first = mbox->last = 0;
mbox->not_empty = sys_sem_new_internal(0);
mbox->not_full = sys_sem_new_internal(0);
mbox->mutex = sys_sem_new_internal(1);
mbox->wait_send = 0;
SYS_STATS_INC_USED(mbox);
*mb = mbox;
return ERR_OK;
}
void
sys_mbox_free(struct sys_mbox **mb)
{
if ((mb != NULL) && (*mb != SYS_MBOX_NULL)) {
struct sys_mbox *mbox = *mb;
SYS_STATS_DEC(mbox.used);
sys_arch_sem_wait(&mbox->mutex, 0);
sys_sem_free_internal(mbox->not_empty);
sys_sem_free_internal(mbox->not_full);
sys_sem_free_internal(mbox->mutex);
mbox->not_empty = mbox->not_full = mbox->mutex = NULL;
/* LWIP_DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox); */
free(mbox);
}
}
err_t
sys_mbox_trypost(struct sys_mbox **mb, void *msg)
{
u8_t first;
struct sys_mbox *mbox;
LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
mbox = *mb;
sys_arch_sem_wait(&mbox->mutex, 0);
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_trypost: mbox %p msg %p\n",
(void *)mbox, (void *)msg));
if ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) {
sys_sem_signal(&mbox->mutex);
return ERR_MEM;
}
mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
if (mbox->last == mbox->first) {
first = 1;
} else {
first = 0;
}
mbox->last++;
if (first) {
sys_sem_signal(&mbox->not_empty);
}
sys_sem_signal(&mbox->mutex);
return ERR_OK;
}
void
sys_mbox_post(struct sys_mbox **mb, void *msg)
{
u8_t first;
struct sys_mbox *mbox;
LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
mbox = *mb;
sys_arch_sem_wait(&mbox->mutex, 0);
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", (void *)mbox, (void *)msg));
while ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) {
mbox->wait_send++;
sys_sem_signal(&mbox->mutex);
sys_arch_sem_wait(&mbox->not_full, 0);
sys_arch_sem_wait(&mbox->mutex, 0);
mbox->wait_send--;
}
mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
if (mbox->last == mbox->first) {
first = 1;
} else {
first = 0;
}
mbox->last++;
if (first) {
sys_sem_signal(&mbox->not_empty);
}
sys_sem_signal(&mbox->mutex);
}
u32_t
sys_arch_mbox_tryfetch(struct sys_mbox **mb, void **msg)
{
struct sys_mbox *mbox;
LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
mbox = *mb;
sys_arch_sem_wait(&mbox->mutex, 0);
if (mbox->first == mbox->last) {
sys_sem_signal(&mbox->mutex);
return SYS_MBOX_EMPTY;
}
if (msg != NULL) {
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p msg %p\n", (void *)mbox, *msg));
*msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
}
else{
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p, null msg\n", (void *)mbox));
}
mbox->first++;
if (mbox->wait_send) {
sys_sem_signal(&mbox->not_full);
}
sys_sem_signal(&mbox->mutex);
return 0;
}
u32_t
sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, u32_t timeout)
{
u32_t time_needed = 0;
struct sys_mbox *mbox;
LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
mbox = *mb;
/* The mutex lock is quick so we don't bother with the timeout
stuff here. */
sys_arch_sem_wait(&mbox->mutex, 0);
while (mbox->first == mbox->last) {
sys_sem_signal(&mbox->mutex);
/* We block while waiting for a mail to arrive in the mailbox. We
must be prepared to timeout. */
if (timeout != 0) {
time_needed = sys_arch_sem_wait(&mbox->not_empty, timeout);
if (time_needed == SYS_ARCH_TIMEOUT) {
return SYS_ARCH_TIMEOUT;
}
} else {
sys_arch_sem_wait(&mbox->not_empty, 0);
}
sys_arch_sem_wait(&mbox->mutex, 0);
}
if (msg != NULL) {
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", (void *)mbox, *msg));
*msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
}
else{
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p, null msg\n", (void *)mbox));
}
mbox->first++;
if (mbox->wait_send) {
sys_sem_signal(&mbox->not_full);
}
sys_sem_signal(&mbox->mutex);
return time_needed;
}
/*-----------------------------------------------------------------------------------*/
/* Semaphore */
static struct sys_sem *
sys_sem_new_internal(u8_t count)
{
struct sys_sem *sem;
sem = (struct sys_sem *)malloc(sizeof(struct sys_sem));
if (sem != NULL) {
sem->c = count;
pthread_condattr_init(&(sem->condattr));
#if !(defined(LWIP_UNIX_MACH) || (defined(LWIP_UNIX_ANDROID) && __ANDROID_API__ < 21))
pthread_condattr_setclock(&(sem->condattr), CLOCK_MONOTONIC);
#endif
pthread_cond_init(&(sem->cond), &(sem->condattr));
pthread_mutex_init(&(sem->mutex), NULL);
}
return sem;
}
err_t
sys_sem_new(struct sys_sem **sem, u8_t count)
{
SYS_STATS_INC_USED(sem);
*sem = sys_sem_new_internal(count);
if (*sem == NULL) {
return ERR_MEM;
}
return ERR_OK;
}
static u32_t
cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, u32_t timeout)
{
struct timespec rtime1, rtime2, ts;
int ret;
if (timeout == 0) {
pthread_cond_wait(cond, mutex);
return 0;
}
/* Get a timestamp and add the timeout value. */
get_monotonic_time(&rtime1);
#if defined(LWIP_UNIX_MACH) || (defined(LWIP_UNIX_ANDROID) && __ANDROID_API__ < 21)
ts.tv_sec = timeout / 1000L;
ts.tv_nsec = (timeout % 1000L) * 1000000L;
ret = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
#else
ts.tv_sec = rtime1.tv_sec + timeout / 1000L;
ts.tv_nsec = rtime1.tv_nsec + (timeout % 1000L) * 1000000L;
if (ts.tv_nsec >= 1000000000L) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000L;
}
ret = pthread_cond_timedwait(cond, mutex, &ts);
#endif
if (ret == ETIMEDOUT) {
return SYS_ARCH_TIMEOUT;
}
/* Calculate for how long we waited for the cond. */
get_monotonic_time(&rtime2);
ts.tv_sec = rtime2.tv_sec - rtime1.tv_sec;
ts.tv_nsec = rtime2.tv_nsec - rtime1.tv_nsec;
if (ts.tv_nsec < 0) {
ts.tv_sec--;
ts.tv_nsec += 1000000000L;
}
return (u32_t)(ts.tv_sec * 1000L + ts.tv_nsec / 1000000L);
}
u32_t
sys_arch_sem_wait(struct sys_sem **s, u32_t timeout)
{
u32_t time_needed = 0;
struct sys_sem *sem;
LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL));
sem = *s;
pthread_mutex_lock(&(sem->mutex));
while (sem->c <= 0) {
if (timeout > 0) {
time_needed = cond_wait(&(sem->cond), &(sem->mutex), timeout);
if (time_needed == SYS_ARCH_TIMEOUT) {
pthread_mutex_unlock(&(sem->mutex));
return SYS_ARCH_TIMEOUT;
}
/* pthread_mutex_unlock(&(sem->mutex));
return time_needed; */
} else {
cond_wait(&(sem->cond), &(sem->mutex), 0);
}
}
sem->c--;
pthread_mutex_unlock(&(sem->mutex));
return (u32_t)time_needed;
}
void
sys_sem_signal(struct sys_sem **s)
{
struct sys_sem *sem;
LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL));
sem = *s;
pthread_mutex_lock(&(sem->mutex));
sem->c++;
if (sem->c > 1) {
sem->c = 1;
}
pthread_cond_broadcast(&(sem->cond));
pthread_mutex_unlock(&(sem->mutex));
}
static void
sys_sem_free_internal(struct sys_sem *sem)
{
pthread_cond_destroy(&(sem->cond));
pthread_condattr_destroy(&(sem->condattr));
pthread_mutex_destroy(&(sem->mutex));
free(sem);
}
void
sys_sem_free(struct sys_sem **sem)
{
if ((sem != NULL) && (*sem != SYS_SEM_NULL)) {
SYS_STATS_DEC(sem.used);
sys_sem_free_internal(*sem);
}
}
/*-----------------------------------------------------------------------------------*/
/* Mutex */
/** Create a new mutex
* @param mutex pointer to the mutex to create
* @return a new mutex */
err_t
sys_mutex_new(struct sys_mutex **mutex)
{
struct sys_mutex *mtx;
mtx = (struct sys_mutex *)malloc(sizeof(struct sys_mutex));
if (mtx != NULL) {
pthread_mutex_init(&(mtx->mutex), NULL);
*mutex = mtx;
return ERR_OK;
}
else {
return ERR_MEM;
}
}
/** Lock a mutex
* @param mutex the mutex to lock */
void
sys_mutex_lock(struct sys_mutex **mutex)
{
pthread_mutex_lock(&((*mutex)->mutex));
}
/** Unlock a mutex
* @param mutex the mutex to unlock */
void
sys_mutex_unlock(struct sys_mutex **mutex)
{
pthread_mutex_unlock(&((*mutex)->mutex));
}
/** Delete a mutex
* @param mutex the mutex to delete */
void
sys_mutex_free(struct sys_mutex **mutex)
{
pthread_mutex_destroy(&((*mutex)->mutex));
free(*mutex);
}
#endif /* !NO_SYS */
/*-----------------------------------------------------------------------------------*/
/* Time */
u32_t
sys_now(void)
{
struct timespec ts;
get_monotonic_time(&ts);
return (u32_t)(ts.tv_sec * 1000L + ts.tv_nsec / 1000000L);
}
u32_t
sys_jiffies(void)
{
struct timespec ts;
get_monotonic_time(&ts);
return (u32_t)(ts.tv_sec * 1000000000L + ts.tv_nsec);
}
/*-----------------------------------------------------------------------------------*/
/* Init */
void
sys_init(void)
{
}
/*-----------------------------------------------------------------------------------*/
/* Critical section */
#if SYS_LIGHTWEIGHT_PROT
/** sys_prot_t sys_arch_protect(void)
This optional function does a "fast" critical region protection and returns
the previous protection level. This function is only called during very short
critical regions. An embedded system which supports ISR-based drivers might
want to implement this function by disabling interrupts. Task-based systems
might want to implement this by using a mutex or disabling tasking. This
function should support recursive calls from the same task or interrupt. In
other words, sys_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sys_arch_protect() is only required if your port is supporting an operating
system.
*/
sys_prot_t
sys_arch_protect(void)
{
/* Note that for the UNIX port, we are using a lightweight mutex, and our
* own counter (which is locked by the mutex). The return code is not actually
* used. */
if (lwprot_thread != pthread_self())
{
/* We are locking the mutex where it has not been locked before *
* or is being locked by another thread */
pthread_mutex_lock(&lwprot_mutex);
lwprot_thread = pthread_self();
lwprot_count = 1;
}
else
/* It is already locked by THIS thread */
lwprot_count++;
return 0;
}
/** void sys_arch_unprotect(sys_prot_t pval)
This optional function does a "fast" set of critical region protection to the
value specified by pval. See the documentation for sys_arch_protect() for
more information. This function is only required if your port is supporting
an operating system.
*/
void
sys_arch_unprotect(sys_prot_t pval)
{
LWIP_UNUSED_ARG(pval);
if (lwprot_thread == pthread_self())
{
if (--lwprot_count == 0)
{
lwprot_thread = (pthread_t) 0xDEAD;
pthread_mutex_unlock(&lwprot_mutex);
}
}
}
#endif /* SYS_LIGHTWEIGHT_PROT */