#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "ip.h"
#include "trip.h"
static void tripread(void *a);
static void tripbind(Ipifc *ifc, int argc, char **argv);
static void tripunbind(Ipifc *ifc);
static void tripbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
static void tripaddmulti(Ipifc *ifc, uchar*, uchar*);
static void tripremmulti(Ipifc *ifc, uchar*, uchar*);
static void tripaddroute(Ipifc *ifc, int, uchar*, uchar*, uchar*, int);
static void tripremroute(Ipifc *ifc, int, uchar*, uchar*);
static void tripares(Fs*, int, uchar*, uchar*, int, int);
Medium tripmedium =
{
.name= "trip",
.mintu= 20,
.maxtu= 64*1024,
.maclen= LCIMACSIZE,
.bind= tripbind,
.unbind= tripunbind,
.bwrite= tripbwrite,
.addmulti= tripaddmulti,
.remmulti= tripremmulti,
.addroute= tripaddroute,
.remroute= tripremroute,
.ares= tripares,
};
typedef struct Tripinfo Tripinfo;
struct Tripinfo
{
Fs* fs; /* my instance of the IP stack */
Ipifc* ifc; /* IP interface */
Card* dev;
Proc* readp; /* reading process */
Chan* mchan; /* Data channel */
};
/*
* called to bind an IP ifc to an ethernet device
* called with ifc qlock'd
*/
static void
tripbind(Ipifc *ifc, int argc, char **argv)
{
int fd;
Chan *mchan;
Tripinfo *er;
if(argc < 2)
error(Ebadarg);
fd = kopen(argv[2], ORDWR);
if(fd < 0)
error("trip open failed");
mchan = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1);
kclose(fd);
if(devtab[mchan->type]->dc != 'T') {
cclose(mchan);
error(Enoport);
}
er = smalloc(sizeof(*er));
er->mchan = mchan;
er->ifc = ifc;
er->dev = tripsetifc(mchan, ifc);
er->fs = ifc->conv->p->f;
ifc->arg = er;
kproc("tripread", tripread, ifc);
}
/*
* called with ifc qlock'd
*/
static void
tripunbind(Ipifc *ifc)
{
Tripinfo *er = ifc->arg;
/*
if(er->readp)
postnote(er->readp, 1, "unbind", 0);
*/
tsleep(&up->sleep, return0, 0, 300);
if(er->mchan != nil)
cclose(er->mchan);
free(er);
}
/*
* called by ipoput with a single block to write
*/
static void
tripbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
{
Tripinfo *er = ifc->arg;
/*
* Packet is rerouted at linecard
* so the gateway is ignored
*/
USED(ip);
USED(version);
if(waserror()) {
print("tripwrite failed\n");
return;
}
devtab[er->mchan->type]->bwrite(er->mchan, bp, 0);
poperror();
ifc->out++;
}
/*
* process to read from the trip interface
*/
static void
tripread(void *a)
{
Ipifc *ifc;
Block *bp;
Tripinfo *er;
ifc = a;
er = ifc->arg;
er->readp = up; /* hide identity under a rock for unbind */
for(;;) {
bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxtu, 0);
ifc->in++;
ipiput4(er->fs, ifc, bp);
}
pexit("hangup", 1);
}
static void
tripaddroute(Ipifc *ifc, int v, uchar *addr, uchar *mask, uchar *gate, int t)
{
int alen;
MTroute mtr;
Tripinfo *tinfo;
tinfo = ifc->arg;
if(!tinfo->dev->routing)
return;
/*
* Multicast addresses are handled on the linecard by
* the multicast port driver, so the route load is dumped.
* loaded by addmulti/remmulti for SBC routes
* joinmulti/leavemulti for inter LC
*/
if(ipismulticast(addr))
return;
mtr.type = T_ROUTEADMIN;
if(v & Rv4) {
mtr.op = RTADD4;
alen = IPv4addrlen;
}
else {
mtr.op = RTADD6;
alen = IPaddrlen;
}
mtr.rtype = t;
memmove(mtr.addr, addr, alen);
memmove(mtr.mask, mask, alen);
memmove(mtr.gate, gate, alen);
i2osend(tinfo->dev, &mtr, sizeof(mtr));
}
static void
tripremroute(Ipifc *ifc, int v, uchar *addr, uchar *mask)
{
int alen;
MTroute mtr;
Tripinfo *tinfo;
tinfo = ifc->arg;
if(!tinfo->dev->routing)
return;
if(ipismulticast(addr))
return;
mtr.type = T_ROUTEADMIN;
if(v & Rv4) {
mtr.op = RTDEL4;
alen = IPv4addrlen;
}
else {
mtr.op = RTDEL6;
alen = IPaddrlen;
}
memmove(mtr.addr, addr, alen);
memmove(mtr.mask, mask, alen);
i2osend(tinfo->dev, &mtr, sizeof(mtr));
}
static void
tripxmitroute(Route *r, Routewalk *rw)
{
int nifc;
char t[5];
uchar a[IPaddrlen], m[IPaddrlen], g[IPaddrlen];
convroute(r, a, m, g, t, &nifc);
if(!(r->type & Rv4)) {
tripaddroute(rw->state, 0, a, m, g, r->type);
return;
}
tripaddroute(rw->state, Rv4, a+IPv4off, m+IPv4off, g+IPv4off, r->type);
}
static void
sendifcinfo(Ipifc *dest)
{
Conv **cp, **e;
Iplifc *l;
Ipifc *ifc;
MTifctl mtc;
Tripinfo *tinfo, *oinfo;
Proto *p;
tinfo = dest->arg;
/* Install interfaces */
p = tinfo->fs->ipifc;
e = &p->conv[p->nc];
for(cp = p->conv; cp < e; cp++) {
if(*cp == nil)
continue;
ifc = (Ipifc*)(*cp)->ptcl;
if(dest == ifc)
continue;
mtc.type = T_CTLIFADMIN;
mtc.maxtu = ifc->maxtu;
mtc.mintu = ifc->mintu;
mtc.port = 0;
if(ifc->m == &tripmedium) {
oinfo = ifc->arg;
mtc.port = oinfo->dev->bar[0].bar;
}
for(l = ifc->lifc; l != nil; l = l->next) {
if(isv4(l->local)) {
mtc.op = IFADD4;
memmove(mtc.addr, l->local+IPv4off, IPv4addrlen);
memmove(mtc.mask, l->mask+IPv4off, IPv4addrlen);
}
else {
mtc.op = IFADD6;
memmove(mtc.addr, l->local, sizeof(mtc.addr));
memmove(mtc.mask, l->mask, sizeof(mtc.mask));
}
i2osend(tinfo->dev, &mtc, sizeof(mtc));
}
}
}
void
tripsync(Ipifc *ifc)
{
Routewalk rw;
if(ifc == nil) {
print("tripsync: interface not bound\n");
return;
}
/* Mirror the route table into the lincard */
rw.o = 0;
rw.n = (1<<22);
rw.state = ifc;
rw.walk = tripxmitroute;
ipwalkroutes(ifc->conv->p->f, &rw);
/*
* Tell the linecard about interfaces that already
* exist elsewhere
*/
sendifcinfo(ifc);
}
/* Tell a line card the SBC is interested in listening
* to a multicast address
*/
static void
tripaddmulti(Ipifc *ifc, uchar *addr, uchar *ifca)
{
MTmultiears mt;
Tripinfo *tinfo;
/* print("tripaddmulti %I %I\n", addr, ifca); /**/
tinfo = ifc->arg;
if(!tinfo->dev->routing)
return;
mt.type = T_MULTIEAR;
mt.op = ADDMULTI;
memmove(mt.addr, addr, sizeof(mt.addr));
memmove(mt.ifca, ifca, sizeof(mt.ifca));
i2osend(tinfo->dev, &mt, sizeof(mt));
}
/* Tell a line card the SBC is no longer interested in listening
* to a multicast address
*/
static void
tripremmulti(Ipifc *ifc, uchar *addr, uchar *ifca)
{
MTmultiears mt;
Tripinfo *tinfo;
tinfo = ifc->arg;
if(!tinfo->dev->routing)
return;
mt.type = T_MULTIEAR;
mt.op = REMMULTI;
memmove(mt.addr, addr, sizeof(mt.addr));
memmove(mt.ifca, ifca, sizeof(mt.ifca));
i2osend(tinfo->dev, &mt, sizeof(mt));
}
static void
tripares(Fs *fs, int vers, uchar *ip, uchar *mac, int l, int)
{
Route *r;
Ipifc *ifc;
MTaresenter ta;
Tripinfo *tinfo;
uchar v6ip[IPaddrlen];
if(vers == V4) {
r = v4lookup(fs, ip);
v4tov6(v6ip, ip);
ip = v6ip;
}
else
r = v6lookup(fs, ip);
if(r == nil) {
print("tripares: no route for entry\n");
return;
}
ifc = r->ifc;
tinfo = ifc->arg;
if(!tinfo->dev->routing)
return;
if(vers == V4) {
v4tov6(v6ip, ip);
ip = v6ip;
}
ta.type = T_ARESENTER;
ta.maclen = l;
memmove(ta.addr, ip, IPaddrlen);
memmove(ta.amac, mac, l);
i2osend(tinfo->dev, &ta, sizeof(ta));
}
void
tripmediumlink(void)
{
addipmedium(&tripmedium);
}
|