This patch switches the MINIX3 ethernet driver stack from a port-based

model to an instance-based model. Each ethernet driver instance is now
responsible for exactly one network interface card. The port field in
/etc/inet.conf now acts as an instance field instead.

This patch also updates the data link protocol. This update:
- eliminates the concept of ports entirely;
- eliminates DL_GETNAME entirely;
- standardizes on using m_source for IPC and DL_ENDPT for safecopies;
- removes error codes from TASK/STAT replies, as they were unused;
- removes a number of other old or unused fields;
- names and renames a few other fields.

All ethernet drivers have been changed to:
- conform to the new protocol, and exactly that;
- take on an instance number based on a given "instance" argument;
- skip that number of PCI devices in probe iterations;
- use config tables and environment variables based on that number;
- no longer be limited to a predefined maximum of cards in any way;
- get rid of any leftover non-safecopy support and other ancient junk;
- have a correct banner protocol figure, or none at all.

Other changes:
* Inet.conf is now taken to be line-based, and supports #-comments.
  No existing installations are expected to be affected by this.
* A new, select-based asynchio library replaces the old one.
  Kindly contributed by Kees J. Bot.
* Inet now supports use of select() on IP devices.
  Combined, the last two changes together speed up dhcpd
  considerably in the presence of multiple interfaces.
* A small bug has been fixed in nonamed.
This commit is contained in:
David van Moolenbroek
2010-05-17 22:22:53 +00:00
parent f5bce90216
commit 9ba65d2ea8
55 changed files with 1971 additions and 4794 deletions

View File

@@ -7,7 +7,7 @@ LIB= c
CPPFLAGS+=-O -D_MINIX -D_POSIX_SOURCE
.include "${.CURDIR}/ansi/Makefile.inc"
.include "${.CURDIR}/wchar/Makefile.inc"
.include "${.CURDIR}/asyn/Makefile.inc"
.include "${.CURDIR}/ip/Makefile.inc"
.include "${.CURDIR}/math/Makefile.inc"
.include "${.CURDIR}/other/Makefile.inc"
@@ -17,6 +17,7 @@ CPPFLAGS+=-O -D_MINIX -D_POSIX_SOURCE
.include "${.CURDIR}/stdtime/Makefile.inc"
.include "${.CURDIR}/syscall/Makefile.inc"
.include "${.CURDIR}/sysvipc/Makefile.inc"
.include "${.CURDIR}/wchar/Makefile.inc"
.include "${.CURDIR}/arch/${ARCH}/int64/Makefile.inc"
.include "${.CURDIR}/arch/${ARCH}/misc/Makefile.inc"

View File

@@ -0,0 +1,12 @@
# ansi sources
.PATH: ${.CURDIR}/asyn
SRCS+= \
asyn_cancel.c \
asyn_close.c \
asyn_init.c \
asyn_pending.c \
asyn_read.c \
asyn_synch.c \
asyn_wait.c \
asyn_write.c

17
lib/libc/asyn/asyn.h Normal file
View File

@@ -0,0 +1,17 @@
/* asyn.h - async I/O
* Author: Kees J. Bot
* 7 Jul 1997
* Minix-vmd compatible asynchio(3) using BSD select(2).
*/
#define nil 0
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/asynchio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
typedef struct _asynfd asynfd_t;
typedef enum state { IDLE, WAITING, PENDING } state_t;

View File

@@ -0,0 +1,21 @@
/* asyn_cancel() - cancel an asynch operation Author: Kees J. Bot
* 7 Jul 1997
*/
#include "asyn.h"
int asyn_cancel(asynchio_t *asyn, int fd, int op)
/* Cancel an asynchronous operation if one is in progress. (This is easy with
* select(2), because no operation is actually happening.)
*/
{
asynfd_t *afd;
if ((unsigned) fd >= FD_SETSIZE) { errno= EBADF; return -1; }
afd= &asyn->asyn_afd[fd];
if (afd->afd_state[op] == WAITING) {
afd->afd_state[op]= IDLE;
FD_CLR(fd, &asyn->asyn_fdset[SEL_READ]);
}
return 0;
}

View File

