/* * Return address info for specified internet network. */ struct ipx_ifaddr * ipx_iaonnetof(struct ipx_addr *dst) { struct ipx_ifaddr *ia; struct ipx_addr *compare; struct ifnet *ifp; struct ipx_ifaddr *ia_maybe = NULL; union ipx_net net = dst->x_net; for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) { if ((ifp = ia->ia_ifp) != NULL) { if (ifp->if_flags & IFF_POINTOPOINT) { compare = &satoipx_addr(ia->ia_dstaddr); if (ipx_hosteq(*dst, *compare)) return (ia); if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) ia_maybe = ia; } else { if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net)) return (ia); } } } return (ia_maybe); }
void ipxnet_output(int s, int flags, struct sockaddr_ipx *sipx, int size) { struct sockaddr_ipx dst; dst = *sipx; sipx = &dst; if (sipx->sipx_addr.x_port == 0) sipx->sipx_addr.x_port = htons(IPXPORT_RIP); #ifdef DEBUG if(do_output || ntohs(msg->rip_cmd) == RIPCMD_REQUEST) #endif /* * Kludge to allow us to get routes out to machines that * don't know their addresses yet; send to that address on * ALL connected nets */ if (ipx_neteqnn(sipx->sipx_addr.x_net, ipx_zeronet)) { extern struct interface *ifnet; struct interface *ifp; for (ifp = ifnet; ifp; ifp = ifp->int_next) { sipx->sipx_addr.x_net = satoipx_addr(ifp->int_addr).x_net; sendto(s, msg, size, flags, (struct sockaddr *)sipx, sizeof (*sipx)); } return; } sendto(s, msg, size, flags, (struct sockaddr *)sipx, sizeof (*sipx)); }
/* * This may also be called for raw listeners. */ void ipx_input(struct mbuf *m, struct ipxpcb *ipxp) { struct ipx *ipx = mtod(m, struct ipx *); struct ifnet *ifp = m->m_pkthdr.rcvif; struct sockaddr_ipx ipx_ipx; KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb")); IPX_LOCK_ASSERT(ipxp); /* * Construct sockaddr format source address. * Stuff source address and datagram in user buffer. */ ipx_ipx.sipx_len = sizeof(ipx_ipx); ipx_ipx.sipx_family = AF_IPX; ipx_ipx.sipx_addr = ipx->ipx_sna; ipx_ipx.sipx_zero[0] = '\0'; ipx_ipx.sipx_zero[1] = '\0'; if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { struct ifaddr *ifa; for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_link)) { if (ifa->ifa_addr->sa_family == AF_IPX) { ipx_ipx.sipx_addr.x_net = IA_SIPX(ifa)->sipx_addr.x_net; break; } } } ipxp->ipxp_rpt = ipx->ipx_pt; if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) { m->m_len -= sizeof(struct ipx); m->m_pkthdr.len -= sizeof(struct ipx); m->m_data += sizeof(struct ipx); } #ifdef MAC if (mac_socket_check_deliver(ipxp->ipxp_socket, m) != 0) { m_freem(m); return; } #endif if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, m, NULL) == 0) m_freem(m); else sorwakeup(ipxp->ipxp_socket); }
void process(int fd, int pkt_type) { struct sockaddr from; int fromlen = sizeof (from), cc, omask; struct ipx *ipxdp = (struct ipx *)packet; cc = recvfrom(fd, packet, sizeof (packet), 0, &from, &fromlen); if (cc <= 0) { if (cc < 0 && errno != EINTR) syslog(LOG_ERR, "recvfrom: %m"); return; } if (tracepackets > 1 && ftrace) { fprintf(ftrace,"rcv %d bytes on %s ", cc, ipxdp_ntoa(&ipxdp->ipx_dna)); fprintf(ftrace," from %s\n", ipxdp_ntoa(&ipxdp->ipx_sna)); } if (noteremoterequests && !ipx_neteqnn(ipxdp->ipx_sna.x_net, ipx_zeronet) && !ipx_neteq(ipxdp->ipx_sna, ipxdp->ipx_dna)) { syslog(LOG_ERR, "net of interface (%s) != net on ether (%s)!\n", ipxdp_nettoa(ipxdp->ipx_dna.x_net), ipxdp_nettoa(ipxdp->ipx_sna.x_net)); } /* We get the IPX header in front of the RIF packet*/ cc -= sizeof (struct ipx); #define mask(s) (1<<((s)-1)) omask = sigblock(mask(SIGALRM)); switch(pkt_type) { case SAP_PKT: sap_input(&from, cc); break; case RIP_PKT: rip_input(&from, cc); break; } sigsetmask(omask); }
/* * IPX input routine. Pass to next level. */ void ipxintr() { register struct ipx *ipx; register struct mbuf *m; register struct ipxpcb *ipxp; struct ipx_ifaddr *ia; register int i; int len, s; char oddshortpacket = 0; next: /* * Get next datagram off input queue and get IPX header * in first mbuf. */ s = splimp(); IF_DEQUEUE(&ipxintrq, m); splx(s); if (m == NULL) return; /* * If no IPX addresses have been set yet but the interfaces * are receiving, can't do anything with incoming packets yet. */ if (ipx_ifaddr == NULL) goto bad; ipxstat.ipxs_total++; if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) && (m = m_pullup(m, sizeof(struct ipx))) == 0) { ipxstat.ipxs_toosmall++; goto next; } /* * Give any raw listeners a crack at the packet */ for (ipxp = ipxrawpcb.ipxp_next; ipxp != &ipxrawpcb; ipxp = ipxp->ipxp_next) { struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL); if (m1 != NULL) ipx_input(m1, ipxp); } ipx = mtod(m, struct ipx *); len = ntohs(ipx->ipx_len); if ((len < m->m_pkthdr.len) && (oddshortpacket = len & 1)) { /* * If this packet is of odd length, and the length * inside the header is less than the received packet * length, preserve garbage byte for possible checksum. */ len++; } /* * Check that the amount of data in the buffers * is as at least much as the IPX header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_pkthdr.len < len) { ipxstat.ipxs_tooshort++; goto bad; } if (m->m_pkthdr.len > len) { if (m->m_len == m->m_pkthdr.len) { m->m_len = len; m->m_pkthdr.len = len; } else m_adj(m, len - m->m_pkthdr.len); } if (ipxcksum && ((i = ipx->ipx_sum) != 0xffff)) { ipx->ipx_sum = 0; if (i != (ipx->ipx_sum = ipx_cksum(m, len))) { ipxstat.ipxs_badsum++; goto bad; } } /* * Propagated (Netbios) packets (type 20) has to be handled * different. :-( */ if (ipx->ipx_pt == IPXPROTO_NETBIOS) { if (ipxnetbios) { ipx_output_type20(m); goto next; } else goto bad; } /* * Is this a directed broadcast? */ if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) { if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) && (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) && (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) && (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) { /* * If it is a broadcast to the net where it was * received from, treat it as ours. */ for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) && ipx_neteq(ia->ia_addr.sipx_addr, ipx->ipx_dna)) goto ours; /* * Look to see if I need to eat this packet. * Algorithm is to forward all young packets * and prematurely age any packets which will * by physically broadcasted. * Any very old packets eaten without forwarding * would die anyway. * * Suggestion of Bill Nesheim, Cornell U. */ if (ipx->ipx_tc < IPX_MAXHOPS) { ipx_forward(m); goto next; } } /* * Is this our packet? If not, forward. */ } else { for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) && (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) || ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet))) break; if (ia == NULL) { ipx_forward(m); goto next; } } ours: /* * Locate pcb for datagram. */ ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD); /* * Switch out to protocol's input routine. */ if (ipxp != NULL) { if (oddshortpacket) { m_adj(m, -1); } ipxstat.ipxs_delivered++; if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0) switch (ipx->ipx_pt) { case IPXPROTO_SPX: spx_input(m, ipxp); goto next; } ipx_input(m, ipxp); } else goto bad; goto next; bad: m_freem(m); goto next; }
/* * Supply dst with the contents of the routing tables. * If this won't fit in one packet, chop it up into several. * * This must be done using the split horizon algorithm. * 1. Don't send routing info to the interface from where it was received. * 2. Don't publish an interface to itself. * 3. If a route is received from more than one interface and the cost is * the same, don't publish it on either interface. I am calling this * clones. */ void supply(struct sockaddr *dst, int flags, struct interface *ifp, int changesonly) { struct rt_entry *rt; struct rt_entry *crt; /* Clone route */ struct rthash *rh; struct netinfo *nn; struct netinfo *n = msg->rip_nets; struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) dst; af_output_t *output = afswitch[dst->sa_family].af_output; int size, metric, ticks; union ipx_net net; int delay = 0; if (sipx->sipx_port == 0) sipx->sipx_port = htons(IPXPORT_RIP); msg->rip_cmd = ntohs(RIPCMD_RESPONSE); for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) { for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { size = (char *)n - (char *)msg; if (size >= ((MAXRIPNETS * sizeof (struct netinfo)) + sizeof (msg->rip_cmd))) { (*output)(ripsock, flags, dst, size); TRACE_OUTPUT(ifp, dst, size); n = msg->rip_nets; delay++; if(delay == 2) { usleep(50000); delay = 0; } } if (changesonly && !(rt->rt_state & RTS_CHANGED)) continue; /* * This should do rule one and two of the split horizon * algorithm. */ if (rt->rt_ifp == ifp) continue; /* * Rule 3. * Look if we have clones (different routes to the same * place with exactly the same cost). * * We should not publish on any of the clone * interfaces. */ crt = rt->rt_clone; while (crt) { if (crt->rt_ifp == ifp) goto next; crt = crt->rt_clone; } sipx = (struct sockaddr_ipx *)&rt->rt_dst; if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST) sipx = (struct sockaddr_ipx *)&rt->rt_router; if (rt->rt_metric == HOPCNT_INFINITY) metric = HOPCNT_INFINITY; else { metric = rt->rt_metric + 1; /* * We don't advertize routes with more than * 15 hops. */ if (metric >= HOPCNT_INFINITY) continue; } /* * XXX One day we should cater for slow interfaces * also. */ ticks = rt->rt_ticks + 1; net = sipx->sipx_addr.x_net; /* * Make sure that we don't put out a two net entries * for a pt to pt link (one for the G route, one for * the if) * This is a kludge, and won't work if there are lots * of nets. */ for (nn = msg->rip_nets; nn < n; nn++) { if (ipx_neteqnn(net, nn->rip_dst)) { if (ticks < ntohs(nn->rip_ticks)) { nn->rip_metric = htons(metric); nn->rip_ticks = htons(ticks); } else if ((ticks == ntohs(nn->rip_ticks)) && (metric < ntohs(nn->rip_metric))) { nn->rip_metric = htons(metric); nn->rip_ticks = htons(ticks); } goto next; } } n->rip_dst = net; n->rip_metric = htons(metric); n->rip_ticks = htons(ticks); n++; next: ; } if (n != msg->rip_nets) { size = (char *)n - (char *)msg; (*output)(ripsock, flags, dst, size); TRACE_OUTPUT(ifp, dst, size); } } }
/* * This will broadcast the type 20 (Netbios) packet to all the interfaces * that have ipx configured and isn't in the list yet. */ int ipx_output_type20(struct mbuf *m) { struct ipx *ipx; union ipx_net *nbnet; struct ipx_ifaddr *ia, *tia = NULL; int error = 0; struct mbuf *m1; int i; struct ifnet *ifp; struct sockaddr_ipx dst; /* * We have to get to the 32 bytes after the ipx header also, so * that we can fill in the network address of the receiving * interface. */ if ((m->m_flags & M_EXT || m->m_len < (sizeof(struct ipx) + 32)) && (m = m_pullup(m, sizeof(struct ipx) + 32)) == NULL) { ipxstat.ipxs_toosmall++; return (0); } ipx = mtod(m, struct ipx *); nbnet = (union ipx_net *)(ipx + 1); if (ipx->ipx_tc >= 8) goto bad; /* * Now see if we have already seen this. */ for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if(ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) { if(tia == NULL) tia = ia; for (i=0;i<ipx->ipx_tc;i++,nbnet++) if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net, *nbnet)) goto bad; } /* * Don't route the packet if the interface where it come from * does not have an IPX address. */ if(tia == NULL) goto bad; /* * Add our receiving interface to the list. */ nbnet = (union ipx_net *)(ipx + 1); nbnet += ipx->ipx_tc; *nbnet = tia->ia_addr.sipx_addr.x_net; /* * Increment the hop count. */ ipx->ipx_tc++; ipxstat.ipxs_forward++; /* * Send to all directly connected ifaces not in list and * not to the one it came from. */ m->m_flags &= ~M_BCAST; bzero(&dst, sizeof(dst)); dst.sipx_family = AF_IPX; dst.sipx_len = 12; dst.sipx_addr.x_host = ipx_broadhost; for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if(ia->ia_ifa.ifa_ifp != m->m_pkthdr.rcvif) { nbnet = (union ipx_net *)(ipx + 1); for (i=0;i<ipx->ipx_tc;i++,nbnet++) if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net, *nbnet)) goto skip_this; /* * Insert the net address of the dest net and * calculate the new checksum if needed. */ ifp = ia->ia_ifa.ifa_ifp; dst.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; ipx->ipx_dna.x_net = dst.sipx_addr.x_net; if(ipx->ipx_sum != 0xffff) ipx->ipx_sum = ipx_cksum(m, ntohs(ipx->ipx_len)); m1 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT); if(m1) { error = ifp->if_output(ifp, m1, (struct sockaddr *)&dst, NULL); /* XXX ipxstat.ipxs_localout++; */ } skip_this: ; } bad: m_freem(m); return (error); }