|
|
researchv10 Norman
/*
* ip line discipline, to be pushed on an ethernet controller.
* collects data till a delim, passes it to ip_input().
*/
#include "sys/param.h"
#include "sys/stream.h"
#include "sys/conf.h"
#include "sys/inet/in.h"
#include "sys/inet/ip_var.h"
#include "sys/inet/ethernet.h"
extern struct ipif ipif[];
extern struct ipif *ipifsort[];
extern int ipcnt; /* number of ip's */
extern int arpcnt;
int ipiput(), ipisrv(), ipclose();
long ipopen();
int iposrv();
static struct qinit iprinit = { ipiput, ipisrv, ipopen, ipclose, IP_MSG_LIMIT, 64};
static struct qinit ipwinit = { putq, iposrv, ipopen, ipclose, 2*IP_MSG_LIMIT, 64 };
struct streamtab ipstream = { &iprinit, &ipwinit };
long
ipopen(q, dev)
register struct queue *q;
{
static int timing;
register struct ipif *fp, *ifend;
if (q->ptr)
return(1);
if(!timing){
timing = 1;
ip_slowtimo();
}
ifend = &ipif[ipcnt];
for (fp = ipif; fp < ifend; fp++)
if (fp->queue == NULL)
break;
if (fp >= ifend)
return(0);
fp->queue = q; /* that's the RD q */
fp->flags = IFF_UP;
fp->that = fp->thishost = 0;
fp->ipackets = fp->opackets = fp->ierrors = fp->oerrors = 0;
fp->mtu = 1500;
fp->arp = -1;
fp->dev = dev;
q->flag |= QDELIM;
WR(q)->flag |= QDELIM;
q->ptr = (caddr_t)fp;
WR(q)->ptr = (caddr_t)fp;
q->flag |= QNOENB; /* ipiput calls qenable() */
return(1);
}
ipclose(q)
struct queue *q;
{
register struct ipif *ifp;
ifp = (struct ipif *)q->ptr;
ip_ifremove(ifp);
ifp->queue = 0;
ifp->flags = 0;
}
ipisrv(q)
register struct queue *q;
{
register struct block *bp, *head, *tail;
register struct ipif *ifp;
/* there is now a whole packet waiting
* on this queue; strip it off and pass to ip_input().
* things other than data or delims are forwarded directly
* by ipiput().
*/
head = tail = (struct block *) 0;
ifp = (struct ipif *)q->ptr;
while(bp = getq(q)){
if (bp->type != M_DATA)
panic("ipisrv");
bp->next = NULL;
if (head == NULL)
head = bp;
else
tail->next = bp;
tail = bp;
if (bp->class&S_DELIM) {
bp->class &=~ S_DELIM;
MCHECK(head);
if((ifp->flags & IFF_ARP)
&& (head->wptr-head->rptr) >= sizeof(struct etherpup)){
/* strip off ether header */
head->rptr += sizeof(struct etherpup);
}
ip_input(head);
ifp->ipackets++;
head = tail = NULL;
}
}
if(head)
bp_putback(q, head);
}
ipiput(q, bp)
register struct queue *q;
register struct block *bp;
{
switch(bp->type){
case M_DATA:
putq(q, bp);
if (bp->class&S_DELIM)
qenable(q);
break;
default:
(*q->next->qinfo->putp)(q->next, bp);
break;
}
}
/*
* set our many broadcast addresses
*/
static
setbcast(ifp)
struct ipif *ifp;
{
int i;
/* official style */
ifp->bcast[0] = ifp->that|~ifp->mask; /* subnet */
ifp->bcast[1] = ifp->that|~IN_CLASS_NMASK(ifp->that); /* net */
ifp->bcast[2] = 0xffffffff; /* undirected */
/* old BSD style */
ifp->bcast[3] = ifp->that&ifp->mask; /* subnet */
ifp->bcast[4] = ifp->that&IN_CLASS_NMASK(ifp->that); /* net */
ifp->bcast[5] = 0; /* undirected */
if(ifp->flags & IFF_HOST)
for(i = 0; i < 6; i++)
ifp->bcast[i] = 0;
}
iposrv(q)
register struct queue *q;
{
struct x{
unsigned int in;
unsigned char en[6];
} *xp;
register struct block *bp;
register struct ipif *ifp;
register long *intp;
ifp = (struct ipif *)q->ptr;
while(bp = getq(q)){
switch (bp->type) {
case M_IOCTL:
switch(stiocom(bp)){
case IPIOARP:
ifp->flags |= IFF_ARP;
bp->type = M_IOCACK;
bp->wptr = bp->rptr;
qreply(q, bp);
break;
case IPIORESOLVE:
xp = (struct x *)(stiodata(bp));
if (arpcnt > 0)
arp_install(xp->in, xp->en);
bp->wptr = bp->rptr;
bp->type = M_IOCACK;
qreply(q, bp);
break;
case IPIOHOST:
intp = (long *)(stiodata(bp));
ifp->that = *intp;
ifp->flags |= IFF_HOST;
ifp->mask = 0xffffffff;
setbcast(ifp);
ip_ifinsert(ifp);
bp->type = M_IOCACK;
qreply(q, bp);
ip_doroute(ifp->that, 0);
break;
case IPIOMTU:
intp = (long *)(stiodata(bp));
ifp->mtu = *intp;
bp->type = M_IOCACK;
qreply(q, bp);
break;
case IPIONET:
intp = (long *)(stiodata(bp));
ifp->that = *intp;
ifp->mask = IN_CLASS_NMASK(ifp->that);
setbcast(ifp);
ip_ifinsert(ifp);
ifp->flags &= (~IFF_HOST);
bp->type = M_IOCACK;
qreply(q, bp);
ip_doroute(ifp->that, 0);
break;
case IPIOMASK:
intp = (long *)(stiodata(bp));
/*
* the mask has to be a superset of the class mask
*/
if((*intp&ifp->mask)==ifp->mask)
ifp->mask = *intp;
setbcast(ifp);
ip_ifinsert(ifp);
bp->type = M_IOCACK;
qreply(q, bp);
break;
case IPIOLOCAL:
intp = (long *)(stiodata(bp));
ifp->thishost = *intp;
setbcast(ifp);
bp->type = M_IOCACK;
qreply(q, bp);
break;
default:
(*q->next->qinfo->putp)(q->next, bp);
break;
}
continue;
default:
if (q->next->flag & QFULL) {
putbq(q, bp);
return;
}
if(bp->class&S_DELIM)
ifp->opackets++;
(*q->next->qinfo->putp)(q->next, bp);
continue;
}
}
}
/*
* Insert an entry into ipifsort. Entries are sorted by mask length,
* longest first.
*/
ip_ifinsert(ifp)
struct ipif *ifp;
{
int s = spl6();
register int i, j;
/*
* First try to remove it. This may be a reordering.
*/
ip_ifremove(ifp);
/*
* Now (re)insert it in the correct place
*/
for(i=0; i<ipcnt; i++){
if(ipifsort[i]==ifp)
panic("ip_ifinsert duplcate");
if(ipifsort[i]==0 || (ifp->mask & ipifsort[i]->mask)!=ifp->mask)
break;
}
if(i>=ipcnt)
panic("ip_ifinsert no room");
for(j=ipcnt-1; j>i; j--)
ipifsort[j] = ipifsort[j-1];
ipifsort[i] = ifp;
splx(s);
}
/*
* Remove an entry from ipifsort. Compress list to fill gap.
* It may not already be there.
*/
ip_ifremove(ifp)
struct ipif *ifp;
{
int s = spl6();
register int i;
for(i=0; i<ipcnt; i++)
if(ipifsort[i]==ifp)
break;
if(i<ipcnt){
for(; i<ipcnt-1; i++)
ipifsort[i] = ipifsort[i+1];
ipifsort[i] = 0;
}
splx(s);
}
/*
* Find the interface to use for sending messages to `dst'.
* ipifsort is sorted into priority order;
* first match found is best.
*/
struct ipif *
ip_ifonnetof(dst)
register unsigned long dst;
{
extern ipprintfs;
register struct ipif *ifp;
register int i;
register int Ipcnt = ipcnt; /* optimization */
/*
* first look for a match against addresses
*/
for(i=0; i < Ipcnt; i++){
if((ifp = ipifsort[i])==0)
break;
if(ifp->flags & IFF_UP)
if((dst & ifp->mask) == ifp->that)
return(ifp);
}
/*
* now try to match against the local host's addresses
*/
ifp = ip_ifwithaddr(dst);
if(ifp)
return(ifp);
/*
* no match
*/
if(ipprintfs)
printf("ifonnetof %x?\n", dst);
return(0);
}
/*
* return the interface for which addr is a local address. if non
* such exists, return 0.
*
* This routine assumes that ipifsort is sorted in priority order
* so that the first match found is the best match.
*/
struct ipif *
ip_ifwithaddr(addr)
register u_long addr;
{
register int i, j;
register u_long net, mask;
register struct ipif *ifp;
register int Ipcnt = ipcnt; /* optimization */
net = in_netof(addr);
for(i=0; i < Ipcnt; i++){
if((ifp = ipifsort[i])==0)
break;
if(ifp->flags & IFF_UP) {
/* address of this host */
if(addr == ifp->thishost)
return(ifp);
for(j = 0; j < 6; j++)
if(addr == ifp->bcast[j])
return(ifp);
/* address on a network simulated by this node */
if(net == ifp->thishost)
return(ifp);
}
}
return(0);
}
/*
* output list bp onto interface ifp
* for better buffering, put it on ip's queue first;
* iposrv will dribble it out as there's room
*/
ip_ldout(bp, dst, ifp)
register struct block *bp;
unsigned long dst; /* host byte order */
register struct ipif *ifp;
{
extern struct block *arp_resolve();
register struct block *bp1;
register struct queue *q;
if(ifp->queue == 0){
printf("ifp but no queue in ip_ldout\n");
bp_free(bp);
return(0);
}
q = WR(ifp->queue);
if(q->flag & QFULL){
bp_free(bp);
ifp->oerrors++;
return(1);
}
if(arpcnt > 0 && (ifp->flags & IFF_ARP)){
bp = arp_resolve(ifp->queue, bp, dst);
if(bp == 0)
return(1);
}
MCHECK(bp);
while(bp){
bp1 = bp->next;
if (bp1==NULL)
bp->class |= S_DELIM;
(*q->qinfo->putp)(q, bp);
bp = bp1;
}
return(0);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.