@@ -0,0 +1,24 @@
/* asyn_close() - forcefully forget about a file descriptor
* Author: Kees J. Bot
* 7 Jul 1997
*/
#include "asyn.h"
int asyn_close(asynchio_t *asyn, int fd)
/* Stop caring about any async operations on this file descriptor. */
{
asynfd_t *afd;
int op;
if ((unsigned) fd >= FD_SETSIZE) { errno= EBADF; return -1; }
afd= &asyn->asyn_afd[fd];
for (op= 0; op < SEL_NR; op++) {
afd->afd_state[op]= IDLE;
FD_CLR(fd, &asyn->asyn_fdset[op]);
}
afd->afd_seen= 0;
asyn->asyn_more++;
return 0;
}

View File

@@ -0,0 +1,9 @@
/* asyn_init() Author: Kees J. Bot
* 7 Jul 1997
*/
#include "asyn.h"
void asyn_init(asynchio_t *asyn)
{
memset(asyn, 0, sizeof(*asyn));
}

View File

@@ -0,0 +1,14 @@
/* asyn_pending() - any results pending? Author: Kees J. Bot
* 7 Jul 1997
*/
#include "asyn.h"
int asyn_pending(asynchio_t *asyn, int fd, int op)
/* Check if a result of an operation is pending. (This is easy with
* select(2), because no operation is actually happening.)
*/
{
if ((unsigned) fd >= FD_SETSIZE) { errno= EBADF; return -1; }
return 0;
}

61
lib/libc/asyn/asyn_read.c Normal file
View File

@@ -0,0 +1,61 @@
/* asyn_read() Author: Kees J. Bot
* 7 Jul 1997
*/
#include "asyn.h"
#include <signal.h>
ssize_t asyn_read(asynchio_t *asyn, int fd, void *buf, size_t len)
/* Asynchronous read(). Try if a read can be done, if not then set a flag
* indicating that select(2) should look out for it. Returns like a normal
* read or returns -1 with errno set to EAGAIN.
*/
{
asynfd_t *afd;
/* Asyn_wait() may block if this counter equals zero indicating that
* all of the asyn_* functions are "in progress".
*/
asyn->asyn_more++;
if ((unsigned) fd >= FD_SETSIZE) { errno= EBADF; return -1; }
afd= &asyn->asyn_afd[fd];
/* If this is the first async call on this filedescriptor then
* remember its file flags.
*/
if (!afd->afd_seen) {
if ((afd->afd_flags= fcntl(fd, F_GETFL)) < 0) return -1;
afd->afd_seen= 1;
}
/* Try to read if I/O is pending. */
if (afd->afd_state[SEL_READ] == PENDING) {
sigset_t mask;
ssize_t result;
int err;
sigemptyset(&mask);
if (sigprocmask(SIG_SETMASK, &mask, &mask) < 0) return -1;
(void) fcntl(fd, F_SETFL, afd->afd_flags | O_NONBLOCK);
/* Try the actual read. */
result= read(fd, buf, len);
err= errno;
(void) fcntl(fd, F_SETFL, afd->afd_flags);
(void) sigprocmask(SIG_SETMASK, &mask, nil);
errno= err;
if (result != -1 || errno != EAGAIN) {
afd->afd_state[SEL_READ]= IDLE;
return result;
}
}
/* Record this read as "waiting". */
afd->afd_state[SEL_READ]= WAITING;
FD_SET(fd, &asyn->asyn_fdset[SEL_READ]);
errno= EAGAIN;
asyn->asyn_more--;
return -1;
}

View File

