2005-04-21 16:53:53 +02:00
|
|
|
/*
|
|
|
|
ip_ioctl.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 "icmp_lib.h"
|
|
|
|
#include "ip.h"
|
|
|
|
#include "ip_int.h"
|
|
|
|
#include "ipr.h"
|
|
|
|
|
|
|
|
THIS_FILE
|
|
|
|
|
|
|
|
FORWARD int ip_checkopt ARGS(( ip_fd_t *ip_fd ));
|
|
|
|
FORWARD void reply_thr_get ARGS(( ip_fd_t *ip_fd, size_t
|
|
|
|
reply, int for_ioctl ));
|
2005-06-28 17:19:58 +02:00
|
|
|
FORWARD void report_addr ARGS(( ip_port_t *ip_port ));
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
PUBLIC int ip_ioctl (fd, req)
|
|
|
|
int fd;
|
|
|
|
ioreq_t req;
|
|
|
|
{
|
|
|
|
ip_fd_t *ip_fd;
|
|
|
|
ip_port_t *ip_port;
|
|
|
|
nwio_ipopt_t *ipopt;
|
|
|
|
nwio_ipopt_t oldopt, newopt;
|
2005-06-28 17:19:58 +02:00
|
|
|
nwio_ipconf2_t *ipconf2;
|
2005-04-21 16:53:53 +02:00
|
|
|
nwio_ipconf_t *ipconf;
|
|
|
|
nwio_route_t *route_ent;
|
|
|
|
acc_t *data;
|
|
|
|
int result;
|
|
|
|
unsigned int new_en_flags, new_di_flags,
|
|
|
|
old_en_flags, old_di_flags;
|
|
|
|
unsigned long new_flags;
|
2005-06-28 17:19:58 +02:00
|
|
|
int ent_no, r;
|
|
|
|
nwio_ipconf_t ipconf_var;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
assert (fd>=0 && fd<=IP_FD_NR);
|
|
|
|
ip_fd= &ip_fd_table[fd];
|
|
|
|
|
|
|
|
assert (ip_fd->if_flags & IFF_INUSE);
|
|
|
|
|
|
|
|
switch (req)
|
|
|
|
{
|
|
|
|
case NWIOSIPOPT:
|
2005-06-28 17:19:58 +02:00
|
|
|
ip_port= ip_fd->if_port;
|
|
|
|
|
|
|
|
if (!(ip_port->ip_flags & IPF_IPADDRSET))
|
|
|
|
{
|
|
|
|
ip_fd->if_ioctl= NWIOSIPOPT;
|
|
|
|
ip_fd->if_flags |= IFF_IOCTL_IP;
|
|
|
|
return NW_SUSPEND;
|
|
|
|
}
|
|
|
|
ip_fd->if_flags &= ~IFF_IOCTL_IP;
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd, 0,
|
|
|
|
sizeof(nwio_ipopt_t), TRUE);
|
|
|
|
|
|
|
|
data= bf_packIffLess (data, sizeof(nwio_ipopt_t));
|
|
|
|
assert (data->acc_length == sizeof(nwio_ipopt_t));
|
|
|
|
|
|
|
|
ipopt= (nwio_ipopt_t *)ptr2acc_data(data);
|
|
|
|
oldopt= ip_fd->if_ipopt;
|
|
|
|
newopt= *ipopt;
|
|
|
|
|
|
|
|
old_en_flags= oldopt.nwio_flags & 0xffff;
|
|
|
|
old_di_flags= (oldopt.nwio_flags >> 16) & 0xffff;
|
|
|
|
new_en_flags= newopt.nwio_flags & 0xffff;
|
|
|
|
new_di_flags= (newopt.nwio_flags >> 16) & 0xffff;
|
|
|
|
if (new_en_flags & new_di_flags)
|
|
|
|
{
|
|
|
|
bf_afree(data);
|
|
|
|
reply_thr_get (ip_fd, EBADMODE, TRUE);
|
|
|
|
return NW_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NWIO_ACC_MASK */
|
|
|
|
if (new_di_flags & NWIO_ACC_MASK)
|
|
|
|
{
|
|
|
|
bf_afree(data);
|
|
|
|
reply_thr_get (ip_fd, EBADMODE, TRUE);
|
|
|
|
return NW_OK;
|
|
|
|
/* access modes can't be disable */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(new_en_flags & NWIO_ACC_MASK))
|
|
|
|
new_en_flags |= (old_en_flags & NWIO_ACC_MASK);
|
|
|
|
|
|
|
|
/* NWIO_LOC_MASK */
|
|
|
|
if (!((new_en_flags|new_di_flags) & NWIO_LOC_MASK))
|
|
|
|
{
|
|
|
|
new_en_flags |= (old_en_flags & NWIO_LOC_MASK);
|
|
|
|
new_di_flags |= (old_di_flags & NWIO_LOC_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NWIO_BROAD_MASK */
|
|
|
|
if (!((new_en_flags|new_di_flags) & NWIO_BROAD_MASK))
|
|
|
|
{
|
|
|
|
new_en_flags |= (old_en_flags & NWIO_BROAD_MASK);
|
|
|
|
new_di_flags |= (old_di_flags & NWIO_BROAD_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NWIO_REM_MASK */
|
|
|
|
if (!((new_en_flags|new_di_flags) & NWIO_REM_MASK))
|
|
|
|
{
|
|
|
|
new_en_flags |= (old_en_flags & NWIO_REM_MASK);
|
|
|
|
new_di_flags |= (old_di_flags & NWIO_REM_MASK);
|
|
|
|
newopt.nwio_rem= oldopt.nwio_rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NWIO_PROTO_MASK */
|
|
|
|
if (!((new_en_flags|new_di_flags) & NWIO_PROTO_MASK))
|
|
|
|
{
|
|
|
|
new_en_flags |= (old_en_flags & NWIO_PROTO_MASK);
|
|
|
|
new_di_flags |= (old_di_flags & NWIO_PROTO_MASK);
|
|
|
|
newopt.nwio_proto= oldopt.nwio_proto;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NWIO_HDR_O_MASK */
|
|
|
|
if (!((new_en_flags|new_di_flags) & NWIO_HDR_O_MASK))
|
|
|
|
{
|
|
|
|
new_en_flags |= (old_en_flags & NWIO_HDR_O_MASK);
|
|
|
|
new_di_flags |= (old_di_flags & NWIO_HDR_O_MASK);
|
|
|
|
newopt.nwio_tos= oldopt.nwio_tos;
|
|
|
|
newopt.nwio_ttl= oldopt.nwio_ttl;
|
|
|
|
newopt.nwio_df= oldopt.nwio_df;
|
|
|
|
newopt.nwio_hdropt= oldopt.nwio_hdropt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NWIO_RW_MASK */
|
|
|
|
if (!((new_en_flags|new_di_flags) & NWIO_RW_MASK))
|
|
|
|
{
|
|
|
|
new_en_flags |= (old_en_flags & NWIO_RW_MASK);
|
|
|
|
new_di_flags |= (old_di_flags & NWIO_RW_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
new_flags= ((unsigned long)new_di_flags << 16) | new_en_flags;
|
|
|
|
|
|
|
|
if ((new_flags & NWIO_RWDATONLY) && (new_flags &
|
|
|
|
(NWIO_REMANY|NWIO_PROTOANY|NWIO_HDR_O_ANY)))
|
|
|
|
{
|
|
|
|
bf_afree(data);
|
|
|
|
reply_thr_get(ip_fd, EBADMODE, TRUE);
|
|
|
|
return NW_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ip_fd->if_flags & IFF_OPTSET)
|
|
|
|
ip_unhash_proto(ip_fd);
|
|
|
|
|
|
|
|
newopt.nwio_flags= new_flags;
|
|
|
|
ip_fd->if_ipopt= newopt;
|
|
|
|
|
|
|
|
result= ip_checkopt(ip_fd);
|
|
|
|
|
|
|
|
if (result<0)
|
|
|
|
ip_fd->if_ipopt= oldopt;
|
|
|
|
|
|
|
|
bf_afree(data);
|
|
|
|
reply_thr_get (ip_fd, result, TRUE);
|
|
|
|
return NW_OK;
|
|
|
|
|
|
|
|
case NWIOGIPOPT:
|
|
|
|
data= bf_memreq(sizeof(nwio_ipopt_t));
|
|
|
|
|
|
|
|
ipopt= (nwio_ipopt_t *)ptr2acc_data(data);
|
|
|
|
|
|
|
|
*ipopt= ip_fd->if_ipopt;
|
|
|
|
|
|
|
|
result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd, 0, data,
|
|
|
|
TRUE);
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, result,
|
|
|
|
(acc_t *)0, TRUE);
|
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
case NWIOSIPCONF2:
|
2005-04-21 16:53:53 +02:00
|
|
|
case NWIOSIPCONF:
|
|
|
|
ip_port= ip_fd->if_port;
|
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
if (req == NWIOSIPCONF2)
|
2005-04-21 16:53:53 +02:00
|
|
|
{
|
2005-06-28 17:19:58 +02:00
|
|
|
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd, 0,
|
|
|
|
sizeof(*ipconf2), TRUE);
|
|
|
|
data= bf_packIffLess (data, sizeof(*ipconf2));
|
|
|
|
assert (data->acc_length == sizeof(*ipconf2));
|
|
|
|
|
|
|
|
ipconf2= (nwio_ipconf2_t *)ptr2acc_data(data);
|
|
|
|
|
|
|
|
ipconf= &ipconf_var;
|
|
|
|
ipconf->nwic_flags= ipconf2->nwic_flags;
|
|
|
|
ipconf->nwic_ipaddr= ipconf2->nwic_ipaddr;
|
|
|
|
ipconf->nwic_netmask= ipconf2->nwic_netmask;
|
|
|
|
ipconf->nwic_flags &= ~NWIC_MTU_SET;
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
2005-06-28 17:19:58 +02:00
|
|
|
else
|
2005-04-21 16:53:53 +02:00
|
|
|
{
|
2005-06-28 17:19:58 +02:00
|
|
|
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd, 0,
|
|
|
|
sizeof(*ipconf), TRUE);
|
|
|
|
data= bf_packIffLess (data, sizeof(*ipconf));
|
|
|
|
assert (data->acc_length == sizeof(*ipconf));
|
|
|
|
|
|
|
|
ipconf= (nwio_ipconf_t *)ptr2acc_data(data);
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
2005-06-28 17:19:58 +02:00
|
|
|
r= ip_setconf(ip_port-ip_port_table, ipconf);
|
|
|
|
bf_afree(data);
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd-> if_srfd, r,
|
|
|
|
(acc_t *)0, TRUE);
|
|
|
|
|
|
|
|
case NWIOGIPCONF2:
|
|
|
|
ip_port= ip_fd->if_port;
|
|
|
|
|
|
|
|
if (!(ip_port->ip_flags & IPF_IPADDRSET))
|
2005-04-21 16:53:53 +02:00
|
|
|
{
|
2005-06-28 17:19:58 +02:00
|
|
|
ip_fd->if_ioctl= NWIOGIPCONF2;
|
|
|
|
ip_fd->if_flags |= IFF_IOCTL_IP;
|
|
|
|
return NW_SUSPEND;
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
2005-06-28 17:19:58 +02:00
|
|
|
ip_fd->if_flags &= ~IFF_IOCTL_IP;
|
|
|
|
data= bf_memreq(sizeof(nwio_ipconf_t));
|
|
|
|
ipconf2= (nwio_ipconf2_t *)ptr2acc_data(data);
|
|
|
|
ipconf2->nwic_flags= NWIC_IPADDR_SET;
|
|
|
|
ipconf2->nwic_ipaddr= ip_port->ip_ipaddr;
|
|
|
|
ipconf2->nwic_netmask= ip_port->ip_subnetmask;
|
|
|
|
if (ip_port->ip_flags & IPF_NETMASKSET)
|
|
|
|
ipconf2->nwic_flags |= NWIC_NETMASK_SET;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd, 0, data,
|
|
|
|
TRUE);
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, result,
|
2005-04-21 16:53:53 +02:00
|
|
|
(acc_t *)0, TRUE);
|
2005-06-28 17:19:58 +02:00
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
case NWIOGIPCONF:
|
|
|
|
ip_port= ip_fd->if_port;
|
|
|
|
|
|
|
|
if (!(ip_port->ip_flags & IPF_IPADDRSET))
|
|
|
|
{
|
2005-06-28 17:19:58 +02:00
|
|
|
ip_fd->if_ioctl= NWIOGIPCONF;
|
|
|
|
ip_fd->if_flags |= IFF_IOCTL_IP;
|
2005-04-21 16:53:53 +02:00
|
|
|
return NW_SUSPEND;
|
|
|
|
}
|
2005-06-28 17:19:58 +02:00
|
|
|
ip_fd->if_flags &= ~IFF_IOCTL_IP;
|
|
|
|
data= bf_memreq(sizeof(*ipconf));
|
2005-04-21 16:53:53 +02:00
|
|
|
ipconf= (nwio_ipconf_t *)ptr2acc_data(data);
|
|
|
|
ipconf->nwic_flags= NWIC_IPADDR_SET;
|
|
|
|
ipconf->nwic_ipaddr= ip_port->ip_ipaddr;
|
|
|
|
ipconf->nwic_netmask= ip_port->ip_subnetmask;
|
|
|
|
if (ip_port->ip_flags & IPF_NETMASKSET)
|
|
|
|
ipconf->nwic_flags |= NWIC_NETMASK_SET;
|
2005-06-28 17:19:58 +02:00
|
|
|
ipconf->nwic_mtu= ip_port->ip_mtu;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd, 0, data,
|
|
|
|
TRUE);
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, result,
|
|
|
|
(acc_t *)0, TRUE);
|
2005-06-28 17:19:58 +02:00
|
|
|
|
|
|
|
case NWIOGIPOROUTE:
|
2005-04-21 16:53:53 +02:00
|
|
|
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
|
|
|
|
0, sizeof(nwio_route_t), TRUE);
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
EFAULT, NULL, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
data= bf_packIffLess (data, sizeof(nwio_route_t) );
|
|
|
|
route_ent= (nwio_route_t *)ptr2acc_data(data);
|
|
|
|
ent_no= route_ent->nwr_ent_no;
|
|
|
|
bf_afree(data);
|
|
|
|
|
|
|
|
data= bf_memreq(sizeof(nwio_route_t));
|
|
|
|
route_ent= (nwio_route_t *)ptr2acc_data(data);
|
2005-06-28 17:19:58 +02:00
|
|
|
result= ipr_get_oroute(ent_no, route_ent);
|
2005-04-21 16:53:53 +02:00
|
|
|
if (result < 0)
|
|
|
|
bf_afree(data);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(result == NW_OK);
|
|
|
|
result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd, 0,
|
|
|
|
data, TRUE);
|
|
|
|
}
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
result, (acc_t *)0, TRUE);
|
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
case NWIOSIPOROUTE:
|
2005-04-21 16:53:53 +02:00
|
|
|
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
|
|
|
|
0, sizeof(nwio_route_t), TRUE);
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
EFAULT, NULL, TRUE);
|
|
|
|
}
|
2005-06-28 17:19:58 +02:00
|
|
|
if (!(ip_fd->if_port->ip_flags & IPF_IPADDRSET))
|
|
|
|
{
|
|
|
|
/* Interface is down, no changes allowed */
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
2009-11-28 14:18:33 +01:00
|
|
|
ENETDOWN, NULL, TRUE);
|
2005-06-28 17:19:58 +02:00
|
|
|
}
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
data= bf_packIffLess (data, sizeof(nwio_route_t) );
|
|
|
|
route_ent= (nwio_route_t *)ptr2acc_data(data);
|
2005-06-28 17:19:58 +02:00
|
|
|
result= ipr_add_oroute(ip_fd->if_port-ip_port_table,
|
|
|
|
route_ent->nwr_dest, route_ent->nwr_netmask,
|
|
|
|
route_ent->nwr_gateway, (time_t)0,
|
|
|
|
route_ent->nwr_dist, route_ent->nwr_mtu,
|
|
|
|
!!(route_ent->nwr_flags & NWRF_STATIC),
|
|
|
|
route_ent->nwr_pref, NULL);
|
|
|
|
bf_afree(data);
|
|
|
|
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
result, (acc_t *)0, TRUE);
|
|
|
|
|
|
|
|
case NWIODIPOROUTE:
|
|
|
|
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
|
|
|
|
0, sizeof(nwio_route_t), TRUE);
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
EFAULT, NULL, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
data= bf_packIffLess (data, sizeof(nwio_route_t) );
|
|
|
|
route_ent= (nwio_route_t *)ptr2acc_data(data);
|
|
|
|
result= ipr_del_oroute(ip_fd->if_port-ip_port_table,
|
2005-04-21 16:53:53 +02:00
|
|
|
route_ent->nwr_dest, route_ent->nwr_netmask,
|
|
|
|
route_ent->nwr_gateway,
|
2005-06-28 17:19:58 +02:00
|
|
|
!!(route_ent->nwr_flags & NWRF_STATIC));
|
2005-04-21 16:53:53 +02:00
|
|
|
bf_afree(data);
|
|
|
|
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
result, (acc_t *)0, TRUE);
|
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
case NWIOGIPIROUTE:
|
2005-04-21 16:53:53 +02:00
|
|
|
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
|
|
|
|
0, sizeof(nwio_route_t), TRUE);
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
EFAULT, NULL, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
data= bf_packIffLess (data, sizeof(nwio_route_t) );
|
|
|
|
route_ent= (nwio_route_t *)ptr2acc_data(data);
|
|
|
|
ent_no= route_ent->nwr_ent_no;
|
|
|
|
bf_afree(data);
|
|
|
|
|
|
|
|
data= bf_memreq(sizeof(nwio_route_t));
|
|
|
|
route_ent= (nwio_route_t *)ptr2acc_data(data);
|
2005-06-28 17:19:58 +02:00
|
|
|
result= ipr_get_iroute(ent_no, route_ent);
|
2005-04-21 16:53:53 +02:00
|
|
|
if (result < 0)
|
|
|
|
bf_afree(data);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(result == NW_OK);
|
|
|
|
result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd, 0,
|
|
|
|
data, TRUE);
|
|
|
|
}
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
result, (acc_t *)0, TRUE);
|
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
case NWIOSIPIROUTE:
|
2005-04-21 16:53:53 +02:00
|
|
|
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
|
|
|
|
0, sizeof(nwio_route_t), TRUE);
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
EFAULT, NULL, TRUE);
|
|
|
|
}
|
2005-06-28 17:19:58 +02:00
|
|
|
if (!(ip_fd->if_port->ip_flags & IPF_IPADDRSET))
|
|
|
|
{
|
|
|
|
/* Interface is down, no changes allowed */
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
2009-11-28 14:18:33 +01:00
|
|
|
ENETDOWN, NULL, TRUE);
|
2005-06-28 17:19:58 +02:00
|
|
|
}
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
data= bf_packIffLess (data, sizeof(nwio_route_t) );
|
|
|
|
route_ent= (nwio_route_t *)ptr2acc_data(data);
|
2005-06-28 17:19:58 +02:00
|
|
|
result= ipr_add_iroute(ip_fd->if_port-ip_port_table,
|
2005-04-21 16:53:53 +02:00
|
|
|
route_ent->nwr_dest, route_ent->nwr_netmask,
|
|
|
|
route_ent->nwr_gateway,
|
|
|
|
(route_ent->nwr_flags & NWRF_UNREACHABLE) ?
|
|
|
|
IRTD_UNREACHABLE : route_ent->nwr_dist,
|
2005-06-28 17:19:58 +02:00
|
|
|
route_ent->nwr_mtu,
|
|
|
|
!!(route_ent->nwr_flags & NWRF_STATIC), NULL);
|
2005-04-21 16:53:53 +02:00
|
|
|
bf_afree(data);
|
|
|
|
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
result, (acc_t *)0, TRUE);
|
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
case NWIODIPIROUTE:
|
2005-04-21 16:53:53 +02:00
|
|
|
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
|
|
|
|
0, sizeof(nwio_route_t), TRUE);
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
EFAULT, NULL, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
data= bf_packIffLess (data, sizeof(nwio_route_t) );
|
|
|
|
route_ent= (nwio_route_t *)ptr2acc_data(data);
|
2005-06-28 17:19:58 +02:00
|
|
|
result= ipr_del_iroute(ip_fd->if_port-ip_port_table,
|
2005-04-21 16:53:53 +02:00
|
|
|
route_ent->nwr_dest, route_ent->nwr_netmask,
|
2005-06-28 17:19:58 +02:00
|
|
|
route_ent->nwr_gateway,
|
|
|
|
!!(route_ent->nwr_flags & NWRF_STATIC));
|
2005-04-21 16:53:53 +02:00
|
|
|
bf_afree(data);
|
|
|
|
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
result, (acc_t *)0, TRUE);
|
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
/* The following ARP ioctls are only valid if the
|
|
|
|
* underlying device is an ethernet.
|
|
|
|
*/
|
|
|
|
case NWIOARPGIP:
|
|
|
|
case NWIOARPGNEXT:
|
|
|
|
case NWIOARPSIP:
|
|
|
|
case NWIOARPDIP:
|
|
|
|
ip_port= ip_fd->if_port;
|
|
|
|
|
|
|
|
if (ip_port->ip_dl_type != IPDL_ETH)
|
|
|
|
{
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
|
|
|
|
EBADIOCTL, (acc_t *)0, TRUE);
|
|
|
|
}
|
2007-04-23 16:49:20 +02:00
|
|
|
|
|
|
|
if (!(ip_port->ip_flags & IPF_IPADDRSET))
|
|
|
|
{
|
|
|
|
ip_fd->if_ioctl= req;
|
|
|
|
ip_fd->if_flags |= IFF_IOCTL_IP;
|
|
|
|
printf("ip_ioctl: suspending ARP request\n");
|
|
|
|
return NW_SUSPEND;
|
|
|
|
}
|
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
result= arp_ioctl(ip_port->ip_dl.dl_eth.de_port,
|
|
|
|
ip_fd->if_srfd, req, ip_fd->if_get_userdata,
|
|
|
|
ip_fd->if_put_userdata);
|
|
|
|
assert (result != SUSPEND);
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, result,
|
|
|
|
(acc_t *)0, TRUE);
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2005-06-28 17:19:58 +02:00
|
|
|
DBLOCK(1, printf("replying EBADIOCTL: 0x%x\n", req));
|
|
|
|
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, EBADIOCTL,
|
2005-04-21 16:53:53 +02:00
|
|
|
(acc_t *)0, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC void ip_hash_proto(ip_fd)
|
|
|
|
ip_fd_t *ip_fd;
|
|
|
|
{
|
|
|
|
ip_port_t *ip_port;
|
|
|
|
int hash;
|
|
|
|
|
|
|
|
ip_port= ip_fd->if_port;
|
|
|
|
if (ip_fd->if_ipopt.nwio_flags & NWIO_PROTOANY)
|
|
|
|
{
|
|
|
|
ip_fd->if_proto_next= ip_port->ip_proto_any;
|
|
|
|
ip_port->ip_proto_any= ip_fd;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hash= ip_fd->if_ipopt.nwio_proto & (IP_PROTO_HASH_NR-1);
|
|
|
|
ip_fd->if_proto_next= ip_port->ip_proto[hash];
|
|
|
|
ip_port->ip_proto[hash]= ip_fd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PUBLIC void ip_unhash_proto(ip_fd)
|
|
|
|
ip_fd_t *ip_fd;
|
|
|
|
{
|
|
|
|
ip_port_t *ip_port;
|
|
|
|
ip_fd_t *prev, *curr, **ip_fd_p;
|
|
|
|
int hash;
|
|
|
|
|
|
|
|
ip_port= ip_fd->if_port;
|
|
|
|
if (ip_fd->if_ipopt.nwio_flags & NWIO_PROTOANY)
|
|
|
|
{
|
|
|
|
ip_fd_p= &ip_port->ip_proto_any;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hash= ip_fd->if_ipopt.nwio_proto & (IP_PROTO_HASH_NR-1);
|
|
|
|
ip_fd_p= &ip_port->ip_proto[hash];
|
|
|
|
}
|
|
|
|
for (prev= NULL, curr= *ip_fd_p; curr;
|
|
|
|
prev= curr, curr= curr->if_proto_next)
|
|
|
|
{
|
|
|
|
if (curr == ip_fd)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
assert(curr);
|
|
|
|
if (prev)
|
|
|
|
prev->if_proto_next= curr->if_proto_next;
|
|
|
|
else
|
|
|
|
*ip_fd_p= curr->if_proto_next;
|
|
|
|
}
|
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
PUBLIC int ip_setconf(ip_port_nr, ipconf)
|
|
|
|
int ip_port_nr;
|
|
|
|
nwio_ipconf_t *ipconf;
|
|
|
|
{
|
2010-01-14 14:53:12 +01:00
|
|
|
int i, do_report;
|
2005-06-28 17:19:58 +02:00
|
|
|
ip_port_t *ip_port;
|
|
|
|
ip_fd_t *ip_fd;
|
|
|
|
ipaddr_t ipaddr;
|
|
|
|
u32_t mtu;
|
|
|
|
|
|
|
|
ip_port= &ip_port_table[ip_port_nr];
|
|
|
|
|
|
|
|
if (ipconf->nwic_flags & ~NWIC_FLAGS)
|
|
|
|
return EBADMODE;
|
|
|
|
|
|
|
|
do_report= 0;
|
|
|
|
if (ipconf->nwic_flags & NWIC_MTU_SET)
|
|
|
|
{
|
|
|
|
mtu= ipconf->nwic_mtu;
|
|
|
|
if (mtu < IP_MIN_MTU || mtu > ip_port->ip_mtu_max)
|
|
|
|
return EINVAL;
|
|
|
|
ip_port->ip_mtu= mtu;
|
|
|
|
do_report= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ipconf->nwic_flags & NWIC_NETMASK_SET)
|
|
|
|
{
|
|
|
|
ip_port->ip_subnetmask= ipconf->nwic_netmask;
|
|
|
|
ip_port->ip_flags |= IPF_NETMASKSET|IPF_SUBNET_BCAST;
|
|
|
|
if (ntohl(ip_port->ip_subnetmask) >= 0xfffffffe)
|
|
|
|
ip_port->ip_flags &= ~IPF_SUBNET_BCAST;
|
|
|
|
do_report= 1;
|
|
|
|
}
|
|
|
|
if (ipconf->nwic_flags & NWIC_IPADDR_SET)
|
|
|
|
{
|
|
|
|
ipaddr= ipconf->nwic_ipaddr;
|
|
|
|
ip_port->ip_ipaddr= ipaddr;
|
|
|
|
ip_port->ip_flags |= IPF_IPADDRSET;
|
|
|
|
ip_port->ip_classfulmask=
|
|
|
|
ip_netmask(ip_nettype(ipaddr));
|
|
|
|
if (!(ip_port->ip_flags & IPF_NETMASKSET))
|
|
|
|
{
|
|
|
|
ip_port->ip_subnetmask= ip_port->ip_classfulmask;
|
|
|
|
}
|
|
|
|
if (ipaddr == HTONL(0x00000000))
|
|
|
|
{
|
|
|
|
/* Special case. Use 0.0.0.0 to shutdown interface. */
|
|
|
|
ip_port->ip_flags &= ~(IPF_IPADDRSET|IPF_NETMASKSET);
|
|
|
|
ip_port->ip_subnetmask= HTONL(0x00000000);
|
|
|
|
}
|
|
|
|
(*ip_port->ip_dev_set_ipaddr)(ip_port);
|
|
|
|
|
|
|
|
/* revive calls waiting for an ip addresses */
|
|
|
|
for (i=0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
|
|
|
|
{
|
|
|
|
if (!(ip_fd->if_flags & IFF_INUSE))
|
|
|
|
continue;
|
|
|
|
if (ip_fd->if_port != ip_port)
|
|
|
|
continue;
|
|
|
|
if (ip_fd->if_flags & IFF_IOCTL_IP)
|
|
|
|
ip_ioctl (i, ip_fd->if_ioctl);
|
|
|
|
}
|
|
|
|
|
|
|
|
do_report= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ipr_chk_itab(ip_port-ip_port_table, ip_port->ip_ipaddr,
|
|
|
|
ip_port->ip_subnetmask);
|
|
|
|
ipr_chk_otab(ip_port-ip_port_table, ip_port->ip_ipaddr,
|
|
|
|
ip_port->ip_subnetmask);
|
|
|
|
if (do_report)
|
|
|
|
report_addr(ip_port);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
PRIVATE int ip_checkopt (ip_fd)
|
|
|
|
ip_fd_t *ip_fd;
|
|
|
|
{
|
|
|
|
/* bug: we don't check access modes yet */
|
|
|
|
|
|
|
|
unsigned long flags;
|
|
|
|
unsigned int en_di_flags;
|
|
|
|
acc_t *pack;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
flags= ip_fd->if_ipopt.nwio_flags;
|
|
|
|
en_di_flags= (flags >>16) | (flags & 0xffff);
|
|
|
|
|
|
|
|
if (flags & NWIO_HDR_O_SPEC)
|
|
|
|
{
|
|
|
|
result= ip_chk_hdropt (ip_fd->if_ipopt.nwio_hdropt.iho_data,
|
|
|
|
ip_fd->if_ipopt.nwio_hdropt.iho_opt_siz);
|
|
|
|
if (result<0)
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
if ((en_di_flags & NWIO_ACC_MASK) &&
|
|
|
|
(en_di_flags & NWIO_LOC_MASK) &&
|
|
|
|
(en_di_flags & NWIO_BROAD_MASK) &&
|
|
|
|
(en_di_flags & NWIO_REM_MASK) &&
|
|
|
|
(en_di_flags & NWIO_PROTO_MASK) &&
|
|
|
|
(en_di_flags & NWIO_HDR_O_MASK) &&
|
|
|
|
(en_di_flags & NWIO_RW_MASK))
|
|
|
|
{
|
|
|
|
ip_fd->if_flags |= IFF_OPTSET;
|
|
|
|
|
|
|
|
ip_hash_proto(ip_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
ip_fd->if_flags &= ~IFF_OPTSET;
|
|
|
|
|
|
|
|
while (ip_fd->if_rdbuf_head)
|
|
|
|
{
|
|
|
|
pack= ip_fd->if_rdbuf_head;
|
|
|
|
ip_fd->if_rdbuf_head= pack->acc_ext_link;
|
|
|
|
bf_afree(pack);
|
|
|
|
}
|
|
|
|
return NW_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRIVATE void reply_thr_get(ip_fd, reply, for_ioctl)
|
|
|
|
ip_fd_t *ip_fd;
|
|
|
|
size_t reply;
|
|
|
|
int for_ioctl;
|
|
|
|
{
|
|
|
|
acc_t *result;
|
|
|
|
result= (ip_fd->if_get_userdata)(ip_fd->if_srfd, reply,
|
|
|
|
(size_t)0, for_ioctl);
|
|
|
|
assert (!result);
|
|
|
|
}
|
|
|
|
|
2005-06-28 17:19:58 +02:00
|
|
|
PRIVATE void report_addr(ip_port)
|
|
|
|
ip_port_t *ip_port;
|
|
|
|
{
|
|
|
|
int i, hdr_len;
|
|
|
|
ip_fd_t *ip_fd;
|
|
|
|
acc_t *pack;
|
|
|
|
ip_hdr_t *ip_hdr;
|
|
|
|
|
|
|
|
pack= bf_memreq(IP_MIN_HDR_SIZE);
|
|
|
|
ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
|
|
|
|
|
|
|
hdr_len= IP_MIN_HDR_SIZE;
|
|
|
|
ip_hdr->ih_vers_ihl= (IP_VERSION << 4) | (hdr_len/4);
|
|
|
|
ip_hdr->ih_tos= 0;
|
|
|
|
ip_hdr->ih_length= htons(ip_port->ip_mtu);
|
|
|
|
ip_hdr->ih_id= 0;
|
|
|
|
ip_hdr->ih_flags_fragoff= 0;
|
|
|
|
ip_hdr->ih_ttl= 0;
|
|
|
|
ip_hdr->ih_proto= 0;
|
|
|
|
ip_hdr->ih_src= ip_port->ip_ipaddr;
|
|
|
|
ip_hdr->ih_dst= ip_port->ip_subnetmask;
|
|
|
|
ip_hdr_chksum(ip_hdr, hdr_len);
|
|
|
|
|
|
|
|
for (i=0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
|
|
|
|
{
|
|
|
|
if (!(ip_fd->if_flags & IFF_INUSE))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (ip_fd->if_port != ip_port)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deliver packet to user */
|
|
|
|
pack->acc_linkC++;
|
|
|
|
ip_packet2user(ip_fd, pack, 255, IP_MIN_HDR_SIZE);
|
|
|
|
}
|
|
|
|
bf_afree(pack); pack= NULL;
|
|
|
|
}
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/*
|
2005-06-28 17:19:58 +02:00
|
|
|
* $PchId: ip_ioctl.c,v 1.22 2004/08/03 11:10:08 philip Exp $
|
2005-04-21 16:53:53 +02:00
|
|
|
*/
|