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.
407 lines
8.9 KiB
C
407 lines
8.9 KiB
C
/* this file contains the interface of the network software with rest of
|
|
minix. Furthermore it contains the main loop of the network task.
|
|
|
|
Copyright 1995 Philip Homburg
|
|
|
|
The valid messages and their parameters are:
|
|
|
|
from FS:
|
|
__________________________________________________________________
|
|
| | | | | | |
|
|
| m_type | DEVICE | PROC_NR | COUNT | POSITION | ADDRESS |
|
|
|_______________|___________|_________|_______|__________|_________|
|
|
| | | | | | |
|
|
| NW_OPEN | minor dev | proc nr | mode | | |
|
|
|_______________|___________|_________|_______|__________|_________|
|
|
| | | | | | |
|
|
| NW_CLOSE | minor dev | proc nr | | | |
|
|
|_______________|___________|_________|_______|__________|_________|
|
|
| | | | | | |
|
|
| NW_IOCTL | minor dev | proc nr | | NWIO.. | address |
|
|
|_______________|___________|_________|_______|__________|_________|
|
|
| | | | | | |
|
|
| NW_READ | minor dev | proc nr | count | | address |
|
|
|_______________|___________|_________|_______|__________|_________|
|
|
| | | | | | |
|
|
| NW_WRITE | minor dev | proc nr | count | | address |
|
|
|_______________|___________|_________|_______|__________|_________|
|
|
| | | | | | |
|
|
| NW_CANCEL | minor dev | proc nr | | | |
|
|
|_______________|___________|_________|_______|__________|_________|
|
|
|
|
from DL_ETH:
|
|
(not documented here)
|
|
*/
|
|
|
|
#include "inet.h"
|
|
|
|
#define _MINIX_SOURCE 1
|
|
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/svrctl.h>
|
|
#include <minix/ds.h>
|
|
#include <minix/endpoint.h>
|
|
#include <minix/drivers.h>
|
|
#include <minix/driver.h>
|
|
|
|
#include "mq.h"
|
|
#include "qp.h"
|
|
#include "proto.h"
|
|
#include "generic/type.h"
|
|
|
|
#include "generic/arp.h"
|
|
#include "generic/assert.h"
|
|
#include "generic/buf.h"
|
|
#include "generic/clock.h"
|
|
#include "generic/eth.h"
|
|
#include "generic/event.h"
|
|
#include "generic/ip.h"
|
|
#include "generic/psip.h"
|
|
#include "generic/rand256.h"
|
|
#include "generic/sr.h"
|
|
#include "generic/tcp.h"
|
|
#include "generic/udp.h"
|
|
|
|
THIS_FILE
|
|
|
|
#define RANDOM_DEV_NAME "/dev/random"
|
|
|
|
endpoint_t this_proc; /* Process number of this server. */
|
|
|
|
/* Killing Solaris */
|
|
int killer_inet= 0;
|
|
|
|
#ifdef BUF_CONSISTENCY_CHECK
|
|
extern int inet_buf_debug;
|
|
#endif
|
|
|
|
#if HZ_DYNAMIC
|
|
u32_t system_hz;
|
|
#endif
|
|
|
|
_PROTOTYPE( void main, (void) );
|
|
|
|
FORWARD _PROTOTYPE( void nw_conf, (void) );
|
|
FORWARD _PROTOTYPE( void nw_init, (void) );
|
|
FORWARD _PROTOTYPE( void ds_event, (void) );
|
|
|
|
/* SEF functions and variables. */
|
|
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
|
|
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
|
|
|
|
PUBLIC void main()
|
|
{
|
|
mq_t *mq;
|
|
int ipc_status;
|
|
int r;
|
|
endpoint_t source;
|
|
int m_type;
|
|
|
|
/* SEF local startup. */
|
|
sef_local_startup();
|
|
|
|
while (TRUE)
|
|
{
|
|
#ifdef BUF_CONSISTENCY_CHECK
|
|
if (inet_buf_debug)
|
|
{
|
|
static int buf_debug_count= 0;
|
|
|
|
if (++buf_debug_count >= inet_buf_debug)
|
|
{
|
|
buf_debug_count= 0;
|
|
if (!bf_consistency_check())
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
if (ev_head)
|
|
{
|
|
ev_process();
|
|
continue;
|
|
}
|
|
if (clck_call_expire)
|
|
{
|
|
clck_expire_timers();
|
|
continue;
|
|
}
|
|
mq= mq_get();
|
|
if (!mq)
|
|
ip_panic(("out of messages"));
|
|
|
|
r= sef_receive_status(ANY, &mq->mq_mess, &ipc_status);
|
|
if (r<0)
|
|
{
|
|
ip_panic(("unable to receive: %d", r));
|
|
}
|
|
reset_time();
|
|
source= mq->mq_mess.m_source;
|
|
m_type= mq->mq_mess.m_type;
|
|
if (source == FS_PROC_NR)
|
|
{
|
|
sr_rec(mq);
|
|
}
|
|
else if (is_ipc_notify(ipc_status))
|
|
{
|
|
if (source == CLOCK)
|
|
{
|
|
clck_tick(&mq->mq_mess);
|
|
mq_free(mq);
|
|
}
|
|
else if (source == PM_PROC_NR)
|
|
{
|
|
/* signaled */
|
|
/* probably SIGTERM */
|
|
mq_free(mq);
|
|
}
|
|
else if (source == DS_PROC_NR)
|
|
{
|
|
/* DS notifies us of an event. */
|
|
ds_event();
|
|
mq_free(mq);
|
|
}
|
|
else
|
|
{
|
|
printf("inet: got unexpected notify from %d\n",
|
|
mq->mq_mess.m_source);
|
|
mq_free(mq);
|
|
}
|
|
}
|
|
else if (m_type == DL_CONF_REPLY || m_type == DL_TASK_REPLY ||
|
|
m_type == DL_STAT_REPLY)
|
|
{
|
|
eth_rec(&mq->mq_mess);
|
|
mq_free(mq);
|
|
}
|
|
else
|
|
{
|
|
printf("inet: got bad message type 0x%x from %d\n",
|
|
mq->mq_mess.m_type, mq->mq_mess.m_source);
|
|
mq_free(mq);
|
|
}
|
|
}
|
|
ip_panic(("task is not allowed to terminate"));
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* sef_local_startup *
|
|
*===========================================================================*/
|
|
PRIVATE void sef_local_startup()
|
|
{
|
|
/* Register init callbacks. */
|
|
sef_setcb_init_fresh(sef_cb_init_fresh);
|
|
sef_setcb_init_restart(sef_cb_init_fresh);
|
|
|
|
/* No live update support for now. */
|
|
|
|
/* Let SEF perform startup. */
|
|
sef_startup();
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* sef_cb_init_fresh *
|
|
*===========================================================================*/
|
|
PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
|
|
{
|
|
/* Initialize the inet server. */
|
|
int r;
|
|
int timerand, fd;
|
|
endpoint_t tasknr;
|
|
u8_t randbits[32];
|
|
struct timeval tv;
|
|
char my_name[32];
|
|
|
|
#if DEBUG
|
|
printf("Starting inet...\n");
|
|
printf("%s\n", version);
|
|
#endif
|
|
|
|
#if HZ_DYNAMIC
|
|
system_hz = sys_hz();
|
|
#endif
|
|
|
|
/* Read configuration. */
|
|
nw_conf();
|
|
|
|
/* Get a random number */
|
|
timerand= 1;
|
|
fd= open(RANDOM_DEV_NAME, O_RDONLY | O_NONBLOCK);
|
|
if (fd != -1)
|
|
{
|
|
r= read(fd, randbits, sizeof(randbits));
|
|
if (r == sizeof(randbits))
|
|
timerand= 0;
|
|
else
|
|
{
|
|
printf("inet: unable to read random data from %s: %s\n",
|
|
RANDOM_DEV_NAME, r == -1 ? strerror(errno) :
|
|
r == 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");
|
|
r= gettimeofday(&tv, NULL);
|
|
if (r == -1)
|
|
{
|
|
printf("sysutime failed: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
memcpy(randbits, &tv, sizeof(tv));
|
|
}
|
|
init_rand256(randbits);
|
|
|
|
/* Our new identity as a server. */
|
|
r = sys_whoami(&tasknr, my_name, sizeof(my_name));
|
|
if (r != OK)
|
|
ip_panic(("inet: sys_whoami failed for 'inet': %d", r));
|
|
this_proc= tasknr;
|
|
|
|
#ifdef BUF_CONSISTENCY_CHECK
|
|
inet_buf_debug= (getenv("inetbufdebug") &&
|
|
(strcmp(getenv("inetbufdebug"), "on") == 0));
|
|
inet_buf_debug= 100;
|
|
if (inet_buf_debug)
|
|
{
|
|
ip_warning(( "buffer consistency check enabled" ));
|
|
}
|
|
#endif
|
|
|
|
if (getenv("killerinet"))
|
|
{
|
|
ip_warning(( "killer inet active" ));
|
|
killer_inet= 1;
|
|
}
|
|
|
|
nw_init();
|
|
|
|
/* Subscribe to driver events for network drivers. */
|
|
r = ds_subscribe("drv\\.net\\..*", DSF_INITIAL | DSF_OVERWRITE);
|
|
if(r != OK) {
|
|
ip_panic(("inet: can't subscribe to driver events"));
|
|
}
|
|
|
|
/* Announce we are up. INET announces its presence to VFS just like
|
|
* any other driver.
|
|
*/
|
|
driver_announce();
|
|
|
|
return(OK);
|
|
}
|
|
|
|
PRIVATE void nw_conf()
|
|
{
|
|
read_conf();
|
|
eth_prep();
|
|
arp_prep();
|
|
psip_prep();
|
|
ip_prep();
|
|
tcp_prep();
|
|
udp_prep();
|
|
}
|
|
|
|
PRIVATE void nw_init()
|
|
{
|
|
mq_init();
|
|
bf_init();
|
|
clck_init();
|
|
sr_init();
|
|
qp_init();
|
|
eth_init();
|
|
arp_init();
|
|
psip_init();
|
|
ip_init();
|
|
tcp_init();
|
|
udp_init();
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* ds_event *
|
|
*===========================================================================*/
|
|
PRIVATE void ds_event()
|
|
{
|
|
char key[DS_MAX_KEYLEN];
|
|
char *driver_prefix = "drv.net.";
|
|
char *label;
|
|
u32_t value;
|
|
int type;
|
|
endpoint_t owner_endpoint;
|
|
int r;
|
|
|
|
/* 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("inet: ds_event: ds_retrieve_u32 failed\n");
|
|
return;
|
|
}
|
|
|
|
/* Only check for network driver up events. */
|
|
if(strncmp(key, driver_prefix, sizeof(driver_prefix))
|
|
|| value != DS_DRIVER_UP) {
|
|
return;
|
|
}
|
|
|
|
/* The driver label comes after the prefix. */
|
|
label = key + strlen(driver_prefix);
|
|
|
|
/* A driver is (re)started. */
|
|
eth_check_driver(label, owner_endpoint);
|
|
}
|
|
|
|
if(r != ENOENT)
|
|
printf("inet: ds_event: ds_check failed: %d\n", r);
|
|
}
|
|
|
|
PUBLIC void panic0(file, line)
|
|
char *file;
|
|
int line;
|
|
{
|
|
printf("panic at %s, %d: ", file, line);
|
|
}
|
|
|
|
PUBLIC void inet_panic()
|
|
{
|
|
printf("\ninet stacktrace: ");
|
|
util_stacktrace();
|
|
(panic)("aborted due to a panic");
|
|
for(;;);
|
|
}
|
|
|
|
#if !NDEBUG
|
|
PUBLIC void bad_assertion(file, line, what)
|
|
char *file;
|
|
int line;
|
|
char *what;
|
|
{
|
|
panic0(file, line);
|
|
printf("assertion \"%s\" failed", what);
|
|
panic();
|
|
}
|
|
|
|
|
|
PUBLIC void bad_compare(file, line, lhs, what, rhs)
|
|
char *file;
|
|
int line;
|
|
int lhs;
|
|
char *what;
|
|
int rhs;
|
|
{
|
|
panic0(file, line);
|
|
printf("compare (%d) %s (%d) failed", lhs, what, rhs);
|
|
panic();
|
|
}
|
|
#endif /* !NDEBUG */
|
|
|
|
/*
|
|
* $PchId: inet.c,v 1.23 2005/06/28 14:27:22 philip Exp $
|
|
*/
|