@@ -0,0 +1,104 @@
/* asyn_special(), asyn_result() Author: Kees J. Bot
* 8 Jul 1997
*/
#include "asyn.h"
#include <signal.h>
/* Saved signal mask between asyn_special() and asyn_result(). */
static sigset_t mask;
int asyn_special(asynchio_t *asyn, int fd, int op)
/* Wait for an operation. This is an odd one out compared to asyn_read()
* and asyn_write(). It does not do an operation itself, but together with
* asyn_result() it is a set of brackets around a system call xxx that has
* no asyn_xxx() for itself. It can be used to build an asyn_accept() or
* asyn_connect() for instance. (Minix-vmd has asyn_ioctl() instead,
* which is used for any other event like TCP/IP listen/connect. BSD has
* a myriad of calls that can't be given an asyn_xxx() counterpart each.)
* Asyn_special() returns -1 for "forget it", 0 for "try it", and 1 for
* "very first call, maybe you should try it once, maybe not". Errno is
* set to EAGAIN if the result is -1 or 1. After trying the system call
* make sure errno equals EAGAIN if the call is still in progress and call
* asyn_result with the result of the system call. Asyn_result() must be
* called if asyn_special() returns 0 or 1.
*
* Example use:
*
* int asyn_accept(asynchio_t *asyn, int s, struct sockaddr *addr, int *addrlen)
* {
* int r;
* if ((r= asyn_special(asyn, fd, SEL_READ)) < 0) return -1;
* r= r == 0 ? accept(fd, addr, addrlen) : -1;
* return asyn_result(asyn, fd, SEL_READ, r);
* }
*
* int asyn_connect(asynchio_t *asyn, int s, struct sockaddr *name, int namelen)
* {
* int r;
* if ((r= asyn_special(asyn, fd, SEL_WRITE)) < 0) return -1;
* if (r == 1 && (r= connect(fd, name, namelen)) < 0) {
* if (errno == EINPROGRESS) errno= EAGAIN;
* }
* return asyn_result(asyn, fd, SEL_WRITE, r);
* }
*/
{
asynfd_t *afd;
int seen;
asyn->asyn_more++;
if ((unsigned) fd >= FD_SETSIZE) { errno= EBADF; return -1; }
afd= &asyn->asyn_afd[fd];
/* If this is the first async call on this filedescriptor then
* remember its file flags.
*/
if (!(seen= afd->afd_seen)) {
if ((afd->afd_flags= fcntl(fd, F_GETFL)) < 0) return -1;
afd->afd_seen= 1;
}
/* Try to read if I/O is pending. */
if (!seen || afd->afd_state[op] == PENDING) {
sigemptyset(&mask);
if (sigprocmask(SIG_SETMASK, &mask, &mask) < 0) return -1;
(void) fcntl(fd, F_SETFL, afd->afd_flags | O_NONBLOCK);
/* Let the caller try the system call. */
errno= EAGAIN;
return seen ? 0 : 1;
}
/* Record this read as "waiting". */
afd->afd_state[op]= WAITING;
FD_SET(fd, &asyn->asyn_fdset[op]);
errno= EAGAIN;
asyn->asyn_more--;
return -1;
}
int asyn_result(asynchio_t *asyn, int fd, int op, int result)
/* The caller has tried the system call with the given result. Finish up. */
{
int err;
asynfd_t *afd= &asyn->asyn_afd[fd];
err= errno;
(void) fcntl(fd, F_SETFL, afd->afd_flags);
(void) sigprocmask(SIG_SETMASK, &mask, nil);
errno= err;
if (result != -1 || errno != EAGAIN) {
afd->afd_state[op]= IDLE;
return result;
}
/* Record this operation as "waiting". */
afd->afd_state[op]= WAITING;
FD_SET(fd, &asyn->asyn_fdset[op]);
errno= EAGAIN;
asyn->asyn_more--;
return -1;
}

View File

@@ -0,0 +1,27 @@
/* asyn_synch() - step back to synch Author: Kees J. Bot
* 7 Jul 1997
*/
#include "asyn.h"
int asyn_synch(asynchio_t *asyn, int fd)
/* No more asynchronous operations on this file descriptor. */
{
asynfd_t *afd;
int flags;
int op;
if ((unsigned) fd >= FD_SETSIZE) { errno= EBADF; return -1; }
afd= &asyn->asyn_afd[fd];
for (op= 0; op < SEL_NR; op++) {
if (afd->afd_state[op] != IDLE) {
errno= EAGAIN;
return -1;
}
}
/* Make sure the file flags are as they once were. */
if (afd->afd_seen && fcntl(fd, F_SETFL, afd->afd_flags) < 0) return -1;
afd->afd_seen= 0;
return 0;
}

119
lib/libc/asyn/asyn_wait.c Normal file
View File

