Retire lwip: the previous lwIP-based TCP/IP service
Change-Id: Id9bbf96344a6e9d796f6773547588a981e70bf0f
This commit is contained in:
parent
49bf8d5c6a
commit
3ea34559da
@ -177,7 +177,7 @@
|
||||
./etc/system.conf.d/hello minix-base
|
||||
./etc/system.conf.d/inet minix-base
|
||||
./etc/system.conf.d/ipc minix-base
|
||||
./etc/system.conf.d/lwip minix-base
|
||||
./etc/system.conf.d/lwip minix-base obsolete
|
||||
./etc/system.conf.d/random minix-base
|
||||
./etc/system.conf.d/uds minix-base
|
||||
./etc/system.conf.d/usb_hub minix-base
|
||||
@ -237,7 +237,7 @@
|
||||
./service/is minix-base
|
||||
./service/isofs minix-base
|
||||
./service/log minix-base
|
||||
./service/lwip minix-base
|
||||
./service/lwip minix-base obsolete
|
||||
./service/memory minix-base
|
||||
./service/mfs minix-base
|
||||
./service/mib minix-base
|
||||
|
@ -1221,7 +1221,7 @@
|
||||
./usr/include/minix/mmio.h minix-comp
|
||||
./usr/include/minix/mthread.h minix-comp
|
||||
./usr/include/minix/netdriver.h minix-comp
|
||||
./usr/include/minix/netsock.h minix-comp
|
||||
./usr/include/minix/netsock.h minix-comp obsolete
|
||||
./usr/include/minix/optset.h minix-comp
|
||||
./usr/include/minix/padconf.h minix-comp
|
||||
./usr/include/minix/param.h minix-comp
|
||||
@ -1922,7 +1922,7 @@
|
||||
./usr/lib/bc/libnetdriver.a minix-comp bitcode
|
||||
./usr/lib/bc/libnetpgp.a minix-comp bitcode
|
||||
./usr/lib/bc/libnetpgpverify.a minix-comp bitcode
|
||||
./usr/lib/bc/libnetsock.a minix-comp bitcode
|
||||
./usr/lib/bc/libnetsock.a minix-comp bitcode,obsolete
|
||||
./usr/lib/bc/libopcodes.a minix-comp bitcode,binutils
|
||||
./usr/lib/bc/libpci.a minix-comp bitcode
|
||||
./usr/lib/bc/libprop.a minix-comp bitcode
|
||||
@ -2077,8 +2077,8 @@
|
||||
./usr/lib/libmthread_pic.a minix-comp
|
||||
./usr/lib/libnetdriver.a minix-comp
|
||||
./usr/lib/libnetdriver_pic.a minix-comp
|
||||
./usr/lib/libnetsock.a minix-comp
|
||||
./usr/lib/libnetsock_pic.a minix-comp
|
||||
./usr/lib/libnetsock.a minix-comp obsolete
|
||||
./usr/lib/libnetsock_pic.a minix-comp obsolete
|
||||
./usr/lib/libobjc.a minix-comp gcc=45
|
||||
./usr/lib/libobjc_pic.a minix-comp gcc=45
|
||||
./usr/lib/libpci.a minix-comp
|
||||
|
@ -88,7 +88,7 @@
|
||||
./usr/lib/libnetdriver_g.a minix-debug debuglib
|
||||
./usr/lib/libnetpgp_g.a minix-debug debuglib
|
||||
./usr/lib/libnetpgpverify_g.a minix-debug debuglib
|
||||
./usr/lib/libnetsock_g.a minix-debug debuglib
|
||||
./usr/lib/libnetsock_g.a minix-debug debuglib,obsolete
|
||||
./usr/lib/libobjc_g.a minix-debug gcc=5,debuglib
|
||||
./usr/lib/libopcodes_g.a minix-debug debuglib
|
||||
./usr/lib/libpci_g.a minix-debug debuglib
|
||||
@ -186,7 +186,7 @@
|
||||
./usr/libdata/debug/service/is.debug minix-debug debug
|
||||
./usr/libdata/debug/service/isofs.debug minix-debug debug
|
||||
./usr/libdata/debug/service/log.debug minix-debug debug
|
||||
./usr/libdata/debug/service/lwip.debug minix-debug debug
|
||||
./usr/libdata/debug/service/lwip.debug minix-debug debug,obsolete
|
||||
./usr/libdata/debug/service/memory.debug minix-debug debug
|
||||
./usr/libdata/debug/service/mfs.debug minix-debug debug
|
||||
./usr/libdata/debug/service/mib.debug minix-debug debug
|
||||
|
12
etc/rs.inet
12
etc/rs.inet
@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Recovery script for INET/lwip. It restarts daemons dependent on it in order
|
||||
# Recovery script for INET. It restarts daemons dependent on it in order
|
||||
# to recover TCP state.
|
||||
|
||||
kill_by_name()
|
||||
@ -64,14 +64,8 @@ kill_by_name syslogd
|
||||
|
||||
# Wait a moment to let daemons clean themselves up
|
||||
sleep 3
|
||||
if [ X`/bin/sysenv lwip` = Xyes ]
|
||||
then
|
||||
minix-service up /service/lwip -script /etc/rs.inet -dev /dev/ip -restarts $restarts
|
||||
dhcpd --lwip &
|
||||
else
|
||||
minix-service up /service/inet -script /etc/rs.inet -dev /dev/ip -restarts $restarts
|
||||
daemonize dhcpd
|
||||
fi
|
||||
minix-service up /service/inet -script /etc/rs.inet -dev /dev/ip -restarts $restarts
|
||||
daemonize dhcpd
|
||||
daemonize nonamed -L
|
||||
daemonize syslogd
|
||||
|
||||
|
16
etc/usr/rc
16
etc/usr/rc
@ -191,12 +191,8 @@ start)
|
||||
arg="-args \"instance=$instance$arg\""
|
||||
eval up $driver -label $label $arg -period 5HZ
|
||||
done
|
||||
if [ X`/bin/sysenv lwip` = Xyes ]
|
||||
then
|
||||
up lwip -script /etc/rs.inet -dev /dev/ip
|
||||
else
|
||||
up inet -script /etc/rs.inet -dev /dev/ip
|
||||
fi
|
||||
|
||||
up inet -script /etc/rs.inet -dev /dev/ip
|
||||
|
||||
# pty needs to know the "tty" group ID
|
||||
up pty -dev /dev/ptmx -args "gid=`stat -f '%g' /dev/ptmx`"
|
||||
@ -371,13 +367,7 @@ start)
|
||||
if grep -s 'psip0.*default' /etc/inet.conf >/dev/null
|
||||
then ifconfig -h 10.0.0.1
|
||||
else
|
||||
if [ X`/bin/sysenv lwip` = Xyes ]
|
||||
then
|
||||
dhcpd --lwip &
|
||||
echo -n " dhcpd"
|
||||
else
|
||||
daemonize dhcpd
|
||||
fi
|
||||
daemonize dhcpd
|
||||
fi
|
||||
daemonize nonamed -L
|
||||
if [ -f "$DAEMONS" ]
|
||||
|
@ -32,6 +32,7 @@ SUBDIR+= ../minix/lib/libasyn \
|
||||
../minix/lib/libexec \
|
||||
../minix/lib/libfsdriver \
|
||||
../minix/lib/libinputdriver \
|
||||
../minix/lib/liblwip \
|
||||
../minix/lib/libminc \
|
||||
../minix/lib/libminixfs \
|
||||
../minix/lib/libnetdriver \
|
||||
@ -46,11 +47,6 @@ SUBDIR+= ../minix/lib/libasyn \
|
||||
SUBDIR+= ../minix/lib/libgcc_s_empty
|
||||
.endif
|
||||
|
||||
.if (${MKLWIP} == "yes")
|
||||
SUBDIR+= ../minix/lib/liblwip \
|
||||
../minix/lib/libnetsock
|
||||
.endif
|
||||
|
||||
.if (${MACHINE_ARCH} == "i386")
|
||||
SUBDIR+= ../minix/lib/libacpi \
|
||||
../minix/lib/libhgfs \
|
||||
|
@ -22,7 +22,7 @@ INCS+= acpi.h audio_fw.h bitmap.h \
|
||||
syslib.h sysutil.h timers.h type.h \
|
||||
u64.h usb.h usb_ch9.h vbox.h \
|
||||
vboxfs.h vboxif.h vboxtype.h vm.h \
|
||||
vfsif.h vtreefs.h libminixfs.h netsock.h \
|
||||
vfsif.h vtreefs.h libminixfs.h \
|
||||
virtio.h
|
||||
|
||||
.include <bsd.kinc.mk>
|
||||
|
@ -1,160 +0,0 @@
|
||||
#ifndef __NET_SERVER_SOCKET_H__
|
||||
#define __NET_SERVER_SOCKET_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <minix/ipc.h>
|
||||
#include <minix/endpoint.h>
|
||||
#include <minix/chardriver.h>
|
||||
|
||||
/*
|
||||
* User can set this variable to make the debugging output differ between
|
||||
* various users, e.g. "TCP" or "UDP"
|
||||
*/
|
||||
extern char * netsock_user_name;
|
||||
|
||||
#define SOCK_TYPE_IP 0
|
||||
#define SOCK_TYPE_TCP 1
|
||||
#define SOCK_TYPE_UDP 2
|
||||
#define SOCK_TYPES 3
|
||||
|
||||
struct socket;
|
||||
struct sock_req;
|
||||
|
||||
typedef int (* sock_op_opcl_t)(struct socket *);
|
||||
typedef int (* sock_op_io_t)(struct socket *, struct sock_req *, int blk);
|
||||
typedef int (* sock_op_select_t)(struct socket *, unsigned int);
|
||||
typedef int (* sock_op_select_reply_t)(struct socket *);
|
||||
|
||||
struct sock_ops {
|
||||
sock_op_opcl_t open;
|
||||
sock_op_opcl_t close;
|
||||
sock_op_io_t read;
|
||||
sock_op_io_t write;
|
||||
sock_op_io_t ioctl;
|
||||
sock_op_select_t select;
|
||||
sock_op_select_reply_t select_reply;
|
||||
};
|
||||
|
||||
struct recv_q {
|
||||
struct recv_q * next;
|
||||
void * data;
|
||||
};
|
||||
|
||||
#define SOCK_FLG_OP_PENDING 0x1
|
||||
#define SOCK_FLG_OP_IOCTL 0x10
|
||||
#define SOCK_FLG_OP_LISTENING 0x100 /* tcp socket is in a listening mode */
|
||||
#define SOCK_FLG_OP_CONNECTING 0x200 /* set when waiting for a connect */
|
||||
#define SOCK_FLG_OP_READING 0x400 /* reading operation in progress */
|
||||
#define SOCK_FLG_OP_WRITING 0x800 /* writing operation in progress */
|
||||
#define SOCK_FLG_CLOSED 0x1000 /* tcp socket has been closed do not
|
||||
expect any more data */
|
||||
/* select() flags - they say what action do we monitor */
|
||||
#define SOCK_FLG_SEL_WRITE 0x100000
|
||||
#define SOCK_FLG_SEL_READ 0x200000
|
||||
#define SOCK_FLG_SEL_ERROR 0x400000
|
||||
|
||||
#define sock_select_set(sock) ((sock)->flags & (SOCK_FLG_SEL_WRITE | \
|
||||
SOCK_FLG_SEL_READ | SOCK_FLG_SEL_ERROR))
|
||||
#define sock_select_read_set(sock) ((sock)->flags & SOCK_FLG_SEL_READ)
|
||||
#define sock_select_write_set(sock) ((sock)->flags & SOCK_FLG_SEL_WRITE)
|
||||
#define sock_select_rw_set(sock) ((sock)->flags & (SOCK_FLG_SEL_READ | \
|
||||
SOCK_FLG_SEL_WRITE))
|
||||
#define sock_select_error_set(sock) ((sock)->flags & SOCK_FLG_SEL_ERROR)
|
||||
#define sock_clear_select(sock) do { \
|
||||
(sock)->flags &= ~(SOCK_FLG_SEL_READ | SOCK_FLG_SEL_WRITE | \
|
||||
SOCK_FLG_SEL_ERROR); \
|
||||
} while (0)
|
||||
|
||||
struct sock_req {
|
||||
enum {
|
||||
SOCK_REQ_READ,
|
||||
SOCK_REQ_WRITE,
|
||||
SOCK_REQ_IOCTL
|
||||
} type;
|
||||
devminor_t minor;
|
||||
endpoint_t endpt;
|
||||
cp_grant_id_t grant;
|
||||
union {
|
||||
size_t size; /* for SOCK_REQ_READ, SOCK_REQ_WRITE */
|
||||
unsigned long req; /* for SOCK_REQ_IOCTL */
|
||||
};
|
||||
int flags;
|
||||
cdev_id_t id;
|
||||
};
|
||||
|
||||
struct socket {
|
||||
int type;
|
||||
u32_t flags;
|
||||
unsigned long usr_flags;
|
||||
void * pcb;
|
||||
struct sock_ops * ops;
|
||||
void * buf;
|
||||
size_t buf_size;
|
||||
struct sock_req req;
|
||||
void * shm;
|
||||
size_t shm_size;
|
||||
endpoint_t select_ep;
|
||||
struct recv_q * recv_head;
|
||||
struct recv_q * recv_tail;
|
||||
unsigned recv_data_size; /* sum of data enqueued */
|
||||
void * data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Each component needs to provide a method how to initially open a socket.
|
||||
* The rest is handled byt the socket library.
|
||||
*/
|
||||
int socket_open(devminor_t minor);
|
||||
|
||||
#define get_sock_num(x) ((long int) ((x) - socket_array))
|
||||
#define is_valid_sock_num(x) (x < MAX_SOCKETS)
|
||||
#define get_sock(x) &socket_array[x]
|
||||
|
||||
#define MAX_SOCKETS 255 /* FIXME as log as the sockets are identified by the
|
||||
minor device number 255 is ok */
|
||||
#define MAX_DEVS 5
|
||||
#define RESERVED (SOCK_TYPES + MAX_DEVS) /* rounded to 8 */
|
||||
|
||||
extern struct socket socket_array[MAX_SOCKETS];
|
||||
|
||||
void socket_request(message * m, int ipc_status);
|
||||
void mq_process(void);
|
||||
|
||||
struct socket * get_unused_sock(void);
|
||||
struct socket * get_nic_sock(unsigned dev);
|
||||
|
||||
void send_req_reply(struct sock_req * req, int status);
|
||||
|
||||
typedef void (* recv_data_free_fn)(void *);
|
||||
|
||||
int sock_enqueue_data(struct socket * sock, void * data, unsigned size);
|
||||
void * sock_dequeue_data(struct socket * sock);
|
||||
void sock_dequeue_data_all(struct socket * sock,
|
||||
recv_data_free_fn data_free);
|
||||
|
||||
void sock_select_notify(struct socket * sock);
|
||||
|
||||
static inline void * debug_malloc(size_t s)
|
||||
{
|
||||
void * ret;
|
||||
|
||||
ret = malloc(s);
|
||||
// printf("allocated %p size %d\n", ret, s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define debug_free(x) do { \
|
||||
if (0) \
|
||||
printf("free called from %s:%d %s freeing %p\n", __FILE__, \
|
||||
__LINE__, __func__, (x)); \
|
||||
free(x); \
|
||||
} while(0)
|
||||
|
||||
int generic_op_select(struct socket * sock, unsigned int sel);
|
||||
int generic_op_select_reply(struct socket * sock);
|
||||
|
||||
/* a function thr user has to provide to reply to the posix server */
|
||||
void posix_reply(endpoint_t ep, message * m);
|
||||
|
||||
#endif /* __NET_SERVER_SOCKET_H__ */
|
@ -14,6 +14,7 @@ SUBDIR+= libdevman
|
||||
SUBDIR+= libexec
|
||||
SUBDIR+= libfsdriver
|
||||
SUBDIR+= libinputdriver
|
||||
SUBDIR+= liblwip
|
||||
SUBDIR+= libminc
|
||||
SUBDIR+= libminixfs
|
||||
SUBDIR+= libnetdriver
|
||||
@ -28,11 +29,6 @@ SUBDIR+= libvtreefs
|
||||
SUBDIR+= libgcc_s_empty
|
||||
.endif
|
||||
|
||||
.if (${MKLWIP} == "yes")
|
||||
SUBDIR+= liblwip
|
||||
SUBDIR+= libnetsock
|
||||
.endif
|
||||
|
||||
.if (${MACHINE_ARCH} == "i386")
|
||||
SUBDIR+= libacpi
|
||||
SUBDIR+= libhgfs
|
||||
|
@ -208,7 +208,7 @@ static void chardriver_reply(message *mess, int ipc_status, int r)
|
||||
/* FIXME: we should be able to check FLAGS against
|
||||
* CDEV_NONBLOCK here, but in practice, several drivers do not
|
||||
* send a reply through this path (eg TTY) or simply do not
|
||||
* implement nonblocking calls properly (eg audio, LWIP).
|
||||
* implement nonblocking calls properly (eg audio).
|
||||
*/
|
||||
#if 0
|
||||
if (mess->m_vfs_lchardriver_readwrite.flags & CDEV_NONBLOCK)
|
||||
|
@ -1,11 +0,0 @@
|
||||
CPPFLAGS+= -D_MINIX_SYSTEM
|
||||
|
||||
LIB = netsock
|
||||
|
||||
CPPFLAGS += -I${.CURDIR}/include/ -D_SYSTEM
|
||||
CPPFLAGS+= -I${.CURDIR}/../../lib/liblwip/include -I${.CURDIR}/../../lib/liblwip/include/ipv4 -I${.CURDIR}/../../lib/liblwip/include/ipv6
|
||||
CFLAGS += -Wall -Wextra -std=c99
|
||||
|
||||
SRCS += socket.c
|
||||
|
||||
.include <bsd.lib.mk>
|
@ -1,560 +0,0 @@
|
||||
/*
|
||||
* This file implements handling of socket-related requests from VFS
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <minix/ipc.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/callnr.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include <minix/netsock.h>
|
||||
|
||||
#include <lwip/tcp.h>
|
||||
|
||||
#include <sys/ioc_net.h>
|
||||
|
||||
char * netsock_user_name = NULL;
|
||||
#define NETSOCK_USER_NAME (netsock_user_name ? netsock_user_name : "NETSOCK")
|
||||
|
||||
#define debug_print(str, ...) printf("%s : %s:%d : " str "\n", \
|
||||
NETSOCK_USER_NAME, __func__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#if 0
|
||||
#define debug_sock_print(...) debug_print(__VA_ARGS__)
|
||||
#else
|
||||
#define debug_sock_print(...)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define debug_sock_select_print(...) debug_print(__VA_ARGS__)
|
||||
#else
|
||||
#define debug_sock_select_print(...) debug_sock_print(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define netsock_panic(str, ...) panic("%s : " str, NETSOCK_USER_NAME, \
|
||||
##__VA_ARGS__)
|
||||
#define netsock_error(str, ...) printf("%s : " str, NETSOCK_USER_NAME, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
|
||||
struct socket socket_array[MAX_SOCKETS];
|
||||
|
||||
static int netsock_open(devminor_t minor, int access, endpoint_t user_endpt);
|
||||
static int netsock_close(devminor_t minor);
|
||||
static ssize_t netsock_read(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
|
||||
static ssize_t netsock_write(devminor_t minor, u64_t position,
|
||||
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||
cdev_id_t id);
|
||||
static int netsock_ioctl(devminor_t minor, unsigned long request,
|
||||
endpoint_t endpt, cp_grant_id_t grant, int flags,
|
||||
endpoint_t user_endpt, cdev_id_t id);
|
||||
static int netsock_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id);
|
||||
static int netsock_select(devminor_t minor, unsigned int ops,
|
||||
endpoint_t endpt);
|
||||
|
||||
static struct chardriver netsock_tab = {
|
||||
.cdr_open = netsock_open,
|
||||
.cdr_close = netsock_close,
|
||||
.cdr_read = netsock_read,
|
||||
.cdr_write = netsock_write,
|
||||
.cdr_ioctl = netsock_ioctl,
|
||||
.cdr_cancel = netsock_cancel,
|
||||
.cdr_select = netsock_select
|
||||
};
|
||||
|
||||
#define recv_q_alloc() debug_malloc(sizeof(struct recv_q))
|
||||
#define recv_q_free debug_free
|
||||
|
||||
struct mq {
|
||||
struct sock_req req;
|
||||
struct mq * prev;
|
||||
struct mq * next;
|
||||
};
|
||||
|
||||
#define mq_alloc() debug_malloc(sizeof(struct mq))
|
||||
#define mq_free debug_free
|
||||
|
||||
static struct mq * mq_head, *mq_tail;
|
||||
|
||||
static int mq_enqueue(struct sock_req * req)
|
||||
{
|
||||
struct mq * mq;
|
||||
|
||||
debug_sock_print("sock %d op %d", req->minor, req->type);
|
||||
mq = mq_alloc();
|
||||
|
||||
if (mq == NULL)
|
||||
return -1;
|
||||
|
||||
mq->next = NULL;
|
||||
mq->req = *req;
|
||||
|
||||
if (mq_head) {
|
||||
mq->prev = mq_tail;
|
||||
mq_tail->next = mq;
|
||||
mq_tail = mq;
|
||||
}
|
||||
else {
|
||||
mq->prev = NULL;
|
||||
mq_head = mq_tail = mq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__unused static struct mq * mq_dequeue_head(void)
|
||||
{
|
||||
struct mq * ret;
|
||||
|
||||
if (!mq_head)
|
||||
return NULL;
|
||||
|
||||
ret = mq_head;
|
||||
|
||||
if (mq_head != mq_tail) {
|
||||
mq_head = mq_head->next;
|
||||
mq_head->prev = NULL;
|
||||
} else
|
||||
mq_head = mq_tail = NULL;
|
||||
|
||||
debug_sock_print("socket %d\n", ret->req.minor);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mq_dequeue(struct mq * mq)
|
||||
{
|
||||
if (mq_head == mq_tail)
|
||||
mq_head = mq_tail = NULL;
|
||||
else {
|
||||
if (mq->prev == NULL) {
|
||||
mq_head = mq->next;
|
||||
mq_head->prev = NULL;
|
||||
} else
|
||||
mq->prev->next = mq->next;
|
||||
if (mq->next == NULL) {
|
||||
mq_tail = mq->prev;
|
||||
mq_tail->next = NULL;
|
||||
} else
|
||||
mq->next->prev = mq->prev;
|
||||
}
|
||||
}
|
||||
|
||||
static int mq_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
|
||||
{
|
||||
struct mq * mq;
|
||||
|
||||
for (mq = mq_tail; mq; mq = mq->prev) {
|
||||
if (minor == mq->req.minor && endpt == mq->req.endpt &&
|
||||
id == mq->req.id) {
|
||||
debug_sock_print("socket %d\n", minor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mq) {
|
||||
mq_dequeue(mq);
|
||||
mq_free(mq);
|
||||
}
|
||||
|
||||
/* FIXME: shouldn't this return (!!mq) ? */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sock_enqueue_data(struct socket * sock, void * data, unsigned size)
|
||||
{
|
||||
struct recv_q * r;
|
||||
|
||||
if (!(r = recv_q_alloc()))
|
||||
return ENOMEM;
|
||||
|
||||
r->data = data;
|
||||
r->next = NULL;
|
||||
|
||||
if (sock->recv_head) {
|
||||
sock->recv_tail->next = r;
|
||||
sock->recv_tail = r;
|
||||
} else {
|
||||
sock->recv_head = sock->recv_tail = r;
|
||||
}
|
||||
|
||||
assert(size > 0);
|
||||
sock->recv_data_size += size;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void * sock_dequeue_data(struct socket * sock)
|
||||
{
|
||||
void * data;
|
||||
struct recv_q * r;
|
||||
|
||||
if ((r = sock->recv_head)) {
|
||||
data = r->data;
|
||||
if (!(sock->recv_head = r->next))
|
||||
sock->recv_tail = NULL;
|
||||
recv_q_free(r);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sock_dequeue_data_all(struct socket * sock,
|
||||
recv_data_free_fn data_free)
|
||||
{
|
||||
void * data;
|
||||
|
||||
while ((data = sock_dequeue_data(sock)))
|
||||
data_free(data);
|
||||
sock->recv_data_size = 0;
|
||||
}
|
||||
|
||||
void send_req_reply(struct sock_req * req, int status)
|
||||
{
|
||||
if (status == EDONTREPLY)
|
||||
return;
|
||||
|
||||
chardriver_reply_task(req->endpt, req->id, status);
|
||||
}
|
||||
|
||||
void sock_select_notify(struct socket * sock)
|
||||
{
|
||||
unsigned int ops;
|
||||
|
||||
debug_sock_select_print("socket num %ld", get_sock_num(sock));
|
||||
assert(sock->select_ep != NONE);
|
||||
|
||||
ops = sock->ops->select_reply(sock);
|
||||
if (ops == 0) {
|
||||
debug_sock_select_print("called from %p sflags 0x%x TXsz %d RXsz %d\n",
|
||||
__builtin_return_address(0), sock->flags,
|
||||
sock->buf_size, sock->recv_data_size);
|
||||
return;
|
||||
}
|
||||
|
||||
chardriver_reply_select(sock->select_ep, get_sock_num(sock), ops);
|
||||
|
||||
sock_clear_select(sock);
|
||||
sock->select_ep = NONE;
|
||||
}
|
||||
|
||||
struct socket * get_unused_sock(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = SOCK_TYPES + MAX_DEVS; i < MAX_SOCKETS; i++) {
|
||||
if (socket_array[i].ops == NULL) {
|
||||
/* clear it all */
|
||||
memset(&socket_array[i], 0, sizeof(struct socket));
|
||||
return &socket_array[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int socket_request_socket(struct socket * sock, struct sock_req * req)
|
||||
{
|
||||
int r, blocking = (req->flags & CDEV_NONBLOCK) ? 0 : 1;
|
||||
|
||||
switch (req->type) {
|
||||
case SOCK_REQ_READ:
|
||||
if (sock->ops && sock->ops->read)
|
||||
r = sock->ops->read(sock, req, blocking);
|
||||
else
|
||||
r = EINVAL;
|
||||
break;
|
||||
case SOCK_REQ_WRITE:
|
||||
if (sock->ops && sock->ops->write)
|
||||
r = sock->ops->write(sock, req, blocking);
|
||||
else
|
||||
r = EINVAL;
|
||||
break;
|
||||
case SOCK_REQ_IOCTL:
|
||||
if (sock->ops && sock->ops->ioctl)
|
||||
r = sock->ops->ioctl(sock, req, blocking);
|
||||
else
|
||||
r = EINVAL;
|
||||
break;
|
||||
default:
|
||||
netsock_panic("cannot happen!");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int netsock_open(devminor_t minor, int UNUSED(access),
|
||||
endpoint_t UNUSED(user_endpt))
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = socket_open(minor)) < 0)
|
||||
return r;
|
||||
|
||||
return CDEV_CLONED | r;
|
||||
}
|
||||
|
||||
static int netsock_close(devminor_t minor)
|
||||
{
|
||||
struct socket *sock;
|
||||
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EINVAL;
|
||||
|
||||
if (sock->ops && sock->ops->close) {
|
||||
sock->flags &= ~SOCK_FLG_OP_PENDING;
|
||||
|
||||
return sock->ops->close(sock);
|
||||
} else
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
static int netsock_request(struct socket *sock, struct sock_req *req)
|
||||
{
|
||||
const char *o __unused;
|
||||
|
||||
/*
|
||||
* If an operation is pending (blocking operation) or writing is
|
||||
* still going on and we're reading, suspend the new operation
|
||||
*/
|
||||
if ((sock->flags & SOCK_FLG_OP_PENDING) ||
|
||||
(req->type == SOCK_REQ_READ &&
|
||||
sock->flags & SOCK_FLG_OP_WRITING)) {
|
||||
if (sock->flags & SOCK_FLG_OP_READING)
|
||||
o = "READ";
|
||||
else if (sock->flags & SOCK_FLG_OP_WRITING)
|
||||
o = "WRITE";
|
||||
else
|
||||
o = "non R/W op";
|
||||
debug_sock_print("socket %ld is busy by %s flgs 0x%x\n",
|
||||
get_sock_num(sock), o, sock->flags);
|
||||
|
||||
if (mq_enqueue(req) != 0) {
|
||||
debug_sock_print("Enqueuing suspended call failed");
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
return EDONTREPLY;
|
||||
}
|
||||
|
||||
return socket_request_socket(sock, req);
|
||||
}
|
||||
|
||||
static ssize_t netsock_read(devminor_t minor, u64_t UNUSED(position),
|
||||
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||
cdev_id_t id)
|
||||
{
|
||||
struct socket *sock;
|
||||
struct sock_req req;
|
||||
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EINVAL;
|
||||
|
||||
/* Build a request record for this request. */
|
||||
req.type = SOCK_REQ_READ;
|
||||
req.minor = minor;
|
||||
req.endpt = endpt;
|
||||
req.grant = grant;
|
||||
req.size = size;
|
||||
req.flags = flags;
|
||||
req.id = id;
|
||||
|
||||
/* Process the request. */
|
||||
return netsock_request(sock, &req);
|
||||
}
|
||||
|
||||
static ssize_t netsock_write(devminor_t minor, u64_t UNUSED(position),
|
||||
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||
cdev_id_t id)
|
||||
{
|
||||
struct socket *sock;
|
||||
struct sock_req req;
|
||||
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EINVAL;
|
||||
|
||||
/* Build a request record for this request. */
|
||||
req.type = SOCK_REQ_WRITE;
|
||||
req.minor = minor;
|
||||
req.endpt = endpt;
|
||||
req.grant = grant;
|
||||
req.size = size;
|
||||
req.flags = flags;
|
||||
req.id = id;
|
||||
|
||||
/* Process the request. */
|
||||
return netsock_request(sock, &req);
|
||||
}
|
||||
|
||||
static int netsock_ioctl(devminor_t minor, unsigned long request,
|
||||
endpoint_t endpt, cp_grant_id_t grant, int flags,
|
||||
endpoint_t UNUSED(user_endpt), cdev_id_t id)
|
||||
{
|
||||
struct socket *sock;
|
||||
struct sock_req req;
|
||||
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EINVAL;
|
||||
|
||||
/* Build a request record for this request. */
|
||||
req.type = SOCK_REQ_IOCTL;
|
||||
req.minor = minor;
|
||||
req.req = request;
|
||||
req.endpt = endpt;
|
||||
req.grant = grant;
|
||||
req.flags = flags;
|
||||
req.id = id;
|
||||
|
||||
/* Process the request. */
|
||||
return netsock_request(sock, &req);
|
||||
}
|
||||
|
||||
static int netsock_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
|
||||
{
|
||||
struct socket *sock;
|
||||
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EDONTREPLY;
|
||||
|
||||
debug_sock_print("socket num %ld", get_sock_num(sock));
|
||||
|
||||
/* Cancel the last operation in the queue */
|
||||
if (mq_cancel(minor, endpt, id))
|
||||
return EINTR;
|
||||
|
||||
/* Cancel any ongoing blocked read */
|
||||
if ((sock->flags & SOCK_FLG_OP_PENDING) &&
|
||||
(sock->flags & SOCK_FLG_OP_READING) &&
|
||||
endpt == sock->req.endpt && id == sock->req.id) {
|
||||
sock->flags &= ~SOCK_FLG_OP_PENDING;
|
||||
return EINTR;
|
||||
}
|
||||
|
||||
/* The request may not be found. This is OK. Do not reply. */
|
||||
return EDONTREPLY;
|
||||
}
|
||||
|
||||
static int netsock_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
|
||||
{
|
||||
struct socket *sock;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* Select is always executed immediately and is never suspended.
|
||||
* Although, it sets actions which must be monitored
|
||||
*/
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EBADF;
|
||||
|
||||
assert(sock->select_ep == NONE || sock->select_ep == endpt);
|
||||
|
||||
if (sock->ops && sock->ops->select) {
|
||||
sock->select_ep = endpt;
|
||||
r = sock->ops->select(sock, ops);
|
||||
if (!sock_select_set(sock))
|
||||
sock->select_ep = NONE;
|
||||
} else
|
||||
r = EINVAL;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void socket_request(message * m, int ipc_status)
|
||||
{
|
||||
debug_sock_print("request %d", m->m_type);
|
||||
|
||||
/* Let the chardriver library decode the request for us. */
|
||||
chardriver_process(&netsock_tab, m, ipc_status);
|
||||
}
|
||||
|
||||
void mq_process(void)
|
||||
{
|
||||
struct mq * mq;
|
||||
struct socket * sock;
|
||||
int r;
|
||||
|
||||
mq = mq_head;
|
||||
|
||||
while(mq) {
|
||||
struct mq * next = mq->next;
|
||||
|
||||
sock = get_sock(mq->req.minor);
|
||||
if (!(sock->flags & SOCK_FLG_OP_PENDING) &&
|
||||
!(mq->req.type == SOCK_REQ_READ &&
|
||||
sock->flags & SOCK_FLG_OP_WRITING)) {
|
||||
debug_sock_print("resuming op on sock %ld\n",
|
||||
get_sock_num(sock));
|
||||
sock->req = mq->req;
|
||||
r = socket_request_socket(sock, &sock->req);
|
||||
send_req_reply(&sock->req, r);
|
||||
mq_dequeue(mq);
|
||||
mq_free(mq);
|
||||
return;
|
||||
}
|
||||
|
||||
mq = next;
|
||||
}
|
||||
}
|
||||
|
||||
int generic_op_select(struct socket * sock, unsigned int sel)
|
||||
{
|
||||
int retsel = 0;
|
||||
|
||||
debug_sock_print("socket num %ld 0x%x", get_sock_num(sock), sel);
|
||||
|
||||
/* in this case any operation would block, no error */
|
||||
if (sock->flags & SOCK_FLG_OP_PENDING) {
|
||||
if (sel & CDEV_NOTIFY) {
|
||||
if (sel & CDEV_OP_RD)
|
||||
sock->flags |= SOCK_FLG_SEL_READ;
|
||||
if (sel & CDEV_OP_WR)
|
||||
sock->flags |= SOCK_FLG_SEL_WRITE;
|
||||
/* FIXME we do not monitor error */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sel & CDEV_OP_RD) {
|
||||
if (sock->recv_head)
|
||||
retsel |= CDEV_OP_RD;
|
||||
else if (sel & CDEV_NOTIFY)
|
||||
sock->flags |= SOCK_FLG_SEL_READ;
|
||||
}
|
||||
/* FIXME generic packet socket never blocks on write */
|
||||
if (sel & CDEV_OP_WR)
|
||||
retsel |= CDEV_OP_WR;
|
||||
/* FIXME CDEV_OP_ERR is ignored, we do not generate exceptions */
|
||||
|
||||
return retsel;
|
||||
}
|
||||
|
||||
int generic_op_select_reply(struct socket * sock)
|
||||
{
|
||||
unsigned int sel = 0;
|
||||
|
||||
assert(sock->select_ep != NONE);
|
||||
debug_sock_print("socket num %ld", get_sock_num(sock));
|
||||
|
||||
/* unused for generic packet socket, see generic_op_select() */
|
||||
assert((sock->flags & (SOCK_FLG_SEL_WRITE | SOCK_FLG_SEL_ERROR)) == 0);
|
||||
|
||||
if (sock->flags & SOCK_FLG_OP_PENDING) {
|
||||
debug_sock_print("WARNING socket still blocking!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sock->flags & SOCK_FLG_SEL_READ && sock->recv_head)
|
||||
sel |= CDEV_OP_RD;
|
||||
|
||||
if (sel)
|
||||
sock->flags &= ~(SOCK_FLG_SEL_WRITE | SOCK_FLG_SEL_READ |
|
||||
SOCK_FLG_SEL_ERROR);
|
||||
|
||||
return sel;
|
||||
}
|
@ -2,11 +2,6 @@
|
||||
|
||||
.if ${MKIMAGEONLY} == "no"
|
||||
SUBDIR+= inet
|
||||
|
||||
. if ${MKLWIP} == "yes"
|
||||
SUBDIR+= lwip
|
||||
. endif # ${MKLWIP} == "yes"
|
||||
|
||||
SUBDIR+= uds
|
||||
.endif # ${MKIMAGEONLY} == "no"
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
# Makefile for lwip server.
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= lwip
|
||||
SRCS= lwip.c \
|
||||
driver.c \
|
||||
udp.c \
|
||||
tcp.c \
|
||||
raw_ip.c \
|
||||
inet_config.c \
|
||||
eth.c \
|
||||
rtinfo.c
|
||||
|
||||
FILES=${PROG}.conf
|
||||
FILESNAME=${PROG}
|
||||
FILESDIR= /etc/system.conf.d
|
||||
|
||||
.PATH: ${.CURDIR}/generic
|
||||
|
||||
DPADD+= ${LIBCHARDRIVER} ${LIBSYS} ${LIBTIMERS} ${LIBLWIP} ${LIBNETSOCK}
|
||||
LDADD+= -lchardriver -lsys -ltimers -llwip -lnetsock
|
||||
|
||||
WARNS?=2
|
||||
|
||||
CPPFLAGS+= -I${NETBSDSRCDIR}/minix/lib/liblwip/include
|
||||
CPPFLAGS+= -I${NETBSDSRCDIR}/minix/lib/liblwip/include/ipv4
|
||||
CPPFLAGS+= -I${NETBSDSRCDIR}/minix/lib/liblwip/include/ipv6
|
||||
CPPFLAGS+= -D_SYSTEM=1
|
||||
|
||||
CFLAGS+= -std=c99
|
||||
|
||||
.include <minix.service.mk>
|
@ -1,816 +0,0 @@
|
||||
/*
|
||||
* This file implements handling of meesagges send by drivers
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <minix/ipc.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include <minix/safecopies.h>
|
||||
#include <minix/netsock.h>
|
||||
|
||||
#include <sys/ioc_net.h>
|
||||
#include <net/gen/in.h>
|
||||
#include <net/gen/ip_io.h>
|
||||
#include <net/gen/route.h>
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
|
||||
#include <lwip/pbuf.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <netif/etharp.h>
|
||||
|
||||
#include "proto.h"
|
||||
#include "driver.h"
|
||||
|
||||
#if 0
|
||||
#define debug_drv_print(str, ...) printf("LWIP %s:%d : " str "\n", \
|
||||
__func__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define debug_drv_print(...) debug_print(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define RAW_BUF_SIZE (32 << 10)
|
||||
|
||||
static struct nic devices[MAX_DEVS];
|
||||
|
||||
static ip_addr_t ip_addr_none = { IPADDR_NONE };
|
||||
|
||||
void nic_assign_driver(const char * dev_type,
|
||||
unsigned int dev_num,
|
||||
const char * driver_name,
|
||||
unsigned int instance,
|
||||
int is_default)
|
||||
{
|
||||
struct nic * nic;
|
||||
|
||||
if (strcmp(dev_type, "eth") != 0) {
|
||||
printf("LWIP : Cannot handle other than ethernet devices, "
|
||||
"ignoring '%s%d'\n", dev_type, dev_num);
|
||||
return;
|
||||
}
|
||||
|
||||
nic = &devices[dev_num];
|
||||
snprintf(nic->name, NIC_NAME_LEN, "%s%d", dev_type, dev_num);
|
||||
nic->name[NIC_NAME_LEN - 1] = '\0';
|
||||
snprintf(nic->drv_name, DRV_NAME_LEN, "%s_%d", driver_name, instance);
|
||||
nic->drv_name[DRV_NAME_LEN - 1] = '\0';
|
||||
nic->is_default = is_default;
|
||||
nic->netif.name[0] = 'e';
|
||||
nic->netif.name[1] = 't';
|
||||
nic->netif.num = dev_num;
|
||||
|
||||
debug_print("/dev/%s driven by %s default = %d",
|
||||
nic->name, nic->drv_name, is_default);
|
||||
}
|
||||
|
||||
static struct nic * lookup_nic_by_drv_ep(endpoint_t ep)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_DEVS; i++) {
|
||||
if (devices[i].drv_ep == ep)
|
||||
return &devices[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nic * lookup_nic_by_drv_name(const char * name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_DEVS; i++) {
|
||||
if (strcmp(devices[i].drv_name, name) == 0)
|
||||
return &devices[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nic * lookup_nic_default(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_DEVS; i++) {
|
||||
if (devices[i].is_default)
|
||||
return &devices[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nic * nic_get(int i)
|
||||
{
|
||||
|
||||
if (i < 0 || i >= MAX_DEVS || devices[i].drv_ep == NONE)
|
||||
return NULL;
|
||||
|
||||
return &devices[i];
|
||||
}
|
||||
|
||||
void nic_init_all(void)
|
||||
{
|
||||
int i;
|
||||
unsigned int g;
|
||||
|
||||
for (i = 0; i < MAX_DEVS; i++) {
|
||||
devices[i].drv_ep = NONE;
|
||||
devices[i].is_default = 0;
|
||||
|
||||
if (cpf_getgrants(&devices[i].rx_iogrant, 1) != 1)
|
||||
panic("Cannot initialize grants");
|
||||
if (cpf_getgrants(&devices[i].rx_iovec[0].iov_grant, 1) != 1)
|
||||
panic("Cannot initialize grants");
|
||||
if (cpf_getgrants(&devices[i].tx_iogrant, 1) != 1)
|
||||
panic("Cannot initialize grants");
|
||||
for (g = 0; g < TX_IOVEC_NUM; g++) {
|
||||
cp_grant_id_t * gid = &devices[i].tx_iovec[g].iov_grant;
|
||||
if (cpf_getgrants(gid, 1) != 1)
|
||||
panic("Cannot initialize grants");
|
||||
}
|
||||
devices[i].raw_socket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void driver_setup_read(struct nic * nic)
|
||||
{
|
||||
message m;
|
||||
|
||||
debug_print("device /dev/%s", nic->name);
|
||||
//assert(nic->rx_pbuf == NULL);
|
||||
if (!(nic->rx_pbuf == NULL)) {
|
||||
panic("device /dev/%s rx_pbuf %p", nic->name, nic->rx_pbuf);
|
||||
}
|
||||
|
||||
if (!(nic->rx_pbuf = pbuf_alloc(PBUF_RAW, ETH_MAX_PACK_SIZE + ETH_CRC_SIZE, PBUF_RAM)))
|
||||
panic("Cannot allocate rx pbuf");
|
||||
|
||||
if (cpf_setgrant_direct(nic->rx_iovec[0].iov_grant,
|
||||
nic->drv_ep, (vir_bytes) nic->rx_pbuf->payload,
|
||||
nic->rx_pbuf->len, CPF_WRITE) != OK)
|
||||
panic("Failed to set grant");
|
||||
nic->rx_iovec[0].iov_size = nic->rx_pbuf->len;
|
||||
|
||||
m.m_type = DL_READV_S;
|
||||
m.m_net_netdrv_dl_readv_s.count = 1;
|
||||
m.m_net_netdrv_dl_readv_s.grant = nic->rx_iogrant;
|
||||
|
||||
if (asynsend(nic->drv_ep, &m) != OK)
|
||||
panic("asynsend to the driver failed!");
|
||||
}
|
||||
|
||||
static void nic_up(struct nic * nic, message * m)
|
||||
{
|
||||
memcpy(nic->netif.hwaddr, m->m_netdrv_net_dl_conf.hw_addr,
|
||||
sizeof(nic->netif.hwaddr));
|
||||
|
||||
debug_print("device %s is up MAC : %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
nic->name,
|
||||
nic->netif.hwaddr[0],
|
||||
nic->netif.hwaddr[1],
|
||||
nic->netif.hwaddr[2],
|
||||
nic->netif.hwaddr[3],
|
||||
nic->netif.hwaddr[4],
|
||||
nic->netif.hwaddr[5]);
|
||||
|
||||
driver_setup_read(nic);
|
||||
|
||||
netif_set_link_up(&nic->netif);
|
||||
netif_set_up(&nic->netif);
|
||||
}
|
||||
|
||||
int driver_tx(struct nic * nic)
|
||||
{
|
||||
struct packet_q * pkt;
|
||||
unsigned int len;
|
||||
message m;
|
||||
|
||||
int err;
|
||||
|
||||
debug_print("device /dev/%s", nic->name);
|
||||
assert(nic->tx_buffer);
|
||||
|
||||
pkt = driver_tx_head(nic);
|
||||
if (pkt == NULL) {
|
||||
debug_print("no packets enqueued");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(pkt->buf_len <= nic->max_pkt_sz);
|
||||
|
||||
if ((len = pkt->buf_len) < nic->min_pkt_sz)
|
||||
len = nic->min_pkt_sz;
|
||||
err = cpf_setgrant_direct(nic->tx_iovec[0].iov_grant,
|
||||
nic->drv_ep, (vir_bytes) pkt->buf,
|
||||
len, CPF_READ);
|
||||
debug_print("packet len %d", len);
|
||||
if (err != OK)
|
||||
panic("Failed to set grant");
|
||||
nic->tx_iovec[0].iov_size = len;
|
||||
|
||||
if (cpf_setgrant_direct(nic->tx_iogrant, nic->drv_ep,
|
||||
(vir_bytes) &nic->tx_iovec,
|
||||
sizeof(iovec_s_t), CPF_READ) != OK)
|
||||
panic("Failed to set grant");
|
||||
|
||||
m.m_type = DL_WRITEV_S;
|
||||
m.m_net_netdrv_dl_writev_s.count = 1;
|
||||
m.m_net_netdrv_dl_writev_s.grant = nic->tx_iogrant;
|
||||
|
||||
if (asynsend(nic->drv_ep, &m) != OK)
|
||||
panic("asynsend to the driver failed!");
|
||||
nic->state = DRV_SENDING;
|
||||
|
||||
debug_print("packet sent to driver");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void nic_pkt_sent(struct nic * nic)
|
||||
{
|
||||
debug_print("device /dev/%s", nic->name);
|
||||
assert(nic->state != DRV_IDLE);
|
||||
|
||||
/* packet has been sent, we are not intereted anymore */
|
||||
driver_tx_dequeue(nic);
|
||||
/*
|
||||
* Try to transmit the next packet. Failure means that no packet is
|
||||
* enqueued and thus the device is entering idle state
|
||||
*/
|
||||
if (!driver_tx(nic))
|
||||
nic->state = DRV_IDLE;
|
||||
}
|
||||
|
||||
__unused static void print_pkt(unsigned char * pkt, int len)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
printf("--- PKT ---\n");
|
||||
|
||||
while (i < len) {
|
||||
int x;
|
||||
|
||||
for (x = 0; x < 8 && i < len; x++, i++)
|
||||
printf("%02x ", pkt[i]);
|
||||
|
||||
kputc(' ');
|
||||
|
||||
for (x = 0; x < 8 && i < len; x++, i++)
|
||||
printf("%02x ", pkt[i]);
|
||||
|
||||
kputc('\n');
|
||||
}
|
||||
|
||||
printf("--- PKT END ---\n");
|
||||
}
|
||||
|
||||
static int raw_receive(struct sock_req *req,
|
||||
struct pbuf *pbuf)
|
||||
{
|
||||
struct pbuf * p;
|
||||
unsigned int rem_len = req->size;
|
||||
unsigned int written = 0;
|
||||
int err;
|
||||
|
||||
debug_print("user buffer size : %d\n", rem_len);
|
||||
|
||||
for (p = pbuf; p && rem_len; p = p->next) {
|
||||
size_t cp_len;
|
||||
|
||||
cp_len = (rem_len < p->len) ? rem_len : p->len;
|
||||
err = copy_to_user(req->endpt, p->payload, cp_len,
|
||||
req->grant, written);
|
||||
if (err != OK)
|
||||
return err;
|
||||
|
||||
written += cp_len;
|
||||
rem_len -= cp_len;
|
||||
}
|
||||
|
||||
debug_print("copied %d bytes\n", written);
|
||||
return written;
|
||||
}
|
||||
|
||||
int raw_socket_input(struct pbuf * pbuf, struct nic * nic)
|
||||
{
|
||||
struct socket * sock;
|
||||
struct pbuf * pbuf_new;
|
||||
|
||||
if ((sock = nic->raw_socket) == NULL)
|
||||
return 0;
|
||||
|
||||
debug_print("socket num : %ld", get_sock_num(sock));
|
||||
|
||||
if (sock->flags & SOCK_FLG_OP_PENDING) {
|
||||
int ret;
|
||||
/* we are resuming a suspended operation */
|
||||
ret = raw_receive(&sock->req, pbuf);
|
||||
|
||||
send_req_reply(&sock->req, ret);
|
||||
sock->flags &= ~SOCK_FLG_OP_PENDING;
|
||||
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do not enqueue more data than allowed */
|
||||
if (sock->recv_data_size > RAW_BUF_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* nobody is waiting for the data or an error occured above, we enqueue
|
||||
* the packet. We store a copy of this packet
|
||||
*/
|
||||
pbuf_new = pbuf_alloc(PBUF_RAW, pbuf->tot_len, PBUF_RAM);
|
||||
if (pbuf_new == NULL) {
|
||||
debug_print("LWIP : cannot allocated new pbuf\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pbuf_copy(pbuf_new, pbuf) != ERR_OK) {
|
||||
debug_print("LWIP : cannot copy pbuf\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we didn't managed to enqueue the packet we report it as not
|
||||
* consumed
|
||||
*/
|
||||
if (sock_enqueue_data(sock, pbuf_new, pbuf_new->tot_len) != OK) {
|
||||
pbuf_free(pbuf_new);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nic_pkt_received(struct nic * nic, unsigned int size)
|
||||
{
|
||||
assert(nic->netif.input);
|
||||
|
||||
#if 0
|
||||
print_pkt((unsigned char *) nic->rx_pbuf->payload, 64 /*nic->rx_pbuf->len */);
|
||||
#endif
|
||||
|
||||
assert(nic->rx_pbuf->tot_len == nic->rx_pbuf->len);
|
||||
nic->rx_pbuf->tot_len = nic->rx_pbuf->len = size - ETH_CRC_SIZE;
|
||||
|
||||
nic->netif.input(nic->rx_pbuf, &nic->netif);
|
||||
nic->rx_pbuf = NULL;
|
||||
driver_setup_read(nic);
|
||||
}
|
||||
|
||||
void driver_request(message * m)
|
||||
{
|
||||
struct nic * nic;
|
||||
|
||||
if ((nic = lookup_nic_by_drv_ep(m->m_source)) == NULL) {
|
||||
printf("LWIP : request from unknown driver %d\n", m->m_source);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m->m_type) {
|
||||
case DL_CONF_REPLY:
|
||||
if (m->m_netdrv_net_dl_conf.stat == OK)
|
||||
nic_up(nic, m);
|
||||
break;
|
||||
case DL_TASK_REPLY:
|
||||
/*
|
||||
if (!(m->m_netdrv_net_dl_task.flags & DL_PACK_SEND) &&
|
||||
!(m->m_netdrv_net_dl_task.flags & DL_PACK_RECV)) {
|
||||
printf("void reply from driver\n");
|
||||
break;
|
||||
}
|
||||
*/
|
||||
if (m->m_netdrv_net_dl_task.flags & DL_PACK_SEND)
|
||||
nic_pkt_sent(nic);
|
||||
if (m->m_netdrv_net_dl_task.flags & DL_PACK_RECV)
|
||||
nic_pkt_received(nic, m->m_netdrv_net_dl_task.count);
|
||||
break;
|
||||
case DL_STAT_REPLY:
|
||||
break;
|
||||
default:
|
||||
printf("LWIP : unexpected request %d from driver %d\n",
|
||||
m->m_type, m->m_source);
|
||||
}
|
||||
}
|
||||
|
||||
void driver_up(const char * label, endpoint_t ep)
|
||||
{
|
||||
struct nic * nic;
|
||||
|
||||
nic = lookup_nic_by_drv_name(label);
|
||||
|
||||
if (nic) {
|
||||
debug_print("LWIP : driver '%s' / %d is up for /dev/%s\n",
|
||||
label, ep, nic->name);
|
||||
nic->drv_ep = ep;
|
||||
} else {
|
||||
printf("LWIP : WARNING unexpected driver '%s' up event\n",
|
||||
label);
|
||||
return;
|
||||
}
|
||||
|
||||
nic->state = DRV_IDLE;
|
||||
|
||||
/*
|
||||
* FIXME
|
||||
*
|
||||
* We set the initial ip to 0.0.0.0 to make dhcpd broadcasing work
|
||||
* at the very begining. dhcp should use raw socket but it is a little
|
||||
* tricy in the current dhcp implementation
|
||||
*/
|
||||
if (!netif_add(&nic->netif, (ip_addr_t *) __UNCONST( &ip_addr_any),
|
||||
&ip_addr_none, &ip_addr_none, nic, ethernetif_init, ethernet_input)) {
|
||||
printf("LWIP : failed to add device /dev/%s\n", nic->name);
|
||||
nic->drv_ep = NONE;
|
||||
}
|
||||
if (nic->is_default)
|
||||
netif_set_default(&nic->netif);
|
||||
|
||||
/* FIXME we support ethernet only, 2048 is safe */
|
||||
nic->tx_buffer = debug_malloc(2048);
|
||||
if (nic->tx_buffer == NULL)
|
||||
panic("Cannot allocate tx_buffer");
|
||||
/* When driver restarts, the rx_pbuf is likely ready to receive data
|
||||
* from its previous instance. We free the buffer here, nobody depends
|
||||
* on it. A new one is allocated when we send a new read request to the
|
||||
* driver.
|
||||
*/
|
||||
if (nic->rx_pbuf) {
|
||||
pbuf_free(nic->rx_pbuf);
|
||||
nic->rx_pbuf = NULL;
|
||||
}
|
||||
|
||||
/* prepare the RX grant once and forever */
|
||||
if (cpf_setgrant_direct(nic->rx_iogrant,
|
||||
nic->drv_ep,
|
||||
(vir_bytes) &nic->rx_iovec,
|
||||
1 * sizeof(iovec_s_t), CPF_READ) != OK)
|
||||
panic("Failed to set grant");
|
||||
}
|
||||
|
||||
static void raw_recv_free(__unused void * data)
|
||||
{
|
||||
pbuf_free((struct pbuf *) data);
|
||||
}
|
||||
|
||||
static int nic_op_close(struct socket * sock)
|
||||
{
|
||||
struct nic * nic = (struct nic *)sock->data;
|
||||
|
||||
debug_drv_print("socket %ld", get_sock_num(sock));
|
||||
|
||||
sock_dequeue_data_all(sock, raw_recv_free);
|
||||
sock->ops = NULL;
|
||||
|
||||
if (nic->raw_socket == sock) {
|
||||
nic->raw_socket = NULL;
|
||||
debug_drv_print("no active raw sock at %s", nic->name);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int nic_ioctl_set_conf(__unused struct socket * sock,
|
||||
struct nic * nic,
|
||||
endpoint_t endpt,
|
||||
cp_grant_id_t grant)
|
||||
{
|
||||
nwio_ipconf_t ipconf;
|
||||
int err;
|
||||
|
||||
err = copy_from_user(endpt, &ipconf, sizeof(ipconf), grant, 0);
|
||||
if (err != OK)
|
||||
return err;
|
||||
|
||||
if (ipconf.nwic_flags & NWIC_IPADDR_SET)
|
||||
netif_set_ipaddr(&nic->netif,
|
||||
(ip_addr_t *)&ipconf.nwic_ipaddr);
|
||||
if (ipconf.nwic_flags & NWIC_NETMASK_SET)
|
||||
netif_set_netmask(&nic->netif,
|
||||
(ip_addr_t *)&ipconf.nwic_netmask);
|
||||
nic->flags = ipconf.nwic_flags;
|
||||
if (nic->flags & NWEO_EN_BROAD)
|
||||
nic->netif.flags |= NETIF_FLAG_BROADCAST;
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int nic_ioctl_get_conf(__unused struct socket * sock,
|
||||
struct nic * nic,
|
||||
endpoint_t endpt,
|
||||
cp_grant_id_t grant)
|
||||
{
|
||||
nwio_ipconf_t ipconf;
|
||||
|
||||
ipconf.nwic_flags = nic->flags;
|
||||
ipconf.nwic_ipaddr = nic->netif.ip_addr.addr;
|
||||
ipconf.nwic_netmask = nic->netif.netmask.addr;
|
||||
ipconf.nwic_mtu = nic->netif.mtu;
|
||||
|
||||
return copy_to_user(endpt, &ipconf, sizeof(ipconf), grant, 0);
|
||||
}
|
||||
|
||||
static int nic_ioctl_set_gateway(__unused struct socket * sock,
|
||||
struct nic * nic,
|
||||
endpoint_t endpt,
|
||||
cp_grant_id_t grant)
|
||||
{
|
||||
nwio_route_t route;
|
||||
int err;
|
||||
|
||||
err = copy_from_user(endpt, &route, sizeof(route), grant, 0);
|
||||
if (err != OK)
|
||||
return err;
|
||||
|
||||
netif_set_gw(&nic->netif, (ip_addr_t *)&route.nwr_gateway);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int nic_ioctl_get_ethstat(__unused struct socket * sock,
|
||||
struct nic * nic,
|
||||
endpoint_t endpt,
|
||||
cp_grant_id_t grant)
|
||||
{
|
||||
nwio_ethstat_t ethstat;
|
||||
|
||||
debug_drv_print("device /dev/%s", nic->name);
|
||||
/*
|
||||
* The device is not up yet, there is nothing to report or it is not
|
||||
* an ethernet device
|
||||
*/
|
||||
if (!nic->netif.flags & NETIF_FLAG_UP ||
|
||||
!(nic->netif.flags & (NETIF_FLAG_ETHERNET |
|
||||
NETIF_FLAG_ETHARP))) {
|
||||
printf("LWIP no such device FUCK\n");
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
memset(ðstat, 0, sizeof(ethstat));
|
||||
memcpy(ðstat.nwes_addr, nic->netif.hwaddr, 6);
|
||||
|
||||
return copy_to_user(endpt, ðstat, sizeof(ethstat), grant, 0);
|
||||
}
|
||||
|
||||
static int nic_ioctl_set_ethopt(struct socket * sock,
|
||||
struct nic * nic,
|
||||
endpoint_t endpt,
|
||||
cp_grant_id_t grant)
|
||||
{
|
||||
int err;
|
||||
nwio_ethopt_t ethopt;
|
||||
|
||||
assert(nic);
|
||||
|
||||
if (!sock)
|
||||
return EINVAL;
|
||||
|
||||
debug_drv_print("device /dev/%s", nic->name);
|
||||
/*
|
||||
* The device is not up yet, there is nothing to report or it is not
|
||||
* an ethernet device
|
||||
*/
|
||||
if (!nic->netif.flags & NETIF_FLAG_UP ||
|
||||
!(nic->netif.flags & (NETIF_FLAG_ETHERNET |
|
||||
NETIF_FLAG_ETHARP))) {
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
err = copy_from_user(endpt, ðopt, sizeof(ethopt), grant, 0);
|
||||
if (err != OK)
|
||||
return err;
|
||||
|
||||
/* we want to get data from this sock */
|
||||
if (ethopt.nweo_flags & NWEO_COPY) {
|
||||
if (nic->raw_socket)
|
||||
return EBUSY;
|
||||
|
||||
nic->raw_socket = sock;
|
||||
debug_drv_print("active raw sock %ld at %s",
|
||||
get_sock_num(sock), nic->name);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int nic_do_ioctl(struct socket * sock, struct nic * nic,
|
||||
struct sock_req * req)
|
||||
{
|
||||
int r;
|
||||
|
||||
debug_print("device /dev/%s req %c %ld %ld",
|
||||
nic->name,
|
||||
(unsigned char) (req->req >> 8),
|
||||
req->req & 0xff, _MINIX_IOCTL_SIZE(req->req));
|
||||
|
||||
debug_drv_print("socket %ld", sock ? get_sock_num(sock) : -1);
|
||||
|
||||
switch (req->req) {
|
||||
case NWIOSIPCONF:
|
||||
r = nic_ioctl_set_conf(sock, nic, req->endpt, req->grant);
|
||||
break;
|
||||
case NWIOGIPCONF:
|
||||
r = nic_ioctl_get_conf(sock, nic, req->endpt, req->grant);
|
||||
break;
|
||||
case NWIOSIPOROUTE:
|
||||
r = nic_ioctl_set_gateway(sock, nic, req->endpt, req->grant);
|
||||
break;
|
||||
case NWIOGETHSTAT:
|
||||
r = nic_ioctl_get_ethstat(sock, nic, req->endpt, req->grant);
|
||||
break;
|
||||
case NWIOSETHOPT:
|
||||
r = nic_ioctl_set_ethopt(sock, nic, req->endpt, req->grant);
|
||||
break;
|
||||
default:
|
||||
r = ENOTTY;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int nic_default_ioctl(struct sock_req *req)
|
||||
{
|
||||
struct nic * nic = lookup_nic_default();
|
||||
|
||||
if (nic == NULL) {
|
||||
debug_print("No default nic, reporting error");
|
||||
return ENOTTY;
|
||||
}
|
||||
|
||||
return nic_do_ioctl(NULL, nic, req);
|
||||
}
|
||||
|
||||
static int nic_op_ioctl(struct socket * sock, struct sock_req * req,
|
||||
__unused int blk)
|
||||
{
|
||||
return nic_do_ioctl(sock, (struct nic *)sock->data, req);
|
||||
}
|
||||
|
||||
static int nic_op_read(struct socket * sock, struct sock_req * req, int blk)
|
||||
{
|
||||
debug_drv_print("sock num %ld", get_sock_num(sock));
|
||||
|
||||
if (sock->recv_head) {
|
||||
/* data available receive immeditely */
|
||||
|
||||
struct pbuf * pbuf;
|
||||
int ret;
|
||||
|
||||
pbuf = sock->recv_head->data;
|
||||
|
||||
ret = raw_receive(req, pbuf);
|
||||
|
||||
if (ret > 0) {
|
||||
sock_dequeue_data(sock);
|
||||
sock->recv_data_size -= pbuf->tot_len;
|
||||
pbuf_free(pbuf);
|
||||
}
|
||||
return ret;
|
||||
} else if (!blk)
|
||||
return EAGAIN;
|
||||
else {
|
||||
/* store the request so we know how to reply */
|
||||
sock->req = *req;
|
||||
/* operation is being processes */
|
||||
sock->flags |= SOCK_FLG_OP_PENDING;
|
||||
|
||||
debug_print("no data to read, suspending");
|
||||
return EDONTREPLY;
|
||||
}
|
||||
}
|
||||
|
||||
static int nic_op_write(struct socket * sock, struct sock_req * req,
|
||||
__unused int blk)
|
||||
{
|
||||
int ret;
|
||||
struct pbuf * pbuf;
|
||||
struct nic * nic = (struct nic *)sock->data;
|
||||
|
||||
assert(nic);
|
||||
debug_print("device %s data size %u", nic->name, req->size);
|
||||
|
||||
pbuf = pbuf_alloc(PBUF_RAW, req->size, PBUF_RAM);
|
||||
if (!pbuf)
|
||||
return ENOMEM;
|
||||
|
||||
if ((ret = copy_from_user(req->endpt, pbuf->payload, req->size,
|
||||
req->grant, 0)) != OK) {
|
||||
pbuf_free(pbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = nic->netif.linkoutput(&nic->netif, pbuf)) != ERR_OK) {
|
||||
debug_print("raw linkoutput failed %d", ret);
|
||||
ret = EIO;
|
||||
} else
|
||||
ret = req->size;
|
||||
|
||||
pbuf_free(pbuf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct sock_ops nic_ops = {
|
||||
.write = nic_op_write,
|
||||
.read = nic_op_read,
|
||||
.close = nic_op_close,
|
||||
.ioctl = nic_op_ioctl,
|
||||
.select = generic_op_select,
|
||||
.select_reply = generic_op_select_reply
|
||||
};
|
||||
|
||||
int nic_open(devminor_t minor)
|
||||
{
|
||||
struct socket * sock;
|
||||
|
||||
debug_print("device %d", minor);
|
||||
|
||||
if (minor > MAX_DEVS || devices[minor].drv_ep == NONE)
|
||||
return ENODEV;
|
||||
|
||||
sock = get_unused_sock();
|
||||
|
||||
if (sock == NULL)
|
||||
return ENODEV;
|
||||
if (sock->ops != NULL)
|
||||
return EBUSY;
|
||||
|
||||
sock->ops = &nic_ops;
|
||||
sock->select_ep = NONE;
|
||||
sock->recv_data_size = 0;
|
||||
sock->data = &devices[minor];
|
||||
|
||||
return get_sock_num(sock);
|
||||
}
|
||||
|
||||
static int driver_pkt_enqueue(struct packet_q ** head,
|
||||
struct packet_q ** tail,
|
||||
struct pbuf * pbuf)
|
||||
{
|
||||
struct packet_q * pkt;
|
||||
char * b;
|
||||
|
||||
pkt = (struct packet_q *) malloc(sizeof(struct packet_q) + pbuf->tot_len);
|
||||
if (!pkt)
|
||||
return ENOMEM;
|
||||
|
||||
pkt->next = NULL;
|
||||
pkt->buf_len = pbuf->tot_len;
|
||||
|
||||
for (b = pkt->buf; pbuf; pbuf = pbuf->next) {
|
||||
memcpy(b, pbuf->payload, pbuf->len);
|
||||
b += pbuf->len;
|
||||
}
|
||||
|
||||
if (*head == NULL)
|
||||
*head = *tail = pkt;
|
||||
else {
|
||||
(*tail)->next = pkt;
|
||||
*tail = pkt;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int driver_tx_enqueue(struct nic * nic, struct pbuf * pbuf)
|
||||
{
|
||||
debug_print("device /dev/%s", nic->name);
|
||||
return driver_pkt_enqueue(&nic->tx_head, &nic->tx_tail, pbuf);
|
||||
}
|
||||
|
||||
static void driver_pkt_dequeue(struct packet_q ** head,
|
||||
struct packet_q ** tail)
|
||||
{
|
||||
struct packet_q * pkt;
|
||||
|
||||
/* we always dequeue only if there is something to dequeue */
|
||||
assert(*head);
|
||||
|
||||
pkt = *head;
|
||||
|
||||
if ((*head = pkt->next) == NULL)
|
||||
*tail = NULL;
|
||||
|
||||
debug_free(pkt);
|
||||
}
|
||||
|
||||
void driver_tx_dequeue(struct nic * nic)
|
||||
{
|
||||
debug_print("device /dev/%s", nic->name);
|
||||
driver_pkt_dequeue(&nic->tx_head, &nic->tx_tail);
|
||||
}
|
||||
|
||||
struct packet_q * driver_tx_head(struct nic * nic)
|
||||
{
|
||||
debug_print("device /dev/%s", nic->name);
|
||||
|
||||
if (!nic->tx_head)
|
||||
return NULL;
|
||||
return nic->tx_head;
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
#ifndef __LWIP_DRIVER_H_
|
||||
#define __LWIP_DRIVER_H_
|
||||
|
||||
#include <minix/endpoint.h>
|
||||
#include <minix/ds.h>
|
||||
|
||||
#include <lwip/pbuf.h>
|
||||
|
||||
#define NIC_NAME_LEN 6
|
||||
#define DRV_NAME_LEN DS_MAX_KEYLEN
|
||||
|
||||
#define TX_IOVEC_NUM 16 /* something the drivers assume */
|
||||
|
||||
struct packet_q {
|
||||
struct packet_q * next;
|
||||
unsigned int buf_len;
|
||||
char buf[];
|
||||
};
|
||||
|
||||
#define DRV_IDLE 0
|
||||
#define DRV_SENDING 1
|
||||
#define DRV_RECEIVING 2
|
||||
|
||||
struct nic {
|
||||
unsigned int flags;
|
||||
char name[NIC_NAME_LEN];
|
||||
char drv_name[DRV_NAME_LEN];
|
||||
endpoint_t drv_ep;
|
||||
int is_default;
|
||||
int state;
|
||||
cp_grant_id_t rx_iogrant;
|
||||
iovec_s_t rx_iovec[1];
|
||||
struct pbuf * rx_pbuf;
|
||||
cp_grant_id_t tx_iogrant;
|
||||
iovec_s_t tx_iovec[TX_IOVEC_NUM];
|
||||
struct packet_q * tx_head;
|
||||
struct packet_q * tx_tail;
|
||||
void * tx_buffer;
|
||||
struct netif netif;
|
||||
unsigned int max_pkt_sz;
|
||||
unsigned int min_pkt_sz;
|
||||
struct socket * raw_socket;
|
||||
};
|
||||
|
||||
int driver_tx_enqueue(struct nic * nic, struct pbuf * pbuf);
|
||||
void driver_tx_dequeue(struct nic * nic);
|
||||
struct packet_q * driver_tx_head(struct nic * nic);
|
||||
|
||||
/*
|
||||
* Transmit the next packet in the TX queue of this device. Returns 1 if
|
||||
* success, 0 otherwise.
|
||||
*/
|
||||
int driver_tx(struct nic * nic);
|
||||
int raw_socket_input(struct pbuf * pbuf, struct nic * nic);
|
||||
|
||||
#endif /* __LWIP_DRIVER_H_ */
|
@ -1,135 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* Ethernet Interface Skeleton
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 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>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is a skeleton for developing Ethernet network interface
|
||||
* drivers for lwIP. Add code to the low_level functions and do a
|
||||
* search-and-replace for the word "ethernetif" to replace it with
|
||||
* something that better describes your network interface.
|
||||
*/
|
||||
|
||||
#include <minix/sysutil.h>
|
||||
#include <minix/netsock.h>
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
#include <lwip/stats.h>
|
||||
#include <lwip/snmp.h>
|
||||
#include <netif/etharp.h>
|
||||
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
|
||||
#include "proto.h"
|
||||
#include "driver.h"
|
||||
|
||||
static err_t low_level_output(__unused struct netif *netif, struct pbuf *pbuf)
|
||||
{
|
||||
struct nic * nic;
|
||||
|
||||
nic = (struct nic *) netif->state;
|
||||
assert(&nic->netif == netif);
|
||||
|
||||
debug_print("device /dev/%s", nic->name);
|
||||
|
||||
if (driver_tx_enqueue(nic, pbuf) != OK)
|
||||
return ERR_MEM;
|
||||
|
||||
/* if the driver is idle, start transmitting the packet */
|
||||
if (nic->state == DRV_IDLE) {
|
||||
if (!driver_tx(nic))
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void low_level_init(struct netif *netif)
|
||||
{
|
||||
message m;
|
||||
struct nic * nic = (struct nic *) netif->state;
|
||||
|
||||
assert(nic);
|
||||
|
||||
/* set MAC hardware address length */
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = 1500;
|
||||
nic->max_pkt_sz = ETH_MAX_PACK_SIZE;
|
||||
nic->min_pkt_sz = ETH_MIN_PACK_SIZE;
|
||||
|
||||
/* device capabilities */
|
||||
netif->flags = NETIF_FLAG_ETHARP;
|
||||
|
||||
m.m_net_netdrv_dl_conf.mode = DL_NOMODE;
|
||||
if (nic->flags & NWEO_EN_BROAD)
|
||||
m.m_net_netdrv_dl_conf.mode |= DL_BROAD_REQ;
|
||||
if (nic->flags & NWEO_EN_MULTI)
|
||||
m.m_net_netdrv_dl_conf.mode |= DL_MULTI_REQ;
|
||||
if (nic->flags & NWEO_EN_PROMISC)
|
||||
m.m_net_netdrv_dl_conf.mode |= DL_PROMISC_REQ;
|
||||
|
||||
m.m_type = DL_CONF;
|
||||
|
||||
if (asynsend(((struct nic *)netif->state)->drv_ep , &m) != OK)
|
||||
printf("LWIP : ERROR cannot send DL_CONF to driver\n");
|
||||
}
|
||||
|
||||
|
||||
err_t ethernetif_init(struct netif *netif)
|
||||
{
|
||||
/*
|
||||
* Initialize the snmp variables and counters inside the struct netif.
|
||||
* The last argument should be replaced with your link speed, in units
|
||||
* of bits per second.
|
||||
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
|
||||
*/
|
||||
|
||||
netif->output = etharp_output;
|
||||
netif->linkoutput = low_level_output;
|
||||
|
||||
/* initialize the hardware */
|
||||
low_level_init(netif);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
@ -1,271 +0,0 @@
|
||||
/*
|
||||
inet/inet_config.c
|
||||
|
||||
Created: Nov 11, 1992 by Philip Homburg
|
||||
|
||||
Modified: Apr 07, 2001 by Kees J. Bot
|
||||
Read the configuration file and fill in the xx_conf[] arrays.
|
||||
|
||||
Copyright 1995 Philip Homburg
|
||||
*/
|
||||
|
||||
#define _POSIX_SOURCE 1
|
||||
#define _NETBSD_SOURCE 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include <minix/syslib.h>
|
||||
#include <minix/netsock.h>
|
||||
#include "inet_config.h"
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
struct eth_conf eth_conf[IP_PORT_MAX];
|
||||
struct psip_conf psip_conf[IP_PORT_MAX];
|
||||
struct ip_conf ip_conf[IP_PORT_MAX];
|
||||
struct tcp_conf tcp_conf[IP_PORT_MAX];
|
||||
struct udp_conf udp_conf[IP_PORT_MAX];
|
||||
dev_t ip_dev;
|
||||
|
||||
int eth_conf_nr;
|
||||
int psip_conf_nr;
|
||||
int ip_conf_nr;
|
||||
int tcp_conf_nr;
|
||||
int udp_conf_nr;
|
||||
|
||||
int ip_forward_directed_bcast= 0; /* Default is off */
|
||||
|
||||
static int ifdefault= -1; /* Default network interface. */
|
||||
|
||||
__dead
|
||||
static void fatal(const char *label)
|
||||
{
|
||||
printf("init: %s: %s\n", label, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void check_mknod(const char *device, mode_t mode, int minor)
|
||||
/* Check if a device exists with the proper device number. */
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
dev= makedev(major(ip_dev), minor);
|
||||
|
||||
unlink(device);
|
||||
if (mknod(device, S_IFCHR | mode, dev) < 0) fatal(device);
|
||||
printf("mknod %s c %d %d\n", device, major(ip_dev), minor);
|
||||
}
|
||||
|
||||
static int cfg_fd;
|
||||
static char word[16];
|
||||
static unsigned char line[256], *lineptr;
|
||||
static unsigned int linenr;
|
||||
|
||||
static __dead void error(void)
|
||||
{
|
||||
printf("inet: error on line %u\n", linenr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int nextline(void)
|
||||
{
|
||||
/* Read a line from the configuration file, to be used by subsequent
|
||||
* token() calls. Skip empty lines, and lines where the first character
|
||||
* after leading "whitespace" is '#'. The last line of the file need
|
||||
* not be terminated by a newline. Return 1 if a line was read in
|
||||
* successfully, and 0 on EOF or error.
|
||||
*/
|
||||
unsigned char *lp, c;
|
||||
int r, skip;
|
||||
|
||||
lineptr = lp = line;
|
||||
linenr++;
|
||||
skip = -1;
|
||||
|
||||
while ((r = read(cfg_fd, &c, 1)) == 1) {
|
||||
if (c == '\n') {
|
||||
if (skip == 0)
|
||||
break;
|
||||
|
||||
linenr++;
|
||||
skip = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (skip == -1 && c > ' ')
|
||||
skip = (c == '#');
|
||||
|
||||
if (skip == 0 && lp < (unsigned char *) line + sizeof(line)-1)
|
||||
*lp++ = c;
|
||||
}
|
||||
|
||||
*lp = 0;
|
||||
return (r == 1 || lp != line);
|
||||
}
|
||||
|
||||
static void token(int need)
|
||||
{
|
||||
/* Read a word from the configuration line. Return a null string on
|
||||
* EOL. Return a punctuation as a one character word. If 'need' is
|
||||
* true then an actual word is expected at this point, so err out if
|
||||
* not.
|
||||
*/
|
||||
unsigned char *wp;
|
||||
static unsigned char c= '\n';
|
||||
|
||||
wp= (unsigned char *) word;
|
||||
*wp = 0;
|
||||
|
||||
while (c <= ' ') {
|
||||
if (*lineptr == 0) {
|
||||
if (need) error();
|
||||
return;
|
||||
}
|
||||
c = *lineptr++;
|
||||
}
|
||||
|
||||
do {
|
||||
if (wp < (unsigned char *) word + sizeof(word)-1) *wp++ = c;
|
||||
c = (*lineptr != 0) ? *lineptr++ : ' ';
|
||||
if (word[0] == ';' || word[0] == '{' || word[0] == '}') {
|
||||
if (need) error();
|
||||
break;
|
||||
}
|
||||
} while (c > ' ' && c != ';' && c != '{' && c != '}');
|
||||
*wp = 0;
|
||||
}
|
||||
|
||||
void inet_read_conf(void)
|
||||
{
|
||||
int ifno, enable;
|
||||
struct stat st;
|
||||
|
||||
{ static int first= 1;
|
||||
if (!first)
|
||||
panic(( "LWIP : read_conf: called a second time" ));
|
||||
first= 0;
|
||||
#if 0
|
||||
*(u8_t *)0 = 0xcc; /* INT 3 */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Open the configuration file. */
|
||||
if ((cfg_fd= open(PATH_INET_CONF, O_RDONLY)) == -1)
|
||||
fatal(PATH_INET_CONF);
|
||||
|
||||
while (nextline()) {
|
||||
token(1);
|
||||
char drv_name[128];
|
||||
unsigned int instance;
|
||||
|
||||
if (strncmp(word, "eth", 3) == 0) {
|
||||
|
||||
ifno = strtol(word+3, NULL, 10);
|
||||
token(1);
|
||||
#if 1
|
||||
strncpy(drv_name, word, 128);
|
||||
#else
|
||||
sprintf(drv_name, "%s_debug", word);
|
||||
#endif
|
||||
token(1);
|
||||
instance = strtol(word, NULL, 10);
|
||||
} else {
|
||||
printf("inet: Unknown device '%s'\n", word);
|
||||
error();
|
||||
}
|
||||
|
||||
enable= 7; /* 1 = IP, 2 = TCP, 4 = UDP */
|
||||
|
||||
token(0);
|
||||
if (word[0] == '{') {
|
||||
token(0);
|
||||
while (word[0] != '}') {
|
||||
if (strcmp(word, "default") == 0) {
|
||||
if (ifdefault != -1) {
|
||||
printf(
|
||||
"inet: ip%d and ip%d can't both be default\n",
|
||||
ifdefault, ifno);
|
||||
error();
|
||||
}
|
||||
ifdefault= ifno;
|
||||
token(0);
|
||||
} else
|
||||
if (strcmp(word, "no") == 0) {
|
||||
token(1);
|
||||
if (strcmp(word, "ip") == 0) {
|
||||
enable= 0;
|
||||
} else
|
||||
if (strcmp(word, "tcp") == 0) {
|
||||
enable &= ~2;
|
||||
} else
|
||||
if (strcmp(word, "udp") == 0) {
|
||||
enable &= ~4;
|
||||
} else {
|
||||
printf(
|
||||
"inet: Can't do 'no %s'\n",
|
||||
word);
|
||||
exit(1);
|
||||
}
|
||||
token(0);
|
||||
} else {
|
||||
printf("inet: Unknown option '%s'\n",
|
||||
word);
|
||||
exit(1);
|
||||
}
|
||||
if (word[0] == ';') token(0);
|
||||
else
|
||||
if (word[0] != '}') error();
|
||||
}
|
||||
token(0);
|
||||
}
|
||||
if (word[0] != ';' && word[0] != 0) error();
|
||||
|
||||
nic_assign_driver("eth", ifno, drv_name, instance, ifdefault == ifno);
|
||||
}
|
||||
|
||||
if (ifdefault == -1) {
|
||||
printf("inet: No networks or no default network defined\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Set umask 0 so we can creat mode 666 devices. */
|
||||
(void) umask(0);
|
||||
|
||||
/* See what the device number of /dev/ip is. That's what we
|
||||
* used last time for the network devices, so we keep doing so.
|
||||
*/
|
||||
if (stat("/dev/ip", &st) < 0) fatal("/dev/ip");
|
||||
ip_dev= st.st_rdev;
|
||||
|
||||
/* create protocol devices */
|
||||
check_mknod("/dev/ip", 0600, SOCK_TYPE_IP);
|
||||
check_mknod("/dev/tcp", 0666, SOCK_TYPE_TCP);
|
||||
check_mknod("/dev/udp", 0666, SOCK_TYPE_UDP);
|
||||
|
||||
/*
|
||||
* create hw devices, to configure ip we need also ip devices for each
|
||||
*/
|
||||
check_mknod("/dev/ip0", 0600, SOCK_TYPES + 0);
|
||||
check_mknod("/dev/eth0", 0600, SOCK_TYPES + 0);
|
||||
|
||||
check_mknod("/dev/ip1", 0600, SOCK_TYPES + 1);
|
||||
check_mknod("/dev/eth1", 0600, SOCK_TYPES + 1);
|
||||
|
||||
check_mknod("/dev/ip2", 0600, SOCK_TYPES + 2);
|
||||
check_mknod("/dev/eth2", 0600, SOCK_TYPES + 2);
|
||||
|
||||
check_mknod("/dev/ip3", 0600, SOCK_TYPES + 3);
|
||||
check_mknod("/dev/eth3", 0600, SOCK_TYPES + 3);
|
||||
|
||||
check_mknod("/dev/ip4", 0600, SOCK_TYPES + 4);
|
||||
check_mknod("/dev/eth4", 0600, SOCK_TYPES + 4);
|
||||
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
/*
|
||||
inet/inet_config.h
|
||||
|
||||
Created: Nov 11, 1992 by Philip Homburg
|
||||
|
||||
Defines values for configurable parameters. The structure definitions for
|
||||
configuration information are also here.
|
||||
|
||||
Copyright 1995 Philip Homburg
|
||||
*/
|
||||
|
||||
#ifndef INET__INET_CONFIG_H
|
||||
#define INET__INET_CONFIG_H
|
||||
|
||||
/* Inet configuration file. */
|
||||
#define PATH_INET_CONF "/etc/inet.conf"
|
||||
|
||||
#define IP_PORT_MAX 32 /* Up to this many network devices */
|
||||
extern int eth_conf_nr; /* Number of ethernets */
|
||||
extern int psip_conf_nr; /* Number of Pseudo IP networks */
|
||||
extern int ip_conf_nr; /* Number of configured IP layers */
|
||||
extern int tcp_conf_nr; /* Number of configured TCP layers */
|
||||
extern int udp_conf_nr; /* Number of configured UDP layers */
|
||||
|
||||
extern dev_t ip_dev; /* Device number of /dev/ip */
|
||||
|
||||
struct eth_conf
|
||||
{
|
||||
char *ec_label; /* Process label name if nonnull */
|
||||
u8_t ec_port; /* Ethernet port for VLAN if label == NULL */
|
||||
u8_t ec_ifno; /* Interface number of /dev/eth* */
|
||||
u16_t ec_vlan; /* VLAN number of this net if label == NULL */
|
||||
};
|
||||
#define eth_is_vlan(ecp) ((ecp)->ec_label == NULL)
|
||||
|
||||
struct psip_conf
|
||||
{
|
||||
u8_t pc_ifno; /* Interface number of /dev/psip* */
|
||||
};
|
||||
|
||||
struct ip_conf
|
||||
{
|
||||
u8_t ic_devtype; /* Underlying device type: Ethernet / PSIP */
|
||||
u8_t ic_port; /* Port of underlying device */
|
||||
u8_t ic_ifno; /* Interface number of /dev/ip*, tcp*, udp* */
|
||||
};
|
||||
|
||||
struct tcp_conf
|
||||
{
|
||||
u8_t tc_port; /* IP port number */
|
||||
};
|
||||
|
||||
struct udp_conf
|
||||
{
|
||||
u8_t uc_port; /* IP port number */
|
||||
};
|
||||
|
||||
/* Types of networks. */
|
||||
#define NETTYPE_ETH 1
|
||||
#define NETTYPE_PSIP 2
|
||||
|
||||
/* To compute the minor device number for a device on an interface. */
|
||||
#define if2minor(ifno, dev) (1 + (ifno) * 8 + (dev))
|
||||
|
||||
#define IPSTAT_DEV "/dev/ipstat"
|
||||
#define IPSTAT_MODE 0666 /* Is this right? What about just setuid apps */
|
||||
#define IPSTAT_MINOR 0 /* Minor number of /dev/ipstat */
|
||||
|
||||
/* Offsets of the minor device numbers within a group per interface. */
|
||||
#define ETH_DEV_OFF 0
|
||||
#define PSIP_DEV_OFF 0
|
||||
#define IP_DEV_OFF 1
|
||||
#define TCP_DEV_OFF 2
|
||||
#define UDP_DEV_OFF 3
|
||||
|
||||
extern struct eth_conf eth_conf[IP_PORT_MAX];
|
||||
extern struct psip_conf psip_conf[IP_PORT_MAX];
|
||||
extern struct ip_conf ip_conf[IP_PORT_MAX];
|
||||
extern struct tcp_conf tcp_conf[IP_PORT_MAX];
|
||||
extern struct udp_conf udp_conf[IP_PORT_MAX];
|
||||
void read_conf(void);
|
||||
void *alloc(size_t size);
|
||||
|
||||
/* Options */
|
||||
extern int ip_forward_directed_bcast;
|
||||
|
||||
#endif /* INET__INET_CONFIG_H */
|
||||
|
||||
/*
|
||||
* $PchId: inet_config.h,v 1.10 2003/08/21 09:24:33 philip Exp $
|
||||
*/
|
@ -1,291 +0,0 @@
|
||||
#include <unistd.h>
|
||||
#include <minix/timers.h>
|
||||
#include <minix/ds.h>
|
||||
#include <minix/endpoint.h>
|
||||
#include <errno.h>
|
||||
#include <minix/sef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <minix/chardriver.h>
|
||||
#include <minix/syslib.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include <minix/timers.h>
|
||||
#include <minix/netsock.h>
|
||||
#include <minix/rmib.h>
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#include <lwip/mem.h>
|
||||
#include <lwip/pbuf.h>
|
||||
#include <lwip/stats.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <netif/etharp.h>
|
||||
#include <lwip/tcp_impl.h>
|
||||
|
||||
static minix_timer_t tcp_ftmr, tcp_stmr, arp_tmr;
|
||||
static int arp_ticks, tcp_fticks, tcp_sticks;
|
||||
|
||||
static struct netif * netif_lo;
|
||||
|
||||
extern struct sock_ops sock_udp_ops;
|
||||
extern struct sock_ops sock_tcp_ops;
|
||||
extern struct sock_ops sock_raw_ip_ops;
|
||||
|
||||
static void sys_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void arp_watchdog(int arg __unused)
|
||||
{
|
||||
etharp_tmr();
|
||||
set_timer(&arp_tmr, arp_ticks, arp_watchdog, 0);
|
||||
}
|
||||
|
||||
static void tcp_fwatchdog(int arg __unused)
|
||||
{
|
||||
tcp_fasttmr();
|
||||
set_timer(&tcp_ftmr, tcp_fticks, tcp_fwatchdog, 0);
|
||||
}
|
||||
|
||||
static void tcp_swatchdog(int arg __unused)
|
||||
{
|
||||
tcp_slowtmr();
|
||||
set_timer(&tcp_ftmr, tcp_sticks, tcp_swatchdog, 0);
|
||||
}
|
||||
|
||||
static int sef_cb_init_fresh(__unused int type, __unused sef_init_info_t *info)
|
||||
{
|
||||
int err;
|
||||
unsigned int hz;
|
||||
|
||||
nic_init_all();
|
||||
inet_read_conf();
|
||||
|
||||
/* init lwip library */
|
||||
stats_init();
|
||||
sys_init();
|
||||
mem_init();
|
||||
memp_init();
|
||||
pbuf_init();
|
||||
|
||||
hz = sys_hz();
|
||||
|
||||
arp_ticks = ARP_TMR_INTERVAL / (1000 / hz);
|
||||
tcp_fticks = TCP_FAST_INTERVAL / (1000 / hz);
|
||||
tcp_sticks = TCP_SLOW_INTERVAL / (1000 / hz);
|
||||
|
||||
etharp_init();
|
||||
|
||||
set_timer(&arp_tmr, arp_ticks, arp_watchdog, 0);
|
||||
set_timer(&tcp_ftmr, tcp_fticks, tcp_fwatchdog, 0);
|
||||
set_timer(&tcp_stmr, tcp_sticks, tcp_swatchdog, 0);
|
||||
|
||||
netif_init();
|
||||
netif_lo = netif_find(__UNCONST("lo0"));
|
||||
|
||||
/* Read configuration. */
|
||||
#if 0
|
||||
nw_conf();
|
||||
|
||||
/* Get a random number */
|
||||
timerand= 1;
|
||||
fd = open(RANDOM_DEV_NAME, O_RDONLY | O_NONBLOCK);
|
||||
if (fd != -1)
|
||||
{
|
||||
err= read(fd, randbits, sizeof(randbits));
|
||||
if (err == sizeof(randbits))
|
||||
timerand= 0;
|
||||
else
|
||||
{
|
||||
printf("inet: unable to read random data from %s: %s\n",
|
||||
RANDOM_DEV_NAME, err == -1 ? strerror(errno) :
|
||||
err == 0 ? "EOF" : "not enough data");
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("inet: unable to open random device %s: %s\n",
|
||||
RANDOM_DEV_NAME, strerror(errno));
|
||||
}
|
||||
if (timerand)
|
||||
{
|
||||
printf("inet: using current time for random-number seed\n");
|
||||
err= gettimeofday(&tv, NULL);
|
||||
if (err == -1)
|
||||
{
|
||||
printf("sysutime failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
memcpy(randbits, &tv, sizeof(tv));
|
||||
}
|
||||
init_rand256(randbits);
|
||||
#endif
|
||||
|
||||
/* Subscribe to driver events for network drivers. */
|
||||
if ((err = ds_subscribe("drv\\.net\\..*",
|
||||
DSF_INITIAL | DSF_OVERWRITE)) != OK)
|
||||
panic(("inet: can't subscribe to driver events"));
|
||||
|
||||
/* Announce we are up. LWIP announces its presence to VFS just like
|
||||
* any other character driver.
|
||||
*/
|
||||
chardriver_announce();
|
||||
|
||||
/* Register net.route RMIB subtree with the MIB service. */
|
||||
rtinfo_init();
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
static void sef_local_startup(void)
|
||||
{
|
||||
/* Register init callbacks. */
|
||||
sef_setcb_init_fresh(sef_cb_init_fresh);
|
||||
sef_setcb_init_restart(sef_cb_init_fresh);
|
||||
|
||||
/* Let SEF perform startup. */
|
||||
sef_startup();
|
||||
}
|
||||
|
||||
static void ds_event(void)
|
||||
{
|
||||
char key[DS_MAX_KEYLEN];
|
||||
const char *driver_prefix = "drv.net.";
|
||||
char *label;
|
||||
u32_t value;
|
||||
int type;
|
||||
endpoint_t owner_endpoint;
|
||||
int r;
|
||||
int prefix_len;
|
||||
|
||||
prefix_len = strlen(driver_prefix);
|
||||
|
||||
/* We may get one notification for multiple updates from DS. Get events
|
||||
* and owners from DS, until DS tells us that there are no more.
|
||||
*/
|
||||
while ((r = ds_check(key, &type, &owner_endpoint)) == OK) {
|
||||
r = ds_retrieve_u32(key, &value);
|
||||
if(r != OK) {
|
||||
printf("LWIP : ds_event: ds_retrieve_u32 failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only check for network driver up events. */
|
||||
if(strncmp(key, driver_prefix, prefix_len)
|
||||
|| value != DS_DRIVER_UP) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* The driver label comes after the prefix. */
|
||||
label = key + strlen(driver_prefix);
|
||||
|
||||
/* A driver is (re)started. */
|
||||
driver_up(label, owner_endpoint);
|
||||
}
|
||||
|
||||
if(r != ENOENT)
|
||||
printf("LWIP : ds_event: ds_check failed: %d\n", r);
|
||||
}
|
||||
|
||||
static void netif_poll_lo(void)
|
||||
{
|
||||
if (netif_lo == NULL)
|
||||
return;
|
||||
|
||||
while (netif_lo->loop_first)
|
||||
netif_poll(netif_lo);
|
||||
}
|
||||
|
||||
int socket_open(devminor_t minor)
|
||||
{
|
||||
struct sock_ops * ops;
|
||||
struct socket * sock;
|
||||
int ret = OK;
|
||||
|
||||
switch (minor) {
|
||||
case SOCK_TYPE_TCP:
|
||||
ops = &sock_tcp_ops;
|
||||
break;
|
||||
case SOCK_TYPE_UDP:
|
||||
ops = &sock_udp_ops;
|
||||
break;
|
||||
case SOCK_TYPE_IP:
|
||||
ops = &sock_raw_ip_ops;
|
||||
break;
|
||||
default:
|
||||
if (minor - SOCK_TYPES < MAX_DEVS)
|
||||
return nic_open(minor - SOCK_TYPES);
|
||||
|
||||
printf("LWIP unknown socket type %d\n", minor);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
sock = get_unused_sock();
|
||||
if (!sock) {
|
||||
printf("LWIP : no free socket\n");
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
sock->ops = ops;
|
||||
sock->select_ep = NONE;
|
||||
sock->recv_data_size = 0;
|
||||
|
||||
if (sock->ops && sock->ops->open)
|
||||
ret = sock->ops->open(sock);
|
||||
|
||||
if (ret == OK) {
|
||||
debug_print("new socket %ld", get_sock_num(sock));
|
||||
ret = get_sock_num(sock);
|
||||
} else {
|
||||
debug_print("failed %d", ret);
|
||||
/* FIXME: shouldn't sock be freed now? */
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(__unused int argc, __unused char ** argv)
|
||||
{
|
||||
sef_local_startup();
|
||||
|
||||
for(;;) {
|
||||
int err, ipc_status;
|
||||
message m;
|
||||
|
||||
netif_poll_lo();
|
||||
|
||||
mq_process();
|
||||
|
||||
if ((err = sef_receive_status(ANY, &m, &ipc_status)) != OK) {
|
||||
printf("LWIP : sef_receive_status errr %d\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.m_source == VFS_PROC_NR)
|
||||
socket_request(&m, ipc_status);
|
||||
else if (is_ipc_notify(ipc_status)) {
|
||||
switch (m.m_source) {
|
||||
case CLOCK:
|
||||
expire_timers(m.m_notify.timestamp);
|
||||
break;
|
||||
case DS_PROC_NR:
|
||||
ds_event();
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
panic("LWIP : unhandled event from PM");
|
||||
break;
|
||||
default:
|
||||
printf("LWIP : unexpected notify from %d\n",
|
||||
m.m_source);
|
||||
continue;
|
||||
}
|
||||
} else if (m.m_source == MIB_PROC_NR)
|
||||
rmib_process(&m, ipc_status);
|
||||
else
|
||||
/* all other request can be from drivers only */
|
||||
driver_request(&m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
service lwip
|
||||
{
|
||||
uid 0;
|
||||
};
|
||||
|
@ -1,62 +0,0 @@
|
||||
#ifndef __LWIP_PROTO_H__
|
||||
#define __LWIP_PROTO_H__
|
||||
|
||||
#include <errno.h>
|
||||
#include <minix/ipc.h>
|
||||
#include <minix/endpoint.h>
|
||||
#include <minix/syslib.h>
|
||||
#include <minix/safecopies.h>
|
||||
#include <minix/const.h>
|
||||
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/netif.h>
|
||||
|
||||
#if 0
|
||||
#define debug_print(str, ...) printf("LWIP %s:%d : " str "\n", \
|
||||
__func__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define debug_print(...)
|
||||
#endif
|
||||
|
||||
/* driver .c */
|
||||
void nic_assign_driver(const char * dev_type,
|
||||
unsigned int dev_num,
|
||||
const char * driver_name,
|
||||
unsigned int instance,
|
||||
int is_default);
|
||||
struct nic *nic_get(int);
|
||||
void nic_init_all(void);
|
||||
void driver_request(message * m);
|
||||
void driver_up(const char * label, endpoint_t ep);
|
||||
/* opens a raw NIC socket */
|
||||
int nic_open(devminor_t minor);
|
||||
int nic_default_ioctl(struct sock_req *req);
|
||||
|
||||
/* inet_config.c */
|
||||
void inet_read_conf(void);
|
||||
|
||||
/* eth.c */
|
||||
err_t ethernetif_init(struct netif *netif);
|
||||
|
||||
static inline int copy_from_user(endpoint_t proc,
|
||||
void * dst_ptr,
|
||||
size_t size,
|
||||
cp_grant_id_t gid,
|
||||
vir_bytes offset)
|
||||
{
|
||||
return sys_safecopyfrom(proc, gid, offset, (vir_bytes)dst_ptr, size);
|
||||
}
|
||||
|
||||
static inline int copy_to_user(endpoint_t proc,
|
||||
void * src_ptr,
|
||||
size_t size,
|
||||
cp_grant_id_t gid,
|
||||
vir_bytes offset)
|
||||
{
|
||||
return sys_safecopyto(proc, gid, offset, (vir_bytes)src_ptr, size);
|
||||
}
|
||||
|
||||
/* rtinfo.c */
|
||||
void rtinfo_init(void);
|
||||
|
||||
#endif /* __LWIP_PROTO_H__ */
|
@ -1,349 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/ioc_net.h>
|
||||
#include <net/gen/in.h>
|
||||
#include <net/gen/ip_io.h>
|
||||
|
||||
#include <lwip/raw.h>
|
||||
#include <lwip/ip_addr.h>
|
||||
|
||||
#include <minix/netsock.h>
|
||||
#include "proto.h"
|
||||
|
||||
#define RAW_IP_BUF_SIZE (32 << 10)
|
||||
|
||||
#define sock_alloc_buf(s) debug_malloc(s)
|
||||
#define sock_free_buf(x) debug_free(x)
|
||||
|
||||
struct raw_ip_recv_data {
|
||||
ip_addr_t ip;
|
||||
struct pbuf * pbuf;
|
||||
};
|
||||
|
||||
#define raw_ip_recv_alloc() debug_malloc(sizeof(struct raw_ip_recv_data))
|
||||
|
||||
static void raw_ip_recv_free(void * data)
|
||||
{
|
||||
if (((struct raw_ip_recv_data *)data)->pbuf)
|
||||
pbuf_free(((struct raw_ip_recv_data *)data)->pbuf);
|
||||
debug_free(data);
|
||||
}
|
||||
|
||||
|
||||
static int raw_ip_op_open(struct socket * sock)
|
||||
{
|
||||
debug_print("socket num %ld", get_sock_num(sock));
|
||||
|
||||
if (!(sock->buf = sock_alloc_buf(RAW_IP_BUF_SIZE))) {
|
||||
return ENOMEM;
|
||||
}
|
||||
sock->buf_size = RAW_IP_BUF_SIZE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void raw_ip_close(struct socket * sock)
|
||||
{
|
||||
/* deque and free all enqueued data before closing */
|
||||
sock_dequeue_data_all(sock, raw_ip_recv_free);
|
||||
|
||||
if (sock->pcb)
|
||||
raw_remove(sock->pcb);
|
||||
if (sock->buf)
|
||||
sock_free_buf(sock->buf);
|
||||
|
||||
/* mark it as unused */
|
||||
sock->ops = NULL;
|
||||
}
|
||||
|
||||
static int raw_ip_op_close(struct socket * sock)
|
||||
{
|
||||
debug_print("socket num %ld", get_sock_num(sock));
|
||||
|
||||
raw_ip_close(sock);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int raw_ip_do_receive(struct sock_req *req,
|
||||
struct pbuf *pbuf)
|
||||
{
|
||||
struct pbuf * p;
|
||||
size_t rem_len = req->size;
|
||||
unsigned int written = 0, hdr_sz = 0;
|
||||
int err;
|
||||
|
||||
debug_print("user buffer size : %u\n", rem_len);
|
||||
|
||||
for (p = pbuf; p && rem_len; p = p->next) {
|
||||
size_t cp_len;
|
||||
|
||||
cp_len = (rem_len < p->len) ? rem_len : p->len;
|
||||
err = copy_to_user(req->endpt, p->payload, cp_len, req->grant,
|
||||
hdr_sz + written);
|
||||
|
||||
if (err != OK)
|
||||
return err;
|
||||
|
||||
written += cp_len;
|
||||
rem_len -= cp_len;
|
||||
}
|
||||
|
||||
debug_print("copied %d bytes\n", written + hdr_sz);
|
||||
return written + hdr_sz;
|
||||
}
|
||||
|
||||
static u8_t raw_ip_op_receive(void *arg,
|
||||
__unused struct raw_pcb *pcb,
|
||||
struct pbuf *pbuf,
|
||||
ip_addr_t *addr)
|
||||
{
|
||||
struct socket * sock = (struct socket *) arg;
|
||||
struct raw_ip_recv_data * data;
|
||||
int ret;
|
||||
|
||||
debug_print("socket num : %ld addr : %x\n",
|
||||
get_sock_num(sock), (unsigned int) addr->addr);
|
||||
|
||||
if (sock->flags & SOCK_FLG_OP_PENDING) {
|
||||
/* we are resuming a suspended operation */
|
||||
ret = raw_ip_do_receive(&sock->req, pbuf);
|
||||
|
||||
send_req_reply(&sock->req, ret);
|
||||
sock->flags &= ~SOCK_FLG_OP_PENDING;
|
||||
|
||||
if (ret > 0) {
|
||||
if (sock->usr_flags & NWIO_EXCL) {
|
||||
pbuf_free(pbuf);
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not enqueue more data than allowed */
|
||||
if (sock->recv_data_size > RAW_IP_BUF_SIZE)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* nobody is waiting for the data or an error occured above, we enqueue
|
||||
* the packet
|
||||
*/
|
||||
if (!(data = raw_ip_recv_alloc())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
data->ip = *addr;
|
||||
if (sock->usr_flags & NWIO_EXCL) {
|
||||
data->pbuf = pbuf;
|
||||
ret = 1;
|
||||
} else {
|
||||
/* we store a copy of this packet */
|
||||
data->pbuf = pbuf_alloc(PBUF_RAW, pbuf->tot_len, PBUF_RAM);
|
||||
if (data->pbuf == NULL) {
|
||||
debug_print("LWIP : cannot allocated new pbuf\n");
|
||||
raw_ip_recv_free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pbuf_copy(data->pbuf, pbuf) != ERR_OK) {
|
||||
debug_print("LWIP : cannot copy pbuf\n");
|
||||
raw_ip_recv_free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we didn't managed to enqueue the packet we report it as not
|
||||
* consumed
|
||||
*/
|
||||
if (sock_enqueue_data(sock, data, data->pbuf->tot_len) != OK) {
|
||||
raw_ip_recv_free(data);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int raw_ip_op_read(struct socket * sock, struct sock_req * req, int blk)
|
||||
{
|
||||
debug_print("socket num %ld", get_sock_num(sock));
|
||||
|
||||
if (sock->pcb == NULL)
|
||||
return EIO;
|
||||
|
||||
if (sock->recv_head) {
|
||||
/* data available receive immeditely */
|
||||
|
||||
struct raw_ip_recv_data * data;
|
||||
int ret;
|
||||
|
||||
data = (struct raw_ip_recv_data *) sock->recv_head->data;
|
||||
|
||||
ret = raw_ip_do_receive(req, data->pbuf);
|
||||
|
||||
if (ret > 0) {
|
||||
sock_dequeue_data(sock);
|
||||
sock->recv_data_size -= data->pbuf->tot_len;
|
||||
raw_ip_recv_free(data);
|
||||
}
|
||||
return ret;
|
||||
} else if (!blk)
|
||||
return EAGAIN;
|
||||
else {
|
||||
/* store the request so we know how to reply */
|
||||
sock->req = *req;
|
||||
/* operation is being processes */
|
||||
sock->flags |= SOCK_FLG_OP_PENDING;
|
||||
|
||||
debug_print("no data to read, suspending");
|
||||
return EDONTREPLY;
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_ip_op_write(struct socket * sock, struct sock_req * req,
|
||||
__unused int blk)
|
||||
{
|
||||
int ret;
|
||||
struct pbuf * pbuf;
|
||||
struct ip_hdr * ip_hdr;
|
||||
|
||||
debug_print("socket num %ld data size %u",
|
||||
get_sock_num(sock), req->size);
|
||||
|
||||
if (sock->pcb == NULL)
|
||||
return EIO;
|
||||
|
||||
if (req->size > sock->buf_size)
|
||||
return ENOMEM;
|
||||
|
||||
pbuf = pbuf_alloc(PBUF_LINK, req->size, PBUF_RAM);
|
||||
if (!pbuf)
|
||||
return ENOMEM;
|
||||
|
||||
if ((ret = copy_from_user(req->endpt, pbuf->payload, req->size,
|
||||
req->grant, 0)) != OK) {
|
||||
pbuf_free(pbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ip_hdr = (struct ip_hdr *) pbuf->payload;
|
||||
if (pbuf_header(pbuf, -IP_HLEN)) {
|
||||
pbuf_free(pbuf);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
if ((ret = raw_sendto((struct raw_pcb *)sock->pcb, pbuf,
|
||||
(ip_addr_t *) &ip_hdr->dest)) != OK) {
|
||||
debug_print("raw_sendto failed %d", ret);
|
||||
ret = EIO;
|
||||
} else
|
||||
ret = req->size;
|
||||
|
||||
|
||||
pbuf_free(pbuf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int raw_ip_set_opt(struct socket * sock, endpoint_t endpt,
|
||||
cp_grant_id_t grant)
|
||||
{
|
||||
int err;
|
||||
nwio_ipopt_t ipopt;
|
||||
struct raw_pcb * pcb;
|
||||
|
||||
err = copy_from_user(endpt, &ipopt, sizeof(ipopt), grant, 0);
|
||||
|
||||
if (err != OK)
|
||||
return err;
|
||||
|
||||
debug_print("ipopt.nwio_flags = 0x%x", ipopt.nwio_flags);
|
||||
debug_print("ipopt.nwio_proto = 0x%x", ipopt.nwio_proto);
|
||||
debug_print("ipopt.nwio_rem = 0x%x",
|
||||
(unsigned int) ipopt.nwio_rem);
|
||||
|
||||
if (sock->pcb == NULL) {
|
||||
if (!(pcb = raw_new(ipopt.nwio_proto))) {
|
||||
raw_ip_close(sock);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
sock->pcb = pcb;
|
||||
} else
|
||||
pcb = (struct raw_pcb *) sock->pcb;
|
||||
|
||||
if (pcb->protocol != ipopt.nwio_proto) {
|
||||
debug_print("conflicting ip socket protocols\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
sock->usr_flags = ipopt.nwio_flags;
|
||||
|
||||
#if 0
|
||||
if (raw_bind(pcb, (ip_addr_t *)&ipopt.nwio_rem) == ERR_USE) {
|
||||
raw_ip_close(sock);
|
||||
return EADDRINUSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* register a receive hook */
|
||||
raw_recv((struct raw_pcb *) sock->pcb, raw_ip_op_receive, sock);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int raw_ip_get_opt(struct socket * sock, endpoint_t endpt,
|
||||
cp_grant_id_t grant)
|
||||
{
|
||||
nwio_ipopt_t ipopt;
|
||||
struct raw_pcb * pcb = (struct raw_pcb *) sock->pcb;
|
||||
|
||||
assert(pcb);
|
||||
|
||||
ipopt.nwio_rem = pcb->remote_ip.addr;
|
||||
ipopt.nwio_flags = sock->usr_flags;
|
||||
|
||||
return copy_to_user(endpt, &ipopt, sizeof(ipopt), grant, 0);
|
||||
}
|
||||
|
||||
static int raw_ip_op_ioctl(struct socket * sock, struct sock_req * req,
|
||||
__unused int blk)
|
||||
{
|
||||
int r;
|
||||
|
||||
debug_print("socket num %ld req %c %ld %ld",
|
||||
get_sock_num(sock),
|
||||
(unsigned char) (req->req >> 8),
|
||||
req->req & 0xff,
|
||||
_MINIX_IOCTL_SIZE(req->req));
|
||||
|
||||
switch (req->req) {
|
||||
case NWIOSIPOPT:
|
||||
r = raw_ip_set_opt(sock, req->endpt, req->grant);
|
||||
break;
|
||||
case NWIOGIPOPT:
|
||||
r = raw_ip_get_opt(sock, req->endpt, req->grant);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* /dev/ip can be also accessed as a default device to be
|
||||
* configured
|
||||
*/
|
||||
r = nic_default_ioctl(req);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
struct sock_ops sock_raw_ip_ops = {
|
||||
.open = raw_ip_op_open,
|
||||
.close = raw_ip_op_close,
|
||||
.read = raw_ip_op_read,
|
||||
.write = raw_ip_op_write,
|
||||
.ioctl = raw_ip_op_ioctl,
|
||||
.select = generic_op_select,
|
||||
.select_reply = generic_op_select_reply
|
||||
};
|
@ -1,397 +0,0 @@
|
||||
/*
|
||||
* Mock net.route sysctl(2) subtree implementation using RMIB. This code
|
||||
* serves as a temporary bridge to allow libc to switch from the original,
|
||||
* native MINIX3 getifaddrs(3) to the NetBSD getifaddrs(3). As such, it
|
||||
* implements only a small subset of NetBSD's full net.route functionality,
|
||||
* although also more than needed only to imitate the MINIX3 getifaddrs(3).
|
||||
*/
|
||||
|
||||
#include <minix/netsock.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <minix/rmib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "proto.h"
|
||||
#include "driver.h"
|
||||
|
||||
/* Max. number of bytes for a full sockaddr_dl structure, including data. */
|
||||
#define SDL_BUFSIZE (sizeof(struct sockaddr_dl) + 32)
|
||||
|
||||
static const char padbuf[RT_ROUNDUP(0)] = { 0 };
|
||||
|
||||
/*
|
||||
* Compute the length for, and possibly copy out, an interface information or
|
||||
* interface address record with an associated set of zero or more routing
|
||||
* table addresses. The addresses are padded as necessary. Store the full
|
||||
* record length and the address bitmap before copying out the entire record.
|
||||
*/
|
||||
static ssize_t
|
||||
copyout_rta(void * hdr, size_t size, u_short * msglen, int * addrs,
|
||||
void * rta_map[RTAX_MAX], size_t rta_len[RTAX_MAX],
|
||||
struct rmib_oldp * oldp, ssize_t off)
|
||||
{
|
||||
iovec_t iov[1 + RTAX_MAX * 2];
|
||||
size_t len, total, padlen;
|
||||
unsigned int i, iovcnt;
|
||||
int mask;
|
||||
|
||||
iovcnt = 0;
|
||||
iov[iovcnt].iov_addr = (vir_bytes)hdr;
|
||||
iov[iovcnt++].iov_size = size;
|
||||
|
||||
total = size;
|
||||
mask = 0;
|
||||
|
||||
/*
|
||||
* Any addresses in the given map should be stored in the numbering
|
||||
* order of the map.
|
||||
*/
|
||||
for (i = 0; i < RTAX_MAX; i++) {
|
||||
if (rta_map[i] == NULL)
|
||||
continue;
|
||||
|
||||
assert(iovcnt < __arraycount(iov));
|
||||
iov[iovcnt].iov_addr = (vir_bytes)rta_map[i];
|
||||
iov[iovcnt++].iov_size = len = rta_len[i];
|
||||
|
||||
padlen = RT_ROUNDUP(len) - len;
|
||||
if (padlen > 0) {
|
||||
assert(iovcnt < __arraycount(iov));
|
||||
iov[iovcnt].iov_addr = (vir_bytes)padbuf;
|
||||
iov[iovcnt++].iov_size = padlen;
|
||||
}
|
||||
|
||||
total += len + padlen;
|
||||
mask |= (1 << i);
|
||||
}
|
||||
|
||||
/* If only the length was requested, return it now. */
|
||||
if (oldp == NULL)
|
||||
return total;
|
||||
|
||||
/*
|
||||
* Casting 'hdr' would violate C99 strict aliasing rules, so store the
|
||||
* computed header values through direct pointers. Bah.
|
||||
*/
|
||||
*msglen = total;
|
||||
*addrs = mask;
|
||||
|
||||
return rmib_vcopyout(oldp, off, iov, iovcnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the length for, and possibly generate, a sockaddr_dl structure for
|
||||
* the given interface. The complication here is that the structure contains
|
||||
* various field packed together dynamically, making it variable sized.
|
||||
*/
|
||||
static size_t
|
||||
make_sdl(const struct nic * nic, int ndx, char * buf, size_t max)
|
||||
{
|
||||
struct sockaddr_dl sdl;
|
||||
size_t hdrlen, namelen, addrlen, padlen, len;
|
||||
|
||||
namelen = strlen(nic->name);
|
||||
addrlen = sizeof(nic->netif.hwaddr);
|
||||
|
||||
/*
|
||||
* Compute the unpadded and padded length of the structure. We pad the
|
||||
* structure ourselves here, even though the caller will otherwise pad
|
||||
* it later, because it is easy to do so and saves on a vector element.
|
||||
*/
|
||||
hdrlen = offsetof(struct sockaddr_dl, sdl_data);
|
||||
len = hdrlen + namelen + addrlen;
|
||||
padlen = RT_ROUNDUP(len) - len;
|
||||
assert(len + padlen <= max);
|
||||
|
||||
/* If we are asked not to generate the actual data, stop here. */
|
||||
if (buf == NULL)
|
||||
return len + padlen;
|
||||
|
||||
/*
|
||||
* Fill the sockaddr_dl structure header. The C99 strict aliasing
|
||||
* rules prevent us from filling 'buf' through a pointer structure
|
||||
* directly.
|
||||
*/
|
||||
memset(&sdl, 0, hdrlen);
|
||||
sdl.sdl_len = len;
|
||||
sdl.sdl_family = AF_LINK;
|
||||
sdl.sdl_index = ndx;
|
||||
sdl.sdl_type = IFT_ETHER;
|
||||
sdl.sdl_nlen = namelen;
|
||||
sdl.sdl_alen = addrlen;
|
||||
sdl.sdl_slen = 0;
|
||||
|
||||
/*
|
||||
* Generate the full sockaddr_dl structure in the given buffer. These
|
||||
* memory sizes are typically small, so the extra memory copies are not
|
||||
* too expensive. The advantage of generating a single sockaddr_dl
|
||||
* structure buffer is that we can use copyout_rta() on it.
|
||||
*/
|
||||
memcpy(buf, &sdl, hdrlen);
|
||||
if (namelen > 0)
|
||||
memcpy(&buf[hdrlen], nic->name, namelen);
|
||||
if (addrlen > 0)
|
||||
memcpy(&buf[hdrlen + namelen], nic->netif.hwaddr, addrlen);
|
||||
if (padlen > 0)
|
||||
memset(&buf[len], 0, padlen);
|
||||
|
||||
return len + padlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the length for, and possibly generate, an interface information
|
||||
* record for the given interface.
|
||||
*/
|
||||
static ssize_t
|
||||
gen_ifm(const struct nic * nic, int ndx, int is_up, struct rmib_oldp * oldp,
|
||||
ssize_t off)
|
||||
{
|
||||
struct if_msghdr ifm;
|
||||
char buf[SDL_BUFSIZE];
|
||||
void *rta_map[RTAX_MAX];
|
||||
size_t rta_len[RTAX_MAX], size;
|
||||
|
||||
if (oldp != NULL) {
|
||||
memset(&ifm, 0, sizeof(ifm));
|
||||
ifm.ifm_version = RTM_VERSION;
|
||||
ifm.ifm_type = RTM_IFINFO;
|
||||
ifm.ifm_flags = (is_up) ? (IFF_UP | IFF_RUNNING) : 0;
|
||||
ifm.ifm_index = ndx;
|
||||
ifm.ifm_data.ifi_type = IFT_ETHER;
|
||||
/* TODO: other ifm_flags, other ifm_data fields, etc. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that we add padding even in this case, to ensure that the
|
||||
* following structures are properly aligned as well.
|
||||
*/
|
||||
size = make_sdl(nic, ndx, (oldp != NULL) ? buf : NULL, sizeof(buf));
|
||||
|
||||
memset(rta_map, 0, sizeof(rta_map));
|
||||
rta_map[RTAX_IFP] = buf;
|
||||
rta_len[RTAX_IFP] = size;
|
||||
|
||||
return copyout_rta(&ifm, sizeof(ifm), &ifm.ifm_msglen, &ifm.ifm_addrs,
|
||||
rta_map, rta_len, oldp, off);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the length for, and possibly generate, an AF_LINK-family interface
|
||||
* address record.
|
||||
*/
|
||||
static ssize_t
|
||||
gen_ifam_dl(const struct nic * nic, int ndx, int is_up,
|
||||
struct rmib_oldp * oldp, ssize_t off)
|
||||
{
|
||||
struct ifa_msghdr ifam;
|
||||
char buf[SDL_BUFSIZE];
|
||||
void *rta_map[RTAX_MAX];
|
||||
size_t rta_len[RTAX_MAX], size;
|
||||
|
||||
if (oldp != NULL) {
|
||||
memset(&ifam, 0, sizeof(ifam));
|
||||
ifam.ifam_version = RTM_VERSION;
|
||||
ifam.ifam_type = RTM_NEWADDR;
|
||||
ifam.ifam_index = ndx;
|
||||
ifam.ifam_metric = 0; /* unknown and irrelevant */
|
||||
}
|
||||
|
||||
size = make_sdl(nic, ndx, (oldp != NULL) ? buf : NULL, sizeof(buf));
|
||||
|
||||
/*
|
||||
* We do not generate a netmask. NetBSD seems to generate a netmask
|
||||
* with all-one bits for the number of bytes equal to the name length,
|
||||
* for reasons unknown to me. If we did the same, we would end up with
|
||||
* a conflict on the static 'namebuf' buffer.
|
||||
*/
|
||||
memset(rta_map, 0, sizeof(rta_map));
|
||||
rta_map[RTAX_IFA] = buf;
|
||||
rta_len[RTAX_IFA] = size;
|
||||
|
||||
return copyout_rta(&ifam, sizeof(ifam), &ifam.ifam_msglen,
|
||||
&ifam.ifam_addrs, rta_map, rta_len, oldp, off);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the length for, and possibly generate, an AF_INET-family interface
|
||||
* address record.
|
||||
*/
|
||||
static ssize_t
|
||||
gen_ifam_inet(const struct nic * nic, int ndx, int is_up,
|
||||
struct rmib_oldp * oldp, ssize_t off)
|
||||
{
|
||||
struct ifa_msghdr ifam;
|
||||
struct sockaddr_in ipaddr, netmask;
|
||||
void *rta_map[RTAX_MAX];
|
||||
size_t rta_len[RTAX_MAX];
|
||||
|
||||
if (oldp != NULL) {
|
||||
memset(&ifam, 0, sizeof(ifam));
|
||||
ifam.ifam_msglen = sizeof(ifam);
|
||||
ifam.ifam_version = RTM_VERSION;
|
||||
ifam.ifam_type = RTM_NEWADDR;
|
||||
ifam.ifam_addrs = 0;
|
||||
ifam.ifam_index = ndx;
|
||||
ifam.ifam_metric = 0; /* unknown and irrelevant */
|
||||
}
|
||||
|
||||
memset(rta_map, 0, sizeof(rta_map));
|
||||
|
||||
if (!ip_addr_isany(&nic->netif.ip_addr)) {
|
||||
if (oldp != NULL) {
|
||||
memset(&ipaddr, 0, sizeof(ipaddr));
|
||||
ipaddr.sin_family = AF_INET;
|
||||
ipaddr.sin_len = sizeof(ipaddr);
|
||||
ipaddr.sin_addr.s_addr =
|
||||
ip4_addr_get_u32(&nic->netif.ip_addr);
|
||||
}
|
||||
|
||||
rta_map[RTAX_IFA] = &ipaddr;
|
||||
rta_len[RTAX_IFA] = sizeof(ipaddr);
|
||||
}
|
||||
|
||||
if (!ip_addr_isany(&nic->netif.netmask)) {
|
||||
/*
|
||||
* TODO: BSD goes through the trouble of compressing the
|
||||
* netmask for some reason. We need to figure out if
|
||||
* compression is actually required by any part of userland.
|
||||
*/
|
||||
if (oldp != NULL) {
|
||||
memset(&netmask, 0, sizeof(netmask));
|
||||
netmask.sin_family = AF_INET;
|
||||
netmask.sin_len = sizeof(netmask);
|
||||
netmask.sin_addr.s_addr =
|
||||
ip4_addr_get_u32(&nic->netif.netmask);
|
||||
}
|
||||
|
||||
rta_map[RTAX_NETMASK] = &netmask;
|
||||
rta_len[RTAX_NETMASK] = sizeof(netmask);
|
||||
}
|
||||
|
||||
return copyout_rta(&ifam, sizeof(ifam), &ifam.ifam_msglen,
|
||||
&ifam.ifam_addrs, rta_map, rta_len, oldp, off);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the size needed for, and optionally copy out, the interface and
|
||||
* address information for the given interface.
|
||||
*/
|
||||
static ssize_t
|
||||
do_one_if(const struct nic * nic, int ndx, struct rmib_oldp * oldp,
|
||||
ssize_t off, int filter)
|
||||
{
|
||||
ssize_t r, len;
|
||||
int is_up;
|
||||
|
||||
/*
|
||||
* If the interface is not configured, we mark it as down and do not
|
||||
* provide IP address information.
|
||||
*/
|
||||
is_up = !ip_addr_isany(&nic->netif.ip_addr);
|
||||
|
||||
len = 0;
|
||||
|
||||
/* There is always a full interface information record. */
|
||||
if ((r = gen_ifm(nic, ndx, is_up, oldp, off)) < 0)
|
||||
return r;
|
||||
len += r;
|
||||
|
||||
/* If not filtered, there is a datalink address record. */
|
||||
if (filter == 0 || filter == AF_LINK) {
|
||||
if ((r = gen_ifam_dl(nic, ndx, is_up, oldp, off + len)) < 0)
|
||||
return r;
|
||||
len += r;
|
||||
}
|
||||
|
||||
/* If configured and not filtered, there is an IPv4 address record. */
|
||||
if (is_up && (filter == 0 || filter == AF_INET)) {
|
||||
if ((r = gen_ifam_inet(nic, ndx, is_up, oldp, off + len)) < 0)
|
||||
return r;
|
||||
len += r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether or not anything was copied out, upon success we return the
|
||||
* full length of the data.
|
||||
*/
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remote MIB implementation of CTL_NET PF_ROUTE 0. This function handles all
|
||||
* queries on the "net.route.rtable" sysctl(2) node.
|
||||
*/
|
||||
static ssize_t
|
||||
net_route_rtable(struct rmib_call * call, struct rmib_node * node __unused,
|
||||
struct rmib_oldp * oldp, struct rmib_newp * newp __unused)
|
||||
{
|
||||
const struct nic *nic;
|
||||
ssize_t r, off;
|
||||
int i, filter, ndx;
|
||||
|
||||
if (call->call_namelen != 3)
|
||||
return EINVAL;
|
||||
|
||||
/* We only support listing interfaces for now. */
|
||||
if (call->call_name[1] != NET_RT_IFLIST)
|
||||
return EOPNOTSUPP;
|
||||
|
||||
filter = call->call_name[0];
|
||||
ndx = call->call_name[2];
|
||||
|
||||
off = 0;
|
||||
|
||||
for (i = 0; i < MAX_DEVS; i++) {
|
||||
if (!(nic = nic_get(i)))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If information about a specific interface index is requested
|
||||
* then skip all other entries. Interface indices must be
|
||||
* nonzero, so we shift the numbers by one. We can avoid going
|
||||
* through the loop altogether here, but getifaddrs(3) does not
|
||||
* query specific interfaces anyway.
|
||||
*/
|
||||
if (ndx != 0 && ndx != i + 1)
|
||||
continue;
|
||||
|
||||
/* Avoid generating results that are never copied out. */
|
||||
if (oldp != NULL && !rmib_inrange(oldp, off))
|
||||
oldp = NULL;
|
||||
|
||||
if ((r = do_one_if(nic, i + 1, oldp, off, filter)) < 0)
|
||||
return r;
|
||||
|
||||
off += r;
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
/* The CTL_NET PF_ROUTE subtree. */
|
||||
static struct rmib_node net_route_table[] = {
|
||||
[0] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_route_rtable,
|
||||
"rtable", "Routing table information")
|
||||
};
|
||||
|
||||
/* The CTL_NET PF_ROUTE node. */
|
||||
static struct rmib_node net_route_node =
|
||||
RMIB_NODE(RMIB_RO, net_route_table, "route", "PF_ROUTE information");
|
||||
|
||||
/*
|
||||
* Register the net.route RMIB subtree with the MIB service. Since inet does
|
||||
* not support clean shutdowns, there is no matching cleanup function.
|
||||
*/
|
||||
void
|
||||
rtinfo_init(void)
|
||||
{
|
||||
const int mib[] = { CTL_NET, PF_ROUTE };
|
||||
int r;
|
||||
|
||||
if ((r = rmib_register(mib, __arraycount(mib), &net_route_node)) != OK)
|
||||
panic("unable to register remote MIB tree: %d", r);
|
||||
}
|
1196
minix/net/lwip/tcp.c
1196
minix/net/lwip/tcp.c
File diff suppressed because it is too large
Load Diff
@ -1,404 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <minix/sysutil.h>
|
||||
|
||||
#include <sys/ioc_net.h>
|
||||
#include <net/gen/in.h>
|
||||
#include <net/gen/udp.h>
|
||||
#include <net/gen/udp_io.h>
|
||||
#include <net/gen/udp_io_hdr.h>
|
||||
|
||||
#include <lwip/udp.h>
|
||||
#include <lwip/ip_addr.h>
|
||||
|
||||
#include <minix/netsock.h>
|
||||
#include "proto.h"
|
||||
|
||||
#define UDP_BUF_SIZE (4 << 10)
|
||||
|
||||
#define sock_alloc_buf(s) debug_malloc(s)
|
||||
#define sock_free_buf(x) debug_free(x)
|
||||
|
||||
#if 0
|
||||
#define debug_udp_print(str, ...) printf("LWIP %s:%d : " str "\n", \
|
||||
__func__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define debug_udp_print(...) debug_print(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
struct udp_recv_data {
|
||||
ip_addr_t ip;
|
||||
u16_t port;
|
||||
struct pbuf * pbuf;
|
||||
};
|
||||
|
||||
#define udp_recv_alloc() debug_malloc(sizeof(struct udp_recv_data))
|
||||
|
||||
static void udp_recv_free(void * data)
|
||||
{
|
||||
if (((struct udp_recv_data *)data)->pbuf)
|
||||
pbuf_free(((struct udp_recv_data *)data)->pbuf);
|
||||
debug_free(data);
|
||||
}
|
||||
|
||||
static int udp_op_open(struct socket * sock)
|
||||
{
|
||||
struct udp_pcb * pcb;
|
||||
|
||||
debug_udp_print("socket num %ld", get_sock_num(sock));
|
||||
|
||||
if (!(pcb = udp_new()))
|
||||
return ENOMEM;
|
||||
|
||||
sock->buf = NULL;
|
||||
sock->buf_size = 0;
|
||||
|
||||
sock->pcb = pcb;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int udp_op_close(struct socket * sock)
|
||||
{
|
||||
debug_udp_print("socket num %ld", get_sock_num(sock));
|
||||
|
||||
/* deque and free all enqueued data before closing */
|
||||
sock_dequeue_data_all(sock, udp_recv_free);
|
||||
|
||||
if (sock->pcb)
|
||||
udp_remove(sock->pcb);
|
||||
assert(sock->buf == NULL);
|
||||
|
||||
/* mark it as unused */
|
||||
sock->ops = NULL;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int udp_do_receive(struct socket * sock,
|
||||
struct sock_req * req,
|
||||
struct udp_pcb *pcb,
|
||||
struct pbuf *pbuf,
|
||||
ip_addr_t *addr,
|
||||
u16_t port)
|
||||
{
|
||||
struct pbuf * p;
|
||||
size_t rem_len = req->size;
|
||||
unsigned int written = 0, hdr_sz = 0;
|
||||
int err;
|
||||
|
||||
debug_udp_print("user buffer size : %u", rem_len);
|
||||
|
||||
/* FIXME make it both a single copy */
|
||||
if (!(sock->usr_flags & NWUO_RWDATONLY)) {
|
||||
udp_io_hdr_t hdr;
|
||||
|
||||
hdr.uih_src_addr = addr->addr;
|
||||
hdr.uih_src_port = htons(port);
|
||||
hdr.uih_dst_addr = pcb->local_ip.addr;
|
||||
hdr.uih_dst_port = htons(pcb->local_port);
|
||||
|
||||
hdr.uih_data_len = 0;
|
||||
hdr.uih_ip_opt_len = 0;
|
||||
|
||||
err = copy_to_user(req->endpt, &hdr, sizeof(hdr), req->grant,
|
||||
0);
|
||||
|
||||
if (err != OK)
|
||||
return err;
|
||||
|
||||
rem_len -= (hdr_sz = sizeof(hdr));
|
||||
}
|
||||
|
||||
for (p = pbuf; p && rem_len; p = p->next) {
|
||||
size_t cp_len;
|
||||
|
||||
cp_len = (rem_len < p->len) ? rem_len : p->len;
|
||||
err = copy_to_user(req->endpt, p->payload, cp_len, req->grant,
|
||||
hdr_sz + written);
|
||||
|
||||
if (err != OK)
|
||||
return err;
|
||||
|
||||
written += cp_len;
|
||||
rem_len -= cp_len;
|
||||
}
|
||||
|
||||
debug_udp_print("copied %d bytes", written + hdr_sz);
|
||||
return written + hdr_sz;
|
||||
}
|
||||
|
||||
static void udp_recv_callback(void *arg,
|
||||
struct udp_pcb *pcb,
|
||||
struct pbuf *pbuf,
|
||||
ip_addr_t *addr,
|
||||
u16_t port)
|
||||
{
|
||||
struct socket * sock = (struct socket *) arg;
|
||||
struct udp_recv_data * data;
|
||||
|
||||
debug_udp_print("socket num : %ld addr : %x port : %d\n",
|
||||
get_sock_num(sock), (unsigned int) addr->addr, port);
|
||||
|
||||
if (sock->flags & SOCK_FLG_OP_PENDING) {
|
||||
/* we are resuming a suspended operation */
|
||||
int ret;
|
||||
|
||||
ret = udp_do_receive(sock, &sock->req, pcb, pbuf, addr, port);
|
||||
|
||||
send_req_reply(&sock->req, ret);
|
||||
sock->flags &= ~SOCK_FLG_OP_PENDING;
|
||||
|
||||
if (ret > 0) {
|
||||
pbuf_free(pbuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not enqueue more data than allowed */
|
||||
if (sock->recv_data_size > UDP_BUF_SIZE) {
|
||||
pbuf_free(pbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* nobody is waiting for the data or an error occured above, we enqueue
|
||||
* the packet
|
||||
*/
|
||||
if (!(data = udp_recv_alloc())) {
|
||||
pbuf_free(pbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
data->ip = *addr;
|
||||
data->port = port;
|
||||
data->pbuf = pbuf;
|
||||
|
||||
if (sock_enqueue_data(sock, data, data->pbuf->tot_len) != OK) {
|
||||
udp_recv_free(data);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't need to notify when somebody is already waiting, reviving
|
||||
* read operation will do the trick for us. But we must announce new
|
||||
* data available here.
|
||||
*/
|
||||
if (sock_select_read_set(sock))
|
||||
sock_select_notify(sock);
|
||||
}
|
||||
|
||||
static int udp_op_read(struct socket * sock, struct sock_req * req, int blk)
|
||||
{
|
||||
debug_udp_print("socket num %ld", get_sock_num(sock));
|
||||
|
||||
if (sock->recv_head) {
|
||||
/* data available receive immeditely */
|
||||
|
||||
struct udp_recv_data * data;
|
||||
int ret;
|
||||
|
||||
data = (struct udp_recv_data *) sock->recv_head->data;
|
||||
|
||||
ret = udp_do_receive(sock, req, (struct udp_pcb *) sock->pcb,
|
||||
data->pbuf, &data->ip, data->port);
|
||||
|
||||
if (ret > 0) {
|
||||
sock_dequeue_data(sock);
|
||||
sock->recv_data_size -= data->pbuf->tot_len;
|
||||
udp_recv_free(data);
|
||||
}
|
||||
return ret;
|
||||
} else if (!blk)
|
||||
return EAGAIN;
|
||||
else {
|
||||
/* store the message so we know how to reply */
|
||||
sock->req = *req;
|
||||
/* operation is being processes */
|
||||
sock->flags |= SOCK_FLG_OP_PENDING;
|
||||
|
||||
debug_udp_print("no data to read, suspending\n");
|
||||
return EDONTREPLY;
|
||||
}
|
||||
}
|
||||
|
||||
static int udp_op_send(struct socket * sock,
|
||||
struct pbuf * pbuf,
|
||||
size_t size)
|
||||
{
|
||||
int err;
|
||||
|
||||
debug_udp_print("pbuf len %d\n", pbuf->len);
|
||||
|
||||
if ((err = udp_send(sock->pcb, pbuf)) == ERR_OK)
|
||||
return size;
|
||||
else {
|
||||
debug_udp_print("udp_send failed %d", err);
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int udp_op_sendto(struct socket * sock, struct pbuf * pbuf, size_t size)
|
||||
{
|
||||
int err;
|
||||
udp_io_hdr_t hdr;
|
||||
|
||||
hdr = *(udp_io_hdr_t *) pbuf->payload;
|
||||
|
||||
pbuf_header(pbuf, -(s16_t)sizeof(udp_io_hdr_t));
|
||||
|
||||
debug_udp_print("data len %d pbuf len %d\n",
|
||||
hdr.uih_data_len, pbuf->len);
|
||||
|
||||
if ((err = udp_sendto(sock->pcb, pbuf, (ip_addr_t *) &hdr.uih_dst_addr,
|
||||
ntohs(hdr.uih_dst_port))) == ERR_OK)
|
||||
return size;
|
||||
else {
|
||||
debug_udp_print("udp_sendto failed %d", err);
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int udp_op_write(struct socket * sock, struct sock_req * req,
|
||||
__unused int blk)
|
||||
{
|
||||
int ret;
|
||||
struct pbuf * pbuf;
|
||||
|
||||
debug_udp_print("socket num %ld data size %u",
|
||||
get_sock_num(sock), req->size);
|
||||
|
||||
pbuf = pbuf_alloc(PBUF_TRANSPORT, req->size, PBUF_POOL);
|
||||
if (!pbuf)
|
||||
return ENOMEM;
|
||||
|
||||
if ((ret = copy_from_user(req->endpt, pbuf->payload, req->size,
|
||||
req->grant, 0)) != OK) {
|
||||
pbuf_free(pbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sock->usr_flags & NWUO_RWDATONLY)
|
||||
ret = udp_op_send(sock, pbuf, req->size);
|
||||
else
|
||||
ret = udp_op_sendto(sock, pbuf, req->size);
|
||||
|
||||
if (pbuf_free(pbuf) == 0) {
|
||||
panic("We cannot buffer udp packets yet!");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int udp_set_opt(struct socket * sock, endpoint_t endpt,
|
||||
cp_grant_id_t grant)
|
||||
{
|
||||
int err;
|
||||
nwio_udpopt_t udpopt;
|
||||
struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb;
|
||||
ip_addr_t loc_ip = ip_addr_any;
|
||||
|
||||
assert(pcb);
|
||||
|
||||
err = copy_from_user(endpt, &udpopt, sizeof(udpopt), grant, 0);
|
||||
|
||||
if (err != OK)
|
||||
return err;
|
||||
|
||||
debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags);
|
||||
debug_udp_print("udpopt.nwuo_remaddr = 0x%x",
|
||||
(unsigned int) udpopt.nwuo_remaddr);
|
||||
debug_udp_print("udpopt.nwuo_remport = 0x%x",
|
||||
ntohs(udpopt.nwuo_remport));
|
||||
debug_udp_print("udpopt.nwuo_locaddr = 0x%x",
|
||||
(unsigned int) udpopt.nwuo_locaddr);
|
||||
debug_udp_print("udpopt.nwuo_locport = 0x%x",
|
||||
ntohs(udpopt.nwuo_locport));
|
||||
|
||||
sock->usr_flags = udpopt.nwuo_flags;
|
||||
|
||||
/*
|
||||
* We will only get data from userspace and the remote address
|
||||
* and port are being set which means that from now on we must
|
||||
* know where to send data. Thus we should interpret this as
|
||||
* connect() call
|
||||
*/
|
||||
if (sock->usr_flags & NWUO_RWDATONLY &&
|
||||
sock->usr_flags & NWUO_RP_SET &&
|
||||
sock->usr_flags & NWUO_RA_SET)
|
||||
udp_connect(pcb, (ip_addr_t *) &udpopt.nwuo_remaddr,
|
||||
ntohs(udpopt.nwuo_remport));
|
||||
/* Setting local address means binding */
|
||||
if (sock->usr_flags & NWUO_LP_SET)
|
||||
udp_bind(pcb, &loc_ip, ntohs(udpopt.nwuo_locport));
|
||||
/* We can only bind to random local port */
|
||||
if (sock->usr_flags & NWUO_LP_SEL)
|
||||
udp_bind(pcb, &loc_ip, 0);
|
||||
|
||||
/* register a receive hook */
|
||||
udp_recv((struct udp_pcb *) sock->pcb, udp_recv_callback, sock);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int udp_get_opt(struct socket * sock, endpoint_t endpt,
|
||||
cp_grant_id_t grant)
|
||||
{
|
||||
nwio_udpopt_t udpopt;
|
||||
struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb;
|
||||
|
||||
assert(pcb);
|
||||
|
||||
udpopt.nwuo_locaddr = pcb->local_ip.addr;
|
||||
udpopt.nwuo_locport = htons(pcb->local_port);
|
||||
udpopt.nwuo_remaddr = pcb->remote_ip.addr;
|
||||
udpopt.nwuo_remport = htons(pcb->remote_port);
|
||||
udpopt.nwuo_flags = sock->usr_flags;
|
||||
|
||||
debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags);
|
||||
debug_udp_print("udpopt.nwuo_remaddr = 0x%x",
|
||||
(unsigned int) udpopt.nwuo_remaddr);
|
||||
debug_udp_print("udpopt.nwuo_remport = 0x%x",
|
||||
ntohs(udpopt.nwuo_remport));
|
||||
debug_udp_print("udpopt.nwuo_locaddr = 0x%x",
|
||||
(unsigned int) udpopt.nwuo_locaddr);
|
||||
debug_udp_print("udpopt.nwuo_locport = 0x%x",
|
||||
ntohs(udpopt.nwuo_locport));
|
||||
|
||||
return copy_to_user(endpt, &udpopt, sizeof(udpopt), grant, 0);
|
||||
}
|
||||
|
||||
static int udp_op_ioctl(struct socket * sock, struct sock_req * req,
|
||||
__unused int blk)
|
||||
{
|
||||
int r;
|
||||
|
||||
debug_udp_print("socket num %ld req %c %ld %ld",
|
||||
get_sock_num(sock),
|
||||
(unsigned char) (req->req >> 8),
|
||||
req->req & 0xff, _MINIX_IOCTL_SIZE(req->req));
|
||||
|
||||
switch (req->req) {
|
||||
case NWIOSUDPOPT:
|
||||
r = udp_set_opt(sock, req->endpt, req->grant);
|
||||
break;
|
||||
case NWIOGUDPOPT:
|
||||
r = udp_get_opt(sock, req->endpt, req->grant);
|
||||
break;
|
||||
default:
|
||||
r = ENOTTY;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
struct sock_ops sock_udp_ops = {
|
||||
.open = udp_op_open,
|
||||
.close = udp_op_close,
|
||||
.read = udp_op_read,
|
||||
.write = udp_op_write,
|
||||
.ioctl = udp_op_ioctl,
|
||||
.select = generic_op_select,
|
||||
.select_reply = generic_op_select_reply
|
||||
};
|
||||
|
@ -1259,7 +1259,7 @@ _MKVARS.yes= \
|
||||
|
||||
#MINIX-specific vars
|
||||
_MKVARS.yes+= \
|
||||
MKSYSDEBUG MKLIVEUPDATE MKLWIP MKLLVMCMDS
|
||||
MKSYSDEBUG MKLIVEUPDATE MKLLVMCMDS
|
||||
.if (${MACHINE_ARCH} == "i386")
|
||||
_MKVARS.yes+= \
|
||||
MKWATCHDOG MKACPI MKAPIC MKDEBUGREG MKINSTALLBOOT MKPCI
|
||||
|
@ -235,7 +235,6 @@ LIB${_lib:tu}= ${DESTDIR}/usr/lib/lib${_lib:S/xx/++/:S/atf_c/atf-c/}.a
|
||||
minixfs \
|
||||
mthread \
|
||||
netdriver \
|
||||
netsock \
|
||||
sffs \
|
||||
sockdriver \
|
||||
sockevent \
|
||||
|
Loading…
x
Reference in New Issue
Block a user