V9/sys/inet.old/ip_ld.c
/*
* ip line discipline, to be pushed on an ethernet controller.
* collects data till a delim, passes it to ip_input().
*/
#include "inet.h"
#include "arp.h"
#include "uarp.h"
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/stream.h"
#include "../h/ioctl.h"
#include "../h/ttyld.h"
#include "../h/map.h"
#include "../h/buf.h"
#include "../h/ubavar.h"
#include "../h/conf.h"
#include "../h/inet/in.h"
#include "../h/inet/ip_var.h"
#include "../h/inet/mbuf.h"
#include "../h/ethernet.h"
struct ipif ipif[NINET];
int Ninet = NINET; /* let netstat find the number of interfaces */
int ipopen(), ipiput(), ipisrv(), ipclose();
int iposrv();
static struct qinit iprinit = { ipiput, ipisrv, ipopen, ipclose, IP_MSG_LIMIT, 64};
static struct qinit ipwinit = { putq, iposrv, ipopen, ipclose, 1024, 64 };
struct streamtab ipinfo = { &iprinit, &ipwinit };
ipopen(q, dev)
register struct queue *q;
{
static int timing;
register i;
register struct ipif *fp;
if (q->ptr)
return(1);
if(!timing){
timing = 1;
ip_slowtimo();
}
for (i=0; ipif[i].queue!=0 && i<NINET; i++)
;
if (i >= NINET)
return(0);
fp = &ipif[i];
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)
register struct queue *q;
{
register struct ipif *ifp;
ifp = (struct ipif *)q->ptr;
#if NARP > 0
if (ifp->arp >= 0)
arp_disable(ifp->arp);
#endif
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_DELIM){
freeb(bp);
if(head){
MCHECK(head);
if((ifp->flags & IFF_ARP)
&& (head->wptr - head->rptr) >= sizeof(struct etherpup)){
/* blow away ether header */
head->rptr += sizeof(struct etherpup);
}
ip_input(head);
ifp->ipackets++;
} else {
printf("ipisrv: no data\n");
ifp->ierrors++;
}
head = tail = (struct block *) 0;
} else if(bp->type == M_DATA){
bp->next = (struct block *) 0;
if(head == (struct block *) 0){
head = bp;
} else {
tail->next = bp;
}
tail = bp;
} else {
printf("ipisrv: weird type %d\n", bp->type);
(*q->next->qinfo->putp)(q->next, bp);
}
}
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); /* putq does compression into blocks */
break;
case M_DELIM:
putq(q, bp);
qenable(q);
break;
default:
(*q->next->qinfo->putp)(q->next, bp);
break;
}
}
iposrv(q)
register struct queue *q;
{
struct x{
unsigned int in;
unsigned char en[6];
} *xp;
register union stmsg *sp;
register struct block *bp;
register struct ipif *ifp;
register int *intp;
ifp = (struct ipif *)q->ptr;
while(bp = getq(q)){
if(bp->type == M_IOCTL){
sp = (union stmsg *)bp->rptr;
switch(sp->ioc0.com){
case IPIOARP:
#if NARP > 0
if (ifp->arp >= 0)
printf("IP: already arping\n");
else {
ifp->arp = arp_enable(ifp->dev,
ETHERPUP_IPTYPE,
sizeof(u_long), 1,
&ifp->thishost);
if (ifp->arp == -1) {
bp->type = M_IOCNAK;
qreply(q, bp);
break;
}
}
#endif
ifp->flags |= IFF_ARP;
bp->type = M_IOCACK;
bp->wptr = bp->rptr;
qreply(q, bp);
break;
case IPIORESOLVE:
xp = (struct x *)(sp->iocx.xxx);
#if NUARP > 0
arp_install(xp->in, xp->en);
#endif
bp->wptr = bp->rptr;
bp->type = M_IOCACK;
qreply(q, bp);
break;
case IPIOHOST:
intp = (int *)(sp->iocx.xxx);
ifp->that = *intp;
ifp->flags |= IFF_HOST;
bp->type = M_IOCACK;
qreply(q, bp);
ip_doroute(ifp->that, 0);
break;
case IPIOMTU:
intp = (int *)(sp->iocx.xxx);
ifp->that = *intp;
ifp->mtu = *intp;
bp->type = M_IOCACK;
qreply(q, bp);
break;
case IPIONET:
intp = (long *)(sp->iocx.xxx);
ifp->that = *intp;
ifp->mask = 0;
ifp->flags &= (~IFF_HOST);
bp->type = M_IOCACK;
qreply(q, bp);
ip_doroute(ifp->that, 0);
break;
case IPIOMASK:
intp = (long *)(sp->iocx.xxx);
ifp->mask = *intp;
bp->type = M_IOCACK;
qreply(q, bp);
ip_doroute(ifp->that, 0);
break;
case IPIOLOCAL:
intp = (int *)(sp->iocx.xxx);
ifp->thishost = *intp;
bp->type = M_IOCACK;
qreply(q, bp);
break;
default:
(*q->next->qinfo->putp)(q->next, bp);
break;
}
} else {
(*q->next->qinfo->putp)(q->next, bp);
if(bp->type == M_DELIM)
ifp->opackets++;
}
}
}
struct ipif *
ip_ifonnetof(dst)
unsigned long dst;
{
extern ipprintfs;
struct ipif *ifp;
/* point-to-point links first */
for(ifp = &ipif[0]; ifp < &ipif[NINET]; ifp++){
if((ifp->flags & IFF_UP) && (ifp->flags & IFF_HOST)){
if(dst == ifp->that)
return(ifp);
}
}
/* now normal nets */
for(ifp = &ipif[0]; ifp < &ipif[NINET]; ifp++){
if((ifp->flags & (IFF_UP|IFF_HOST)) == IFF_UP){
if(in_netof(dst) == ifp->that)
return(ifp);
}
}
if(ipprintfs)
printf("ifonnetof %x?\n", dst);
return(0);
}
struct ipif *
ip_ifwithaddr(addr)
unsigned long addr;
{
struct ipif *ifp;
unsigned long net;
net = in_netof(addr);
for(ifp = &ipif[0]; ifp < &ipif[NINET]; ifp++){
if(ifp->flags & IFF_UP){
/* address of this host */
if(addr == ifp->thishost)
return(ifp);
/* address of this host's network */
if(addr == in_netof(ifp->thishost))
return(ifp);
/* address on a network simulated by this node */
if(net == ifp->thishost)
return(ifp);
}
}
return(0);
}
ip_ldout(bp, dst, ifp)
register struct block *bp;
unsigned long dst; /* host byte order */
register struct ipif *ifp;
{
#if NARP > 0 || NUARP > 0
extern struct block *arp_resolve();
#endif
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->next->flag & QFULL){
bp_free(bp);
ifp->oerrors++;
return(1);
}
#if NARP > 0
if(ifp->flags & IFF_ARP){
bp = arp_resolve(ifp->arp, bp, &dst);
if(bp == 0)
return(1);
}
#endif
#if NUARP > 0
if(ifp->flags & IFF_ARP){
bp = arp_resolve(ifp->queue, bp, dst);
if(bp == 0)
return(1);
}
#endif
MCHECK(bp);
while(bp){
bp1 = bp->next;
(*q->next->qinfo->putp)(q->next, bp);
bp = bp1;
}
bp1 = allocb(0);
if(bp1){
bp1->type = M_DELIM;
(*q->next->qinfo->putp)(q->next, bp1);
ifp->opackets++;
} else {
printf("ip_ldout: no allocb for delim\n");
ifp->oerrors++;
}
return(0);
}