@@ -0,0 +1,119 @@
/* asyn_wait() - wait for asynch operations Author: Kees J. Bot
* 7 Jul 1997
*/
#define DEBUG 0
#include "asyn.h"
#include <time.h>
#if DEBUG
#include <stdio.h>
#endif
#define TBOUND_MIN 1
#define TBOUND_MAX 16
int asyn_wait(asynchio_t *asyn, int flags, struct timeval *to)
/* Wait for one or more nonblocking operations to return a result. */
{
int r;
static struct timeval zero_time;
struct timeval t;
static time_t tbound= TBOUND_MIN;
/* Are there more things to do before we can block? */
if (asyn->asyn_more > 0) { asyn->asyn_more= 0; return 0; }
if (flags & ASYN_NONBLOCK) {
/* Don't block by using a zero second timeout. */
to= &zero_time;
} else
if (to != nil) {
/* asyn_wait() uses an absolute time. */
if (to->tv_usec >= 1000000L) {
to->tv_sec+= to->tv_usec / 1000000L;
to->tv_usec%= 1000000L;
}
(void) gettimeofday(&t, nil);
if (t.tv_sec > to->tv_sec || (t.tv_sec == to->tv_sec
&& t.tv_usec >= to->tv_usec)) {
to= &zero_time;
} else {
t.tv_sec= to->tv_sec - t.tv_sec;
t.tv_usec= to->tv_usec - t.tv_usec;
if (t.tv_usec < 0) {
t.tv_sec--;
t.tv_usec+= 1000000L;
}
to= &t;
}
/* Don't sleep too long, we don't trust select(). */
if (to->tv_sec > tbound) goto bound;
} else {
bound:
/* No timeout? Don't hang in (buggy?) select() forever. */
to= &t;
t.tv_sec= tbound;
t.tv_usec= 0;
}
#if DEBUG
{
int op;
fprintf(stderr, "select: ");
for (op= 0; op < SEL_NR; op++) {
fd_set *fdsetp= &asyn->asyn_fdset[op];
int fd;
for (fd= 0; fd < FD_SETSIZE; fd++) {
if (FD_ISSET(fd, fdsetp)) {
asyn->asyn_afd[fd].afd_state[op]=
PENDING;
fprintf(stderr, "%d%c", fd, "rwx"[op]);
}
}
}
fflush(stderr);
}
#endif
r= select(FD_SETSIZE, &asyn->asyn_fdset[SEL_READ],
&asyn->asyn_fdset[SEL_WRITE],
&asyn->asyn_fdset[SEL_EXCEPT], to);
#if DEBUG
fprintf(stderr, " (%d) ", r);
#endif
if (r > 0) {
/* An event occurred on one or more file descriptors. */
int op;
for (op= 0; op < SEL_NR; op++) {
fd_set *fdsetp= &asyn->asyn_fdset[op];
int fd;
for (fd= 0; fd < FD_SETSIZE; fd++) {
if (FD_ISSET(fd, fdsetp)) {
asyn->asyn_afd[fd].afd_state[op]=
PENDING;
#if DEBUG
fprintf(stderr, "%d%c", fd, "rwx"[op]);
#endif
}
}
}
tbound= TBOUND_MIN;
} else
if (r == 0) {
/* If nothing happened then let the time boundary slip a bit. */
if (tbound < TBOUND_MAX) tbound <<= 1;
}
#if DEBUG
fputc('\n', stderr);
#endif
FD_ZERO(&asyn->asyn_fdset[SEL_READ]);
FD_ZERO(&asyn->asyn_fdset[SEL_WRITE]);
FD_ZERO(&asyn->asyn_fdset[SEL_EXCEPT]);
return r == 0 ? (errno= EINTR, -1) : r;
}

View File

@@ -0,0 +1,50 @@
/* asyn_write() Author: Kees J. Bot
* 7 Jul 1997
*/
#include "asyn.h"
#include <signal.h>
ssize_t asyn_write(asynchio_t *asyn, int fd, const void *buf, size_t len)
/* Nonblocking write(). (See asyn_read()). */
{
asynfd_t *afd;
ssize_t result;
asyn->asyn_more++;
if ((unsigned) fd >= FD_SETSIZE) { errno= EBADF; return -1; }
afd= &asyn->asyn_afd[fd];
if (!afd->afd_seen) {
if ((afd->afd_flags= fcntl(fd, F_GETFL)) < 0) return -1;
afd->afd_seen= 1;
}
if (afd->afd_state[SEL_WRITE] == PENDING) {
sigset_t mask;
ssize_t result;
int err;
sigemptyset(&mask);
if (sigprocmask(SIG_SETMASK, &mask, &mask) < 0) return -1;
(void) fcntl(fd, F_SETFL, afd->afd_flags | O_NONBLOCK);
result= write(fd, buf, len);
err= errno;
(void) fcntl(fd, F_SETFL, afd->afd_flags);
(void) sigprocmask(SIG_SETMASK, &mask, nil);
errno= err;
if (result != -1 || errno != EAGAIN) {
afd->afd_state[SEL_WRITE]= IDLE;
return result;
}
}
afd->afd_state[SEL_WRITE]= WAITING;
FD_SET(fd, &asyn->asyn_fdset[SEL_WRITE]);
errno= EAGAIN;
asyn->asyn_more--;
return -1;
}

View File

