#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netiso/iso.h>
#include <netiso/iso_var.h>
#include <netiso/iso_snpac.h>
#include <netiso/clnp.h>
#include <netiso/clnl.h>
#include <netiso/esis.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netiso/eonvar.h>
#include <netiso/clnp_stat.h>
#include <netiso/argo_debug.h>
#if ISO
u_char clnp_protox[ISOPROTO_MAX];
struct clnl_protosw clnl_protox[256];
int clnpqmaxlen = IFQ_MAXLEN;
struct mbuf *clnp_data_ck();
int clnp_input();
int esis_input();
#ifdef ISO_X25ESIS
int x25esis_input();
#endif
clnp_init()
{
register struct protosw *pr;
if ((pr = pffindproto(PF_ISO, ISOPROTO_RAW, SOCK_RAW)) == 0)
printf("clnl_init: no raw CLNP\n");
else
clnp_protox[ISOPROTO_RAW] = pr - isosw;
if ((pr = pffindproto(PF_ISO, ISOPROTO_TP, SOCK_SEQPACKET)) == 0)
printf("clnl_init: no tp/clnp\n");
else
clnp_protox[ISOPROTO_TP] = pr - isosw;
clnl_protox[ISO8473_CLNP].clnl_input = clnp_input;
clnlintrq.ifq_maxlen = clnpqmaxlen;
}
clnlintr()
{
register struct mbuf *m;
register struct clnl_fixed *clnl;
int s;
struct clnl_protosw *clnlsw;
struct snpa_hdr sh;
next:
s = splimp();
IF_DEQUEUE(&clnlintrq, m);
splx(s);
if (m == 0)
return;
if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.rcvif == 0) {
m_freem(m);
goto next;
} else {
register struct ifaddr *ifa;
for (ifa = m->m_pkthdr.rcvif->if_addrlist; ifa; ifa = ifa->ifa_next)
if (ifa->ifa_addr->sa_family == AF_ISO)
break;
if (ifa == 0) {
m_freem(m);
goto next;
}
}
bzero((caddr_t)&sh, sizeof(sh));
sh.snh_flags = m->m_flags & (M_MCAST|M_BCAST);
switch((sh.snh_ifp = m->m_pkthdr.rcvif)->if_type) {
extern int ether_output();
case IFT_EON:
bcopy(mtod(m, caddr_t), (caddr_t)sh.snh_dhost, sizeof(u_long));
bcopy(sizeof(u_long) + mtod(m, caddr_t),
(caddr_t)sh.snh_shost, sizeof(u_long));
sh.snh_dhost[4] = mtod(m, u_char *)[sizeof(struct ip) +
_offsetof(struct eon_hdr, eonh_class)];
m->m_data += EONIPLEN;
m->m_len -= EONIPLEN;
m->m_pkthdr.len -= EONIPLEN;
break;
default:
if (sh.snh_ifp->if_output == ether_output) {
bcopy((caddr_t)(mtod(m, struct ether_header *)->ether_dhost),
(caddr_t)sh.snh_dhost, 2*sizeof(sh.snh_dhost));
m->m_data += sizeof (struct ether_header);
m->m_len -= sizeof (struct ether_header);
m->m_pkthdr.len -= sizeof (struct ether_header);
}
}
IFDEBUG(D_INPUT)
int i;
printf("clnlintr: src:");
for (i=0; i<6; i++)
printf("%x%c", sh.snh_shost[i] & 0xff, (i<5) ? ':' : ' ');
printf(" dst:");
for (i=0; i<6; i++)
printf("%x%c", sh.snh_dhost[i] & 0xff, (i<5) ? ':' : ' ');
printf("\n");
ENDDEBUG
if ((IS_CLUSTER(m) || (m->m_len < sizeof(struct clnl_fixed))) &&
((m = m_pullup(m, sizeof(struct clnl_fixed))) == 0)) {
INCSTAT(cns_toosmall);
goto next;
}
clnl = mtod(m, struct clnl_fixed *);
if ((clnl->cnf_hdr_len < CLNP_HDR_MIN) ||
(clnl->cnf_hdr_len > CLNP_HDR_MAX)) {
INCSTAT(cns_badhlen);
m_freem(m);
goto next;
}
if (clnl->cnf_hdr_len > m->m_len) {
if ((m = m_pullup(m, (int)clnl->cnf_hdr_len)) == 0) {
INCSTAT(cns_badhlen);
goto next;
}
clnl = mtod(m, struct clnl_fixed *);
}
clnlsw = &clnl_protox[clnl->cnf_proto_id];
if (clnlsw->clnl_input)
(*clnlsw->clnl_input) (m, &sh);
else
m_freem(m);
goto next;
}
clnp_input(m, shp)
struct mbuf *m;
struct snpa_hdr *shp;
{
register struct clnp_fixed *clnp;
struct sockaddr_iso source;
struct sockaddr_iso target;
#define src source.siso_addr
#define dst target.siso_addr
caddr_t hoff;
caddr_t hend;
struct clnp_segment seg_part;
int seg_off=0;
int seg_len;
struct clnp_optidx oidx, *oidxp = NULL;
extern int iso_systype;
extern struct sockaddr_iso blank_siso;
int need_afrin = 0;
IFDEBUG(D_INPUT)
printf(
"clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, %s\n",
m->m_len, m->m_type, IS_CLUSTER(m) ? "cluster" : "normal");
ENDDEBUG
need_afrin = 0;
if (iso_ifaddr == NULL) {
clnp_discard(m, ADDR_DESTUNREACH);
return;
}
INCSTAT(cns_total);
clnp = mtod(m, struct clnp_fixed *);
IFDEBUG(D_DUMPIN)
struct mbuf *mhead;
int total_len = 0;
printf("clnp_input: clnp header:\n");
dump_buf(mtod(m, caddr_t), clnp->cnf_hdr_len);
printf("clnp_input: mbuf chain:\n");
for (mhead = m; mhead != NULL; mhead=mhead->m_next) {
printf("m x%x, len %d\n", mhead, mhead->m_len);
total_len += mhead->m_len;
}
printf("clnp_input: total length of mbuf chain %d:\n", total_len);
ENDDEBUG
if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, (int)clnp->cnf_hdr_len)) {
INCSTAT(cns_badcsum);
clnp_discard(m, GEN_BADCSUM);
return;
}
if (clnp->cnf_vers != ISO8473_V1) {
INCSTAT(cns_badvers);
clnp_discard(m, DISC_UNSUPPVERS);
return;
}
CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len);
if ((m = clnp_data_ck(m, seg_len)) == 0)
return;
clnp = mtod(m, struct clnp_fixed *);
hend = (caddr_t)clnp + clnp->cnf_hdr_len;
source = target = blank_siso;
hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
CLNP_EXTRACT_ADDR(dst, hoff, hend);
if (hoff == (caddr_t)0) {
INCSTAT(cns_badaddr);
clnp_discard(m, GEN_INCOMPLETE);
return;
}
CLNP_EXTRACT_ADDR(src, hoff, hend);
if (hoff == (caddr_t)0) {
INCSTAT(cns_badaddr);
clnp_discard(m, GEN_INCOMPLETE);
return;
}
IFDEBUG(D_INPUT)
printf("clnp_input: from %s", clnp_iso_addrp(&src));
printf(" to %s\n", clnp_iso_addrp(&dst));
ENDDEBUG
if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
(clnp->cnf_type & CNF_SEG_OK)) {
if (hoff + sizeof(struct clnp_segment) > hend) {
INCSTAT(cns_noseg);
clnp_discard(m, GEN_INCOMPLETE);
return;
} else {
(void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment));
seg_part.cng_id = ntohs(seg_part.cng_id);
seg_part.cng_off = ntohs(seg_part.cng_off);
seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len);
seg_off = hoff - (caddr_t)clnp;
hoff += sizeof(struct clnp_segment);
}
}
if (hoff < hend) {
int errcode;
oidxp = &oidx;
errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp);
if ((errcode == 0) && (oidxp->cni_securep))
errcode = DISC_UNSUPPSECURE;
if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) &&
((clnp->cnf_type & CNF_TYPE) != CLNP_ER))
errcode = DISC_UNSUPPOPT;
#ifdef DECBIT
if (oidxp->cni_qos_formatp) {
caddr_t qosp = CLNP_OFFTOOPT(m, oidxp->cni_qos_formatp);
u_char qos = *qosp;
need_afrin = ((qos & (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)) ==
(CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED));
if (need_afrin)
INCSTAT(cns_congest_rcvd);
}
#endif
if (errcode != 0) {
clnp_discard(m, (char)errcode);
IFDEBUG(D_INPUT)
printf("clnp_input: dropped (err x%x) due to bad options\n",
errcode);
ENDDEBUG
return;
}
}
if (clnp_ours(&dst) == 0) {
IFDEBUG(D_INPUT)
printf("clnp_input: forwarding packet not for us\n");
ENDDEBUG
clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp);
return;
}
if ((shp->snh_flags & M_MCAST) && (iso_systype == SNPA_ES)) {
extern short esis_holding_time;
esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time,
shp->snh_shost, 6, &dst);
}
if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
(clnp->cnf_type & CNF_SEG_OK) &&
(seg_len != seg_part.cng_tot_len)) {
struct mbuf *m0;
if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) {
m = m0;
clnp = mtod(m, struct clnp_fixed *);
INCSTAT(cns_reassembled);
} else {
return;
}
}
INCSTAT(cns_delivered);
switch (clnp->cnf_type & CNF_TYPE) {
case CLNP_ER:
if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) {
clnp_discard(m, GEN_HDRSYNTAX);
} else {
clnp_er_input(m, &src, oidxp->cni_er_reason);
}
break;
case CLNP_DT:
(*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &source, &target,
clnp->cnf_hdr_len, need_afrin);
break;
case CLNP_RAW:
case CLNP_ECR:
IFDEBUG(D_INPUT)
printf("clnp_input: raw input of %d bytes\n",
clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len);
ENDDEBUG
(*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &source, &target,
clnp->cnf_hdr_len);
break;
case CLNP_EC:
IFDEBUG(D_INPUT)
printf("clnp_input: echoing packet\n");
ENDDEBUG
(void)clnp_echoreply(m,
(clnp->cnf_type & CNF_SEG_OK ? (int)seg_part.cng_tot_len : seg_len),
&source, &target, oidxp);
break;
default:
printf("clnp_input: unknown clnp pkt type %d\n",
clnp->cnf_type & CNF_TYPE);
clnp_stat.cns_delivered--;
clnp_stat.cns_noproto++;
clnp_discard(m, GEN_HDRSYNTAX);
break;
}
}
#endif