BBN-Vax-TCP/bbnnet-oct82/imp_io.c
#include "../h/param.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../bbnnet/mbuf.h"
#include "../bbnnet/net.h"
#include "../bbnnet/ifcb.h"
#include "../bbnnet/ip.h"
#include "../bbnnet/imp.h"
#include "../bbnnet/raw.h"
#include "../bbnnet/ucb.h"
#include "../bbnnet/fsm.h"
extern struct user u;
/*
* ARPANET 1822 input routine
*
* Called from netmain to interpret 1822 imp-host messages. Completed messages
* are placed on the input queue by the driver. Type 0 messages (non-control)
* are passed to higher level protocol processors on the basis of link
* number. All other type messages (control) are handled here.
*/
imp_rcv(ip)
register struct ifcb *ip;
{
register struct mbuf *m, *n;
register struct imp *p;
register struct proto *q;
register struct host *hp;
register struct ucb *up;
int i;
int error = FALSE;
struct socket naddr;
int netreset();
/* process all messages on input queue */
for (;;) {
spl5();
if ((m = ip->if_inq_hd) == NULL) {
spl0();
break;
}
ip->if_inq_hd = m->m_act;
spl0();
m->m_act = NULL;
p = mtod(m, struct imp *);
if (p->i_nff != IMP_NFF) /* make sure leader is ok */
goto free;
switch (p->i_type) { /* case on msg type */
case IMP_DATA: /* normal msg */
p->i_mlen = short_from_net(p->i_mlen) >> 3;
/* dispatch on link number, pass to either
ip or raw input handler */
if (p->i_link == ip->if_link) {
m->m_off += sizeof(struct imp);
m->m_len -= sizeof(struct imp);
#ifdef IPADJ
/* remove any IMP message padding */
ip_adj(m, (struct ip *)((int)p +
sizeof(struct imp)));
#endif IPADJ
/* if any user IPs, copy message */
if ((q = netcb.n_ip_proto) != NULL)
n = m_copy(m);
ip_input(m, ip);
/* dispatch to other IPs */
if (q != NULL) {
n->m_off -= sizeof(struct imp);
n->m_len += sizeof(struct imp);
raw_disp(n, q);
}
} else
goto dispraw;
break;
case IMP_LERROR: /* imp leader error */
log_err(ip, "leader error");
h_reset(iptonet(ip->if_addr));
imp_noops(ip); /* send no-ops to clear i/f */
goto free;
case IMP_DOWN: /* imp going down msg */
log_err(ip, "going down");
ip->if_avail = FALSE;
timeout((caddr_t)netreset, (caddr_t)ip, 30*60);
goto free;
case IMP_NOP: /* no-op */
/* compare local addr with that in message,
warn and reset if no match */
if (p->i_host != ip->if_addr.s_host ||
p->i_imp != ip->if_addr.s_imp) {
ip->if_addr.s_host = p->i_host;
ip->if_addr.s_imp = p->i_imp;
printf("%s%d imp: address mismatch, reset to %d/%d\n",
ip->if_name, ip->if_unit,
p->i_host, p->i_impno);
}
goto free;
case IMP_RFNM: /* RFNM */
case IMP_INCOMP: /* incomplete */
/* record in host table and free */
p->i_htype = netoint(iptonet(ip->if_addr));
if ((hp = h_find(&p->i_htype)) != NULL)
if (hp->h_rfnm != 0) {
hp->h_rfnm--;
/* send any blocked msgs */
if ((n = hp->h_outq) != NULL) {
hp->h_outq = n->m_act;
imp_snd(n, ip, NULL,0,0,TRUE);
/* delete any temp host entries if
RFNM count is zero */
} else if (hp->h_rfnm == 0 &&
hp->h_stat&HTEMP)
h_free(hp);
}
goto disperr;
case IMP_DEAD: /* unreachable host */
/* set status, record in host tab and free */
p->i_htype = netoint(iptonet(ip->if_addr));
if ((hp = h_find(&p->i_htype)) != NULL) {
hp->h_stat &= ~HUP;
hp->h_rfnm = 0;
/* signal all conns to this host */
for (up=netcb.n_ucb_hd; up != NULL;
up = up->uc_next)
if (up->uc_proc != NULL &&
up->uc_route == hp)
/* if route addr different from
dest addr, must be dead
gateway */
if (hp->h_addr.s_addr ==
addr_1822(up->uc_host)) {
up->uc_xstat = p->i_stype;
to_user(up,
(p->i_stype ==
IMP_DEAD_HOST
? UDEAD
: UNRCH));
/* look for another gateway to
continue with */
} else if (!ip_reroute(up, hp)){
up->uc_xstat = 0;
to_user(up, UNRCH);
}
}
goto disperr;
case IMP_DERROR: /* imp data error */
/* clear RFNM status for this host and send no-ops
to clear i/f */
log_err(ip, "data error");
p->i_htype = netoint(iptonet(ip->if_addr));
if ((hp = h_find(&p->i_htype)) != NULL)
hp->h_rfnm = 0;
imp_noops(ip);
goto disperr;
case IMP_RESET: /* reset */
log_err(ip, "reset complete");
goto free;
default: /* illegal type */
goto free;
disperr:
/* dispatch control messages to raw connections */
if (p->i_link == ip->if_link &&
netcb.n_ip_proto == NULL)
goto free;
error = TRUE;
dispraw:
/* dipatch control and data messages to raw conns */
naddr.s_addr = ip->if_addr.s_addr;
naddr.s_imp = p->i_imp;
naddr.s_host = p->i_host;
raw_input(m, &naddr, &ip->if_addr,
(short)p->i_link, URAW, error);
break;
free:
m_freem(m); /* free message chain */
}
}
}
/*
* ARPANET 1822 output routine
*
* Called from higher level protocol routines to set up messages for
* transmission to the imp. Sets up header for non-asis messages.
* Enques a message passed as an mbuf chain from the higher level protocol
* routines. Does RFNM counting: if more than 8 messages are in flight,
* hold on a RFNM queue until the i/f clears.
*/
imp_snd(mp, ip, addr, len, link, asis)
register struct mbuf *mp;
register struct ifcb *ip;
struct socket *addr;
register len;
int link, asis;
{
register struct mbuf *m;
register struct imp *p;
register struct host *hp;
int i;
struct socket ohost;
if (!ip->if_avail) { /* make sure i/f is up */
m_freem(mp);
return(FALSE);
}
mp->m_act = NULL;
if (asis)
p = mtod(mp, struct imp *); /* -> 1822 leader */
else {
/* build header in current mbuf */
mp->m_off -= sizeof(struct imp);
mp->m_len += sizeof(struct imp);
p = mtod(mp, struct imp *);
p->i_host = addr->s_host;
p->i_impno = addr->s_impno;
p->i_lh = 0; /* do not send logical host field */
p->i_mlen = len + sizeof(struct imp);
p->i_link = link;
p->i_nff = IMP_NFF;
p->i_dnet = 0;
p->i_lflgs = 0;
p->i_type = IMP_DATA;
p->i_stype = 0;
p->i_htype = 0;
}
#ifndef IMPLOOP
/* do RFNM counting for type 0 messages (no more than 8 outstanding
to any host) */
if (p->i_type == 0) {
ohost.s_addr = ip->if_addr.s_addr;
ohost.s_host = p->i_host;
ohost.s_imp = p->i_imp;
hp = h_find(&ohost); /* get host table entry */
/* if imp would block, put msg on queue until rfnm */
if (hp != NULL) {
if (hp->h_rfnm > 8) {
if ((m = hp->h_outq) == NULL)
hp->h_outq = mp;
else {
/* don't pile up too many messages */
i = 8;
while (m->m_act != NULL) {
if (--i > 0)
m = m->m_act;
else {
m_freem(mp);
return(FALSE);
}
}
m->m_act = mp;
}
return(TRUE);
} else
hp->h_rfnm++;
} else {
/* make a temporary host entry if none exists already */
if ((hp = h_make(&ohost, TRUE)) != NULL)
hp->h_rfnm++;
}
}
/* put output message on queue */
spl5();
if (ip->if_outq_hd != NULL)
ip->if_outq_tl->m_act = mp;
else
ip->if_outq_hd = mp;
ip->if_outq_tl = mp;
spl0();
/* if no outstanding output, start some */
if (!ip->if_active)
(*ip->if_out)(ip);
#else
/* software looping: put msg chain on input queue */
if (ip->if_inq_hd != NULL)
ip->if_inq_tl->m_act = mp;
else
ip->if_inq_hd = mp;
ip->if_inq_tl = mp;
#endif IMPLOOP
return(TRUE);
}
/*
* Raw ARPANET 1822 output routine. Called from raw_write with an empty
* mbuf chained to the user supplied message chain for header construction.
*/
imp_raw(up, m, len)
register struct ucb *up;
register struct mbuf *m;
int len;
{
register struct proto *p;
switch (up->uc_flags & RAWMASK) {
case RAWCOMP: /* system supplies leader */
/* leader will be constructed at end of first mbuf */
m->m_off = MSIZE;
m->m_len = 0;
if ((p = up->uc_proto) == NULL) {
u.u_error = ENETRNG;
m_freem(m);
} else if (!imp_snd(m, up->uc_srcif, &up->uc_host, len,
p->pr_num, FALSE))
u.u_error = EBLOCK;
break;
case RAWASIS: /* user supplies leader */
/* ->user supplied header */
if ((m = m_free(m)) == NULL)
u.u_error = ERAWBAD;
else if (!imp_snd(m, up->uc_srcif, NULL, 0, 0, TRUE))
u.u_error = EBLOCK;
break;
default:
u.u_error = ENETPARM;
m_freem(m);
}
}
/*
* Put three 1822 no-ops at the head of the output queue. Part of host-imp
* initialization procedure.
*/
imp_noops(ip)
register struct ifcb *ip;
{
register inx;
register struct mbuf *m;
register struct imp *l;
int s;
for (inx = 0; inx < 3; inx++ ) {
/* get a buffer for the no-op */
if ((m = m_get(0)) == NULL)
return(FALSE);
m->m_off = MHEAD;
m->m_len = 10;
l = mtod(m, struct imp *);
l->i_nff = IMP_NFF;
l->i_dnet = 0;
l->i_lflgs = 0;
l->i_htype = 0;
l->i_host = 0;
l->i_imp = 0;
l->i_link = inx;
l->i_stype = 0;
l->i_mlen = 0;
l->i_type = IMP_NOP;
/* put no-op at head of output queue */
s = spl5();
if (ip->if_outq_hd == NULL)
ip->if_outq_tl = m;
else
m->m_act = ip->if_outq_hd;
ip->if_outq_hd = m;
splx(s);
}
if (!ip->if_active)
(*ip->if_out)(ip);
return(TRUE);
}
log_err(ip, s)
register struct ifcb *ip;
char *s;
{
printf("%s%d imp: %s\n", ip->if_name, ip->if_unit, s);
}