@@ -35,7 +35,6 @@ SRCS+= \
_vm_set_priv.c \
_vm_update.c \
_vm_query_exit.c \
asynchio.c \
basename.c \
bcmp.c \
bcopy.c \

View File

@@ -1,153 +0,0 @@
/* asyn_init(), asyn_read(), asyn_write(), asyn_ioctl(),
* asyn_wait(), asyn_synch(), asyn_close()
* Author: Kees J. Bot
* 26 Jan 1995
* Thise are just stub routines that are call compatible with
* the asynchio(3) library of Minix-vmd. See asynchio.h.
*/
#define alarm _alarm
#define ioctl _ioctl
#define read _read
#define sigaction _sigaction
#define sigfillset _sigfillset
#define time _time
#define write _write
#include <lib.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/asynchio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#define IO_IDLE 0
#define IO_INPROGRESS 1
#define IO_RESULT 2
#define OP_NOOP 0
#define OP_READ 1
#define OP_WRITE 2
#define OP_IOCTL 3
static asynchio_t *asyn_current;
void asyn_init(asynchio_t *asyn)
{
asyn->state= IO_IDLE;
asyn->op= OP_NOOP;
}
static ssize_t operation(int op, asynchio_t *asyn, int fd, int req,
void *data, ssize_t count)
{
switch (asyn->state) {
case IO_INPROGRESS:
if (asyn_current != asyn && asyn->op != op) abort();
/*FALL THROUGH*/
case IO_IDLE:
asyn_current= asyn;
asyn->op= op;
asyn->fd= fd;
asyn->req= req;
asyn->data= data;
asyn->count= count;
asyn->state= IO_INPROGRESS;
errno= EINPROGRESS;
return -1;
case IO_RESULT:
if (asyn_current != asyn && asyn->op != op) abort();
errno= asyn->errno;
return asyn->count;
}
}
ssize_t asyn_read(asynchio_t *asyn, int fd, void *buf, size_t len)
{
return operation(OP_READ, asyn, fd, 0, buf, len);
}
ssize_t asyn_write(asynchio_t *asyn, int fd, const void *buf, size_t len)
{
return operation(OP_WRITE, asyn, fd, 0, (void *) buf, len);
}
int asyn_ioctl(asynchio_t *asyn, int fd, unsigned long request, void *data)
{
return operation(OP_IOCTL, asyn, fd, request, data, 0);
}
static void time_out(int sig)
{
alarm(1);
}
int asyn_wait(asynchio_t *asyn, int flags, struct timeval *to)
{
time_t now;
unsigned old_timer, new_timer;
struct sigaction old_sa, new_sa;
if (asyn_current != asyn) abort();
if (flags & ASYN_NONBLOCK) abort();
if (asyn->state == IO_RESULT) {
asyn->state= IO_IDLE;
asyn->op= OP_NOOP;
return 0;
}
if (to != NULL) {
now= time(NULL);
if (to->tv_sec <= now) { errno= EINTR; return -1; }
old_timer= alarm(0);
new_sa.sa_handler= time_out;
sigfillset(&new_sa.sa_mask);
new_sa.sa_flags= 0;
sigaction(SIGALRM, &new_sa, &old_sa);
new_timer= to->tv_sec - now;
if (new_timer < old_timer) {
new_timer= old_timer;
}
alarm(new_timer);
}
switch (asyn->op) {
case OP_NOOP:
asyn->count= pause();
asyn->errno= errno;
case OP_READ:
asyn->count= read(asyn->fd, asyn->data, asyn->count);
asyn->errno= errno;
break;
case OP_WRITE:
asyn->count= write(asyn->fd, asyn->data, asyn->count);
asyn->errno= errno;
break;
case OP_IOCTL:
asyn->count= ioctl(asyn->fd, asyn->req, asyn->data);
asyn->errno= errno;
break;
}
if (to != NULL) {
alarm(0);
sigaction(SIGALRM, &old_sa, (struct sigaction *)0);
alarm(old_timer);
}
if (asyn->count == -1 && asyn->errno == EINTR) {
errno= EINTR;
return -1;
} else {
asyn->state= IO_RESULT;
return 0;
}
}
int asyn_synch(asynchio_t *asyn, int fd)
{
}
int asyn_close(asynchio_t *asyn, int fd)
{
asyn_init(asyn);
}

View File

@@ -64,7 +64,7 @@ int *status_ptr;
if(m_ptr->m_type == DL_CONF) {
conf_expected = FALSE;
}
else if(m_ptr->m_type != DL_GETNAME) {
else {
continue;
}
}