Exemplo n.º 1
0
/*
 * Route an outgoing frame from a socket.
 */
int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
			struct iovec *iov, size_t len, int noblock)
{
	struct sk_buff *skb;
	struct ipx_sock *ipxs = ipx_sk(sk);
	struct ipx_interface *intrfc;
	struct ipxhdr *ipx;
	size_t size;
	int ipx_offset;
	struct ipx_route *rt = NULL;
	int rc;

	/* Find the appropriate interface on which to send packet */
	if (!usipx->sipx_network && ipx_primary_net) {
		usipx->sipx_network = ipx_primary_net->if_netnum;
		intrfc = ipx_primary_net;
	} else {
		rt = ipxrtr_lookup(usipx->sipx_network);
		rc = -ENETUNREACH;
		if (!rt)
			goto out;
		intrfc = rt->ir_intrfc;
	}

	ipxitf_hold(intrfc);
	ipx_offset = intrfc->if_ipx_offset;
	size = sizeof(struct ipxhdr) + len + ipx_offset;

	skb = sock_alloc_send_skb(sk, size, noblock, &rc);
	if (!skb)
		goto out_put;

	skb_reserve(skb, ipx_offset);
	skb->sk = sk;

	/* Fill in IPX header */
	skb_reset_network_header(skb);
	skb_reset_transport_header(skb);
	skb_put(skb, sizeof(struct ipxhdr));
	ipx = ipx_hdr(skb);
	ipx->ipx_pktsize = htons(len + sizeof(struct ipxhdr));
	IPX_SKB_CB(skb)->ipx_tctrl = 0;
	ipx->ipx_type 	 = usipx->sipx_type;

	IPX_SKB_CB(skb)->last_hop.index = -1;
#ifdef CONFIG_IPX_INTERN
	IPX_SKB_CB(skb)->ipx_source_net = ipxs->intrfc->if_netnum;
	memcpy(ipx->ipx_source.node, ipxs->node, IPX_NODE_LEN);
#else
	rc = ntohs(ipxs->port);
	if (rc == 0x453 || rc == 0x452) {
		/* RIP/SAP special handling for mars_nwe */
		IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum;
		memcpy(ipx->ipx_source.node, intrfc->if_node, IPX_NODE_LEN);
	} else {
		IPX_SKB_CB(skb)->ipx_source_net = ipxs->intrfc->if_netnum;
		memcpy(ipx->ipx_source.node, ipxs->intrfc->if_node,
			IPX_NODE_LEN);
	}
#endif	/* CONFIG_IPX_INTERN */
	ipx->ipx_source.sock		= ipxs->port;
	IPX_SKB_CB(skb)->ipx_dest_net	= usipx->sipx_network;
	memcpy(ipx->ipx_dest.node, usipx->sipx_node, IPX_NODE_LEN);
	ipx->ipx_dest.sock		= usipx->sipx_port;

	rc = memcpy_fromiovec(skb_put(skb, len), iov, len);
	if (rc) {
		kfree_skb(skb);
		goto out_put;
	}

	/* Apply checksum. Not allowed on 802.3 links. */
	if (sk->sk_no_check || intrfc->if_dlink_type == htons(IPX_FRAME_8023))
		ipx->ipx_checksum = htons(0xFFFF);
	else
		ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr));

	rc = ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ?
			 rt->ir_router_node : ipx->ipx_dest.node);
out_put:
	ipxitf_put(intrfc);
	if (rt)
		ipxrtr_put(rt);
out:
	return rc;
}
Exemplo n.º 2
0
/*
 * 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;
}
Exemplo n.º 3
0
/*
 * 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);
}