minix/servers/inet/generic/ip.c

494 lines
10 KiB
C
Raw Normal View History

2005-04-21 16:53:53 +02:00
/*
ip.c
Copyright 1995 Philip Homburg
*/
#include "inet.h"
#include "buf.h"
#include "event.h"
#include "type.h"
#include "arp.h"
#include "assert.h"
#include "clock.h"
#include "eth.h"
#include "icmp.h"
#include "icmp_lib.h"
#include "io.h"
#include "ip.h"
#include "ip_int.h"
#include "ipr.h"
#include "sr.h"
THIS_FILE
2012-03-25 20:25:53 +02:00
static void ip_close ARGS(( int fd ));
static int ip_cancel ARGS(( int fd, int which_operation ));
static int ip_select ARGS(( int fd, unsigned operations ));
2005-04-21 16:53:53 +02:00
2012-03-25 20:25:53 +02:00
static void ip_buffree ARGS(( int priority ));
2005-04-21 16:53:53 +02:00
#ifdef BUF_CONSISTENCY_CHECK
2012-03-25 20:25:53 +02:00
static void ip_bufcheck ARGS(( void ));
2005-04-21 16:53:53 +02:00
#endif
2012-03-25 20:25:53 +02:00
static void ip_bad_callback ARGS(( struct ip_port *ip_port ));
2005-04-21 16:53:53 +02:00
2012-03-25 20:25:53 +02:00
ip_port_t *ip_port_table;
ip_fd_t ip_fd_table[IP_FD_NR];
ip_ass_t ip_ass_table[IP_ASS_NR];
2005-04-21 16:53:53 +02:00
2012-03-25 20:25:53 +02:00
void ip_prep()
2005-04-21 16:53:53 +02:00
{
ip_port_table= alloc(ip_conf_nr * sizeof(ip_port_table[0]));
icmp_prep();
}
2012-03-25 20:25:53 +02:00
void ip_init()
2005-04-21 16:53:53 +02:00
{
int i, j, result;
ip_ass_t *ip_ass;
ip_fd_t *ip_fd;
ip_port_t *ip_port;
struct ip_conf *icp;
assert (BUF_S >= sizeof(struct nwio_ethopt));
assert (BUF_S >= IP_MAX_HDR_SIZE + ETH_HDR_SIZE);
assert (BUF_S >= sizeof(nwio_ipopt_t));
assert (BUF_S >= sizeof(nwio_route_t));
for (i=0, ip_ass= ip_ass_table; i<IP_ASS_NR; i++, ip_ass++)
{
ip_ass->ia_frags= 0;
ip_ass->ia_first_time= 0;
ip_ass->ia_port= 0;
}
for (i=0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
{
ip_fd->if_flags= IFF_EMPTY;
ip_fd->if_rdbuf_head= 0;
}
for (i=0, ip_port= ip_port_table, icp= ip_conf;
i<ip_conf_nr; i++, ip_port++, icp++)
{
ip_port->ip_port= i;
ip_port->ip_flags= IPF_EMPTY;
ip_port->ip_dev_main= (ip_dev_t)ip_bad_callback;
ip_port->ip_dev_set_ipaddr= (ip_dev_t)ip_bad_callback;
ip_port->ip_dev_send= (ip_dev_send_t)ip_bad_callback;
ip_port->ip_dl_type= icp->ic_devtype;
ip_port->ip_mtu= IP_DEF_MTU;
ip_port->ip_mtu_max= IP_MAX_PACKSIZE;
2005-04-21 16:53:53 +02:00
switch(ip_port->ip_dl_type)
{
case IPDL_ETH:
ip_port->ip_dl.dl_eth.de_port= icp->ic_port;
result= ipeth_init(ip_port);
if (result == -1)
continue;
assert(result == NW_OK);
break;
case IPDL_PSIP:
ip_port->ip_dl.dl_ps.ps_port= icp->ic_port;
result= ipps_init(ip_port);
if (result == -1)
continue;
assert(result == NW_OK);
break;
default:
ip_panic(( "unknown ip_dl_type %d",
ip_port->ip_dl_type ));
break;
2005-04-21 16:53:53 +02:00
}
ip_port->ip_loopb_head= NULL;
ip_port->ip_loopb_tail= NULL;
ev_init(&ip_port->ip_loopb_event);
ip_port->ip_routeq_head= NULL;
ip_port->ip_routeq_tail= NULL;
ev_init(&ip_port->ip_routeq_event);
2005-04-21 16:53:53 +02:00
ip_port->ip_flags |= IPF_CONFIGURED;
ip_port->ip_proto_any= NULL;
for (j= 0; j<IP_PROTO_HASH_NR; j++)
ip_port->ip_proto[j]= NULL;
}
#ifndef BUF_CONSISTENCY_CHECK
bf_logon(ip_buffree);
#else
bf_logon(ip_buffree, ip_bufcheck);
#endif
icmp_init();
ipr_init();
for (i=0, ip_port= ip_port_table; i<ip_conf_nr; i++, ip_port++)
{
if (!(ip_port->ip_flags & IPF_CONFIGURED))
continue;
ip_port->ip_frame_id= (u16_t)get_time();
sr_add_minor(if2minor(ip_conf[i].ic_ifno, IP_DEV_OFF),
i, ip_open, ip_close, ip_read,
ip_write, ip_ioctl, ip_cancel, ip_select);
2005-04-21 16:53:53 +02:00
(*ip_port->ip_dev_main)(ip_port);
}
}
2012-03-25 20:25:53 +02:00
static int ip_cancel (fd, which_operation)
2005-04-21 16:53:53 +02:00
int fd;
int which_operation;
{
ip_fd_t *ip_fd;
acc_t *repl_res;
int result;
ip_fd= &ip_fd_table[fd];
switch (which_operation)
{
case SR_CANCEL_IOCTL:
assert (ip_fd->if_flags & IFF_IOCTL_IP);
ip_fd->if_flags &= ~IFF_IOCTL_IP;
2005-04-21 16:53:53 +02:00
repl_res= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
(size_t)EINTR, (size_t)0, TRUE);
assert (!repl_res);
break;
case SR_CANCEL_READ:
assert (ip_fd->if_flags & IFF_READ_IP);
ip_fd->if_flags &= ~IFF_READ_IP;
result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
(size_t)EINTR, (acc_t *)0, FALSE);
assert (!result);
break;
#if 0
case SR_CANCEL_WRITE:
assert(0);
assert (ip_fd->if_flags & IFF_WRITE_MASK);
ip_fd->if_flags &= ~IFF_WRITE_MASK;
repl_res= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
(size_t)EINTR, (size_t)0, FALSE);
assert (!repl_res);
break;
#endif
default:
ip_panic(( "unknown cancel request" ));
break;
2005-04-21 16:53:53 +02:00
}
return NW_OK;
}
2012-03-25 20:25:53 +02:00
static int ip_select(fd, operations)
int fd;
unsigned operations;
{
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.
2010-05-18 00:22:53 +02:00
unsigned resops;
ip_fd_t *ip_fd;
ip_fd= &ip_fd_table[fd];
assert (ip_fd->if_flags & IFF_INUSE);
resops= 0;
if (operations & SR_SELECT_READ)
{
if (ip_sel_read(ip_fd))
resops |= SR_SELECT_READ;
else if (!(operations & SR_SELECT_POLL))
ip_fd->if_flags |= IFF_SEL_READ;
}
if (operations & SR_SELECT_WRITE)
{
/* Should handle special case when the interface is down */
resops |= SR_SELECT_WRITE;
}
if (operations & SR_SELECT_EXCEPTION)
{
printf("ip_select: not implemented for exceptions\n");
}
return resops;
}
2005-04-21 16:53:53 +02:00
2012-03-25 20:25:53 +02:00
int ip_open (port, srfd, get_userdata, put_userdata, put_pkt,
select_res)
2005-04-21 16:53:53 +02:00
int port;
int srfd;
get_userdata_t get_userdata;
put_userdata_t put_userdata;
put_pkt_t put_pkt;
select_res_t select_res;
2005-04-21 16:53:53 +02:00
{
int i;
ip_fd_t *ip_fd;
ip_port_t *ip_port;
ip_port= &ip_port_table[port];
if (!(ip_port->ip_flags & IPF_CONFIGURED))
return ENXIO;
for (i=0; i<IP_FD_NR && (ip_fd_table[i].if_flags & IFF_INUSE);
i++);
if (i>=IP_FD_NR)
{
DBLOCK(1, printf("out of fds\n"));
return EAGAIN;
}
ip_fd= &ip_fd_table[i];
ip_fd->if_flags= IFF_INUSE;
ip_fd->if_ipopt.nwio_flags= NWIO_DEFAULT;
ip_fd->if_ipopt.nwio_tos= 0;
ip_fd->if_ipopt.nwio_df= FALSE;
ip_fd->if_ipopt.nwio_ttl= 255;
ip_fd->if_ipopt.nwio_hdropt.iho_opt_siz= 0;
ip_fd->if_port= ip_port;
ip_fd->if_srfd= srfd;
assert(ip_fd->if_rdbuf_head == NULL);
ip_fd->if_get_userdata= get_userdata;
ip_fd->if_put_userdata= put_userdata;
ip_fd->if_put_pkt= put_pkt;
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.
2010-05-18 00:22:53 +02:00
ip_fd->if_select_res= select_res;
2005-04-21 16:53:53 +02:00
return i;
}
2012-03-25 20:25:53 +02:00
static void ip_close (fd)
2005-04-21 16:53:53 +02:00
int fd;
{
ip_fd_t *ip_fd;
acc_t *pack;
ip_fd= &ip_fd_table[fd];
assert ((ip_fd->if_flags & IFF_INUSE) &&
!(ip_fd->if_flags & IFF_BUSY));
if (ip_fd->if_flags & IFF_OPTSET)
ip_unhash_proto(ip_fd);
while (ip_fd->if_rdbuf_head)
{
pack= ip_fd->if_rdbuf_head;
ip_fd->if_rdbuf_head= pack->acc_ext_link;
bf_afree(pack);
}
ip_fd->if_flags= IFF_EMPTY;
}
2012-03-25 20:25:53 +02:00
static void ip_buffree(priority)
2005-04-21 16:53:53 +02:00
int priority;
{
int i;
ip_port_t *ip_port;
ip_fd_t *ip_fd;
ip_ass_t *ip_ass;
acc_t *pack, *next_pack;
for (i= 0, ip_port= ip_port_table; i<ip_conf_nr; i++, ip_port++)
{
if (ip_port->ip_dl_type == IPDL_ETH)
{
/* Can't free de_frame.
* bf_check_acc(ip_port->ip_dl.dl_eth.de_frame);
*/
if (priority == IP_PRI_PORTBUFS)
{
next_pack= ip_port->ip_dl.dl_eth.de_arp_head;
while(next_pack != NULL)
{
pack= next_pack;
next_pack= pack->acc_ext_link;
bf_afree(pack);
}
ip_port->ip_dl.dl_eth.de_arp_head= next_pack;
next_pack= ip_port->ip_dl.dl_eth.de_q_head;
while(next_pack != NULL)
{
pack= next_pack;
next_pack= pack->acc_ext_link;
bf_afree(pack);
}
ip_port->ip_dl.dl_eth.de_q_head= next_pack;
}
}
else if (ip_port->ip_dl_type == IPDL_PSIP)
{
if (priority == IP_PRI_PORTBUFS)
{
next_pack= ip_port->ip_dl.dl_ps.ps_send_head;
while (next_pack != NULL)
2005-04-21 16:53:53 +02:00
{
pack= next_pack;
next_pack= pack->acc_ext_link;
bf_afree(pack);
}
ip_port->ip_dl.dl_ps.ps_send_head= next_pack;
}
}
if (priority == IP_PRI_PORTBUFS)
{
next_pack= ip_port->ip_loopb_head;
while(next_pack && next_pack->acc_ext_link)
{
pack= next_pack;
next_pack= pack->acc_ext_link;
bf_afree(pack);
}
if (next_pack)
{
if (ev_in_queue(&ip_port->ip_loopb_event))
{
#if DEBUG
2005-04-21 16:53:53 +02:00
printf(
"not freeing ip_loopb_head, ip_loopb_event enqueued\n");
#endif
}
else
{
bf_afree(next_pack);
next_pack= NULL;
}
}
ip_port->ip_loopb_head= next_pack;
next_pack= ip_port->ip_routeq_head;
while(next_pack && next_pack->acc_ext_link)
{
pack= next_pack;
next_pack= pack->acc_ext_link;
bf_afree(pack);
}
if (next_pack)
{
if (ev_in_queue(&ip_port->ip_routeq_event))
{
#if DEBUG
printf(
"not freeing ip_loopb_head, ip_routeq_event enqueued\n");
#endif
}
else
{
bf_afree(next_pack);
next_pack= NULL;
}
}
ip_port->ip_routeq_head= next_pack;
2005-04-21 16:53:53 +02:00
}
}
if (priority == IP_PRI_FDBUFS_EXTRA)
{
for (i= 0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
{
while (ip_fd->if_rdbuf_head &&
ip_fd->if_rdbuf_head->acc_ext_link)
{
pack= ip_fd->if_rdbuf_head;
ip_fd->if_rdbuf_head= pack->acc_ext_link;
bf_afree(pack);
}
}
}
if (priority == IP_PRI_FDBUFS)
{
for (i= 0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
{
while (ip_fd->if_rdbuf_head)
{
pack= ip_fd->if_rdbuf_head;
ip_fd->if_rdbuf_head= pack->acc_ext_link;
bf_afree(pack);
}
}
}
if (priority == IP_PRI_ASSBUFS)
{
for (i= 0, ip_ass= ip_ass_table; i<IP_ASS_NR; i++, ip_ass++)
{
while(ip_ass->ia_frags != NULL)
{
pack= ip_ass->ia_frags;
ip_ass->ia_frags= pack->acc_ext_link;
bf_afree(pack);
}
ip_ass->ia_first_time= 0;
}
}
}
#ifdef BUF_CONSISTENCY_CHECK
2012-03-25 20:25:53 +02:00
static void ip_bufcheck()
2005-04-21 16:53:53 +02:00
{
int i;
ip_port_t *ip_port;
ip_fd_t *ip_fd;
ip_ass_t *ip_ass;
acc_t *pack;
for (i= 0, ip_port= ip_port_table; i<ip_conf_nr; i++, ip_port++)
{
if (ip_port->ip_dl_type == IPDL_ETH)
{
bf_check_acc(ip_port->ip_dl.dl_eth.de_frame);
for (pack= ip_port->ip_dl.dl_eth.de_q_head; pack;
pack= pack->acc_ext_link)
{
bf_check_acc(pack);
}
for (pack= ip_port->ip_dl.dl_eth.de_arp_head; pack;
pack= pack->acc_ext_link)
{
bf_check_acc(pack);
}
}
else if (ip_port->ip_dl_type == IPDL_PSIP)
{
for (pack= ip_port->ip_dl.dl_ps.ps_send_head; pack;
pack= pack->acc_ext_link)
{
bf_check_acc(pack);
}
}
for (pack= ip_port->ip_loopb_head; pack;
pack= pack->acc_ext_link)
{
bf_check_acc(pack);
}
for (pack= ip_port->ip_routeq_head; pack;
pack= pack->acc_ext_link)
{
bf_check_acc(pack);
}
2005-04-21 16:53:53 +02:00
}
for (i= 0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
{
for (pack= ip_fd->if_rdbuf_head; pack;
pack= pack->acc_ext_link)
{
bf_check_acc(pack);
}
}
for (i= 0, ip_ass= ip_ass_table; i<IP_ASS_NR; i++, ip_ass++)
{
for (pack= ip_ass->ia_frags; pack; pack= pack->acc_ext_link)
bf_check_acc(pack);
}
}
#endif /* BUF_CONSISTENCY_CHECK */
2012-03-25 20:25:53 +02:00
static void ip_bad_callback(ip_port)
2005-04-21 16:53:53 +02:00
struct ip_port *ip_port;
{
ip_panic(( "no callback filled in for port %d", ip_port->ip_port ));
}
/*
* $PchId: ip.c,v 1.19 2005/06/28 14:17:40 philip Exp $
2005-04-21 16:53:53 +02:00
*/