📄 esis.c
字号:
} IFDEBUG(D_ESISINPUT) printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n", ht, naddr, nsellength); ENDDEBUG while (naddr-- > 0) { struct iso_addr *nsap2; u_char *buf2; ESIS_EXTRACT_ADDR(nsap, buf); /* see if there is at least one more nsap in ESH differing only by nsel */ if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) { ESIS_EXTRACT_ADDR(nsap2, buf2); IFDEBUG(D_ESISINPUT) printf("esis_eshinput: comparing %s ", clnp_iso_addrp(nsap)); printf("and %s\n", clnp_iso_addrp(nsap2)); ENDDEBUG if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr, nsap->isoa_len - nsellength) == 0) { nlen = nsellength; break; } } new_entry |= snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_ES, ht, nlen); nlen = 0; } } IFDEBUG(D_ESISINPUT) printf("esis_eshinput: nsap %s is %s\n", clnp_iso_addrp(nsap), new_entry ? "new" : "old"); ENDDEBUG if (new_entry && (iso_systype & SNPA_IS)) esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);bad: return;}/* * FUNCTION: esis_ishinput * * PURPOSE: process an incoming ISH pdu * * RETURNS: * * SIDE EFFECTS: * * NOTES: */esis_ishinput(m, shp)struct mbuf *m; /* esh pdu */struct snpa_hdr *shp; /* subnetwork header */{ struct esis_fixed *pdu = mtod(m, struct esis_fixed *); u_short ht, newct; /* holding time */ struct iso_addr *nsap; /* Network Entity Title */ register u_char *buf = (u_char *) (pdu + 1); register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; int new_entry; esis_stat.es_ishrcvd++; CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); IFDEBUG(D_ESISINPUT) printf("esis_ishinput: ish: ht %d\n", ht); ENDDEBUG if (ESHonly) goto bad; ESIS_EXTRACT_ADDR(nsap, buf); while (buf < buflim) { switch (*buf) { case ESISOVAL_ESCT: if (iso_systype & SNPA_IS) break; if (buf[1] != 2) goto bad; CTOH(buf[2], buf[3], newct); if (esis_config_time != newct) { untimeout(esis_config,0); esis_config_time = newct; esis_config(); } break; default: printf("Unknown ISH option: %x\n", *buf); } ESIS_NEXT_OPTION(buf); } new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0); IFDEBUG(D_ESISINPUT) printf("esis_ishinput: nsap %s is %s\n", clnp_iso_addrp(nsap), new_entry ? "new" : "old"); ENDDEBUG if (new_entry) esis_shoutput(shp->snh_ifp, iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);bad: return;}/* * FUNCTION: esis_rdinput * * PURPOSE: Process an incoming RD pdu * * RETURNS: * * SIDE EFFECTS: * * NOTES: */esis_rdinput(m0, shp)struct mbuf *m0; /* esh pdu */struct snpa_hdr *shp; /* subnetwork header */{ struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); u_short ht; /* holding time */ struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0; register struct iso_addr *bsnpa; register u_char *buf = (u_char *)(pdu + 1); register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; esis_stat.es_rdrcvd++; /* intermediate systems ignore redirects */ if (iso_systype & SNPA_IS) return; if (ESHonly) return; CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); if (buf >= buflim) return; /* Extract DA */ ESIS_EXTRACT_ADDR(da, buf); /* Extract better snpa */ ESIS_EXTRACT_ADDR(bsnpa, buf); /* Extract NET if present */ if (buf < buflim) { if (*buf == 0) buf++; /* no NET present, skip NETL anyway */ else ESIS_EXTRACT_ADDR(net, buf); } /* process options */ while (buf < buflim) { switch (*buf) { case ESISOVAL_SNPAMASK: if (snpamask) /* duplicate */ return; snpamask = (struct iso_addr *)(buf + 1); break; case ESISOVAL_NETMASK: if (netmask) /* duplicate */ return; netmask = (struct iso_addr *)(buf + 1); break; default: printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]); } ESIS_NEXT_OPTION(buf); } IFDEBUG(D_ESISINPUT) printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da)); if (net) printf("\t: net %s\n", clnp_iso_addrp(net)); ENDDEBUG /* * If netl is zero, then redirect is to an ES. We need to add an entry * to the snpa cache for (destination, better snpa). * If netl is not zero, then the redirect is to an IS. In this * case, add an snpa cache entry for (net, better snpa). * * If the redirect is to an IS, add a route entry towards that * IS. */ if (net == 0 || net->isoa_len == 0 || snpamask) { /* redirect to an ES */ snpac_add(shp->snh_ifp, da, bsnpa->isoa_genaddr, SNPA_ES, ht, 0); } else { snpac_add(shp->snh_ifp, net, bsnpa->isoa_genaddr, SNPA_IS, ht, 0); snpac_addrt(shp->snh_ifp, da, net, netmask); }bad: ; /* Needed by ESIS_NEXT_OPTION */}/* * FUNCTION: esis_config * * PURPOSE: Report configuration * * RETURNS: * * SIDE EFFECTS: * * NOTES: Called every esis_config_time seconds */voidesis_config(){ register struct ifnet *ifp; timeout(esis_config, (caddr_t)0, hz * esis_config_time); /* * Report configuration for each interface that * - is UP * - has BROADCAST capability * - has an ISO address */ /* Todo: a better way would be to construct the esh or ish * once and copy it out for all devices, possibly calling * a method in the iso_ifaddr structure to encapsulate and * transmit it. This could work to advantage for non-broadcast media */ for (ifp = ifnet; ifp; ifp = ifp->if_next) { if ((ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_BROADCAST)) { /* search for an ISO address family */ struct ifaddr *ia; for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { if (ia->ifa_addr->sa_family == AF_ISO) { esis_shoutput(ifp, iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, esis_holding_time, (caddr_t)(iso_systype & SNPA_ES ? all_is_snpa : all_es_snpa), 6, (struct iso_addr *)0); break; } } } }}/* * FUNCTION: esis_shoutput * * PURPOSE: Transmit an esh or ish pdu * * RETURNS: nothing * * SIDE EFFECTS: * * NOTES: */esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)struct ifnet *ifp;int type;short ht;caddr_t sn_addr;int sn_len;struct iso_addr *isoa;{ struct mbuf *m, *m0; caddr_t cp, naddrp; int naddr = 0; struct esis_fixed *pdu; struct iso_ifaddr *ia; int len; struct sockaddr_iso siso; if (type == ESIS_ESH) esis_stat.es_eshsent++; else if (type == ESIS_ISH) esis_stat.es_ishsent++; else { printf("esis_shoutput: bad pdu type\n"); return; } IFDEBUG(D_ESISOUTPUT) int i; printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", ht, sn_len); for (i=0; i<sn_len; i++) printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' '); printf("\n"); ENDDEBUG if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { esis_stat.es_nomem++; return; } bzero(mtod(m, caddr_t), MHLEN); pdu = mtod(m, struct esis_fixed *); naddrp = cp = (caddr_t)(pdu + 1); len = sizeof(struct esis_fixed); /* * Build fixed part of header */ pdu->esis_proto_id = ISO9542_ESIS; pdu->esis_vers = ESIS_VERSION; pdu->esis_type = type; HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); if (type == ESIS_ESH) { cp++; len++; } m->m_len = len; if (isoa) { /* * Here we are responding to a clnp packet sent to an NSAP * that is ours which was sent to the MAC addr all_es's. * It is possible that we did not specifically advertise this * NSAP, even though it is ours, so we will respond * directly to the sender that we are here. If we do have * multiple NSEL's we'll tack them on so he can compress them out. */ (void) esis_insert_addr(&cp, &len, isoa, m, 0); naddr = 1; } for (ia = iso_ifaddr; ia; ia = ia->ia_next) { int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0); int n = ia->ia_addr.siso_nlen; register struct iso_ifaddr *ia2; if (type == ESIS_ISH && naddr > 0) break; for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next) if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0) break; if (ia2 != ia) continue; /* Means we have previously copied this nsap */ if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) { isoa = 0; continue; /* Ditto */ } IFDEBUG(D_ESISOUTPUT) printf("esis_shoutput: adding NSAP %s\n", clnp_iso_addrp(&ia->ia_addr.siso_addr)); ENDDEBUG if (!esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m, nsellen)) { EXTEND_PACKET(m, m0, cp); (void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m, nsellen); } naddr++; } if (type == ESIS_ESH) *naddrp = naddr; else { /* add suggested es config timer option to ISH */ if (M_TRAILINGSPACE(m) < 4) { printf("esis_shoutput: extending packet\n"); EXTEND_PACKET(m, m0, cp); } *cp++ = ESISOVAL_ESCT; *cp++ = 2; HTOC(*cp, *(cp+1), esis_esconfig_time); len += 4; m->m_len += 4; IFDEBUG(D_ESISOUTPUT) printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n", m0, m, m->m_data, m->m_len, cp); ENDDEBUG } m0->m_pkthdr.len = len; pdu->esis_hdr_len = len; iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); bzero((caddr_t)&siso, sizeof(siso)); siso.siso_family = AF_ISO; siso.siso_data[0] = AFI_SNA; siso.siso_nlen = sn_len + 1; bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len); (ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0);}/* * FUNCTION: isis_input * * PURPOSE: Process an incoming isis packet * * RETURNS: nothing * * SIDE EFFECTS: * * NOTES: */isis_input(m0, shp)struct mbuf *m0; /* ptr to first mbuf of pkt */struct snpa_hdr *shp; /* subnetwork header */{ register int type; register struct rawcb *rp, *first_rp = 0; struct ifnet *ifp = shp->snh_ifp; char workbuf[16]; struct mbuf *mm; IFDEBUG(D_ISISINPUT) int i; printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp, ifp->if_name, ifp->if_unit); for (i=0; i<6; i++) printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' '); printf(" to:"); for (i=0; i<6; i++) printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' '); printf("\n"); ENDDEBUG esis_dl.sdl_alen = ifp->if_addrlen; esis_dl.sdl_index = ifp->if_index; bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen); for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) { if (first_rp == 0) { first_rp = rp; continue; } if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */ if (sbappendaddr(&rp->rcb_socket->so_rcv, &esis_dl, mm, (struct mbuf *)0) != 0) { sorwakeup(rp->rcb_socket); } else { IFDEBUG(D_ISISINPUT) printf("Error in sbappenaddr, mm = 0x%x\n", mm); ENDDEBUG m_freem(mm); } } } if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv, &esis_dl, m0, (struct mbuf *)0) != 0) { sorwakeup(first_rp->rcb_socket); return; } m_freem(m0);}isis_output(sdl, m)register struct sockaddr_dl *sdl;struct mbuf *m;{ register struct ifnet *ifp; struct ifaddr *ifa, *ifa_ifwithnet(); struct sockaddr_iso siso; int error = 0; unsigned sn_len; ifa = ifa_ifwithnet((struct sockaddr *)sdl); /* get ifp from sdl */ if (ifa == 0) { IFDEBUG(D_ISISOUTPUT) printf("isis_output: interface not found\n"); ENDDEBUG error = EINVAL; goto release; } ifp = ifa->ifa_ifp; sn_len = sdl->sdl_alen; IFDEBUG(D_ISISOUTPUT) u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len; printf("isis_output: ifp 0x%x (%s%d), to: ", ifp, ifp->if_name, ifp->if_unit); while (cp < cplim) { printf("%x", *cp++); printf("%c", (cp < cplim) ? ':' : ' '); } printf("\n"); ENDDEBUG bzero((caddr_t)&siso, sizeof(siso)); siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */ siso.siso_data[0] = AFI_SNA; siso.siso_nlen = sn_len + 1; bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len); error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0); if (error) { IFDEBUG(D_ISISOUTPUT) printf("isis_output: error from ether_output is %d\n", error); ENDDEBUG } return (error);release: if (m != NULL) m_freem(m); return(error);}/* * FUNCTION: esis_ctlinput * * PURPOSE: Handle the PRC_IFDOWN transition * * RETURNS: nothing * * SIDE EFFECTS: * * NOTES: Calls snpac_flush for interface specified. * The loop through iso_ifaddr is stupid because * back in if_down, we knew the ifp... */esis_ctlinput(req, siso)int req; /* request: we handle only PRC_IFDOWN */struct sockaddr_iso *siso; /* address of ifp */{ register struct iso_ifaddr *ia; /* scan through interface addresses */ if (req == PRC_IFDOWN) for (ia = iso_ifaddr; ia; ia = ia->ia_next) { if (iso_addrmatch(IA_SIS(ia), siso)) snpac_flushifp(ia->ia_ifp); }}#endif /* ISO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -