V10/sys/inet/ip_device.c
/*
* ip device driver; each minor device is one protocol.
* so tcp would be placed on top of ip minor device #6.
*/
#include "sys/param.h"
#include "sys/stream.h"
#include "sys/conf.h"
#include "sys/inet/in.h"
#include "sys/inet/ip_var.h"
extern int ipcnt; /* number of ip devices */
long ipdopen();
int ipdclose(), ipdput(), ipdosrv();
static struct qinit ipdrinit = { noput, NULL, ipdopen, ipdclose, 0, 0 };
struct qinit ipdwinit = { ipdput, ipdosrv, ipdopen, ipdclose,
IP_BODY_LIMIT, 129 };
struct streamtab ipdinfo = { &ipdrinit, &ipdwinit };
struct cdevsw ipcdev = cstrinit(&ipdinfo);
struct queue *ipdstate[256];
int ipprintfs;
long
ipdopen(q, dev)
register struct queue *q;
dev_t dev;
{
dev = minor(dev);
if(ipdstate[dev])
return(0);
ipdstate[dev] = q;
q->ptr = (caddr_t)dev;
q->flag |= QDELIM;
WR(q)->ptr = (caddr_t)dev;
WR(q)->flag |= QNOENB;
return(1);
}
ipdclose(q)
register struct queue *q;
{
ipdstate[(int)q->ptr] = 0;
}
ipdput(q, bp)
register struct queue *q;
register struct block *bp;
{
struct foo{
u_long dst;
u_long gate;
} foo;
int i;
struct block *bp1;
switch(bp->type){
case M_DATA:
putq(q, bp);
if (bp->class&S_DELIM)
qenable(q);
return;
case M_IOCTL:
bp->type = M_IOCACK;
switch(stiocom(bp)){
case IPIOROUTE:
bcopy(stiodata(bp), &foo, sizeof(struct foo));
if(ip_doroute(foo.dst, foo.gate))
bp->type = M_IOCNAK;
break;
case IPIOGETIFS:
i = *(int *)(stiodata(bp));
if(i>=ipcnt) {
bp->type = M_IOCNAK;
break;
}
bp1 = allocb(sizeof(struct ipif));
if (bp1 == 0) {
bp->type = M_IOCNAK;
break;
}
freeb(bp);
bp = bp1;
bp->type = M_IOCACK;
bp->wptr = (u_char *)stiodata(bp);
*(struct ipif *)(bp->wptr) = ipif[i];
bp->wptr += sizeof(struct ipif);
break;
default:
bp->type = M_IOCNAK;
break;
}
qreply(q, bp);
return;
default:
freeb(bp);
return;
}
}
ipdrint(bp, dev)
register struct block *bp;
unsigned dev;
{
register struct block *bp1;
register struct queue *nq;
if ((nq = ipdstate[dev]) == NULL) {
bp_free(bp);
return;
}
nq = nq->next; /* optimization */
if(nq->flag&QFULL){
bp_free(bp);
if(ipprintfs)
printf("ipdrint: QFULL\n");
ipstat.ips_qfull++;
return;
}
while(bp){
bp1 = bp->next;
if (bp1==NULL)
bp->class |= S_DELIM;
else
bp->class &=~ S_DELIM;
(*nq->qinfo->putp)(nq, bp);
bp = bp1;
}
}
ipdosrv(q)
struct queue *q;
{
register struct block *bp, *tail, *head;
head = tail = NULL;
while(bp = getq(q)){
if (bp->type != M_DATA)
panic("ipdosrv");
bp->next = NULL;
if (head == NULL)
head = bp;
else
tail->next = bp;
tail = bp;
if (bp->class&S_DELIM) {
ip_output(head, (struct block *)0, 0);
head = tail = NULL;
}
}
if (head)
bp_putback(q, head);
}