xref: /csrg-svn/sys/netns/ns_output.c (revision 33371)
123211Smckusick /*
2*33371Ssklower  * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California.
3*33371Ssklower  * All rights reserved.
423211Smckusick  *
5*33371Ssklower  * Redistribution and use in source and binary forms are permitted
6*33371Ssklower  * provided that this notice is preserved and that due credit is given
7*33371Ssklower  * to the University of California at Berkeley. The name of the University
8*33371Ssklower  * may not be used to endorse or promote products derived from this
9*33371Ssklower  * software without specific prior written permission. This software
10*33371Ssklower  * is provided ``as is'' without express or implied warranty.
11*33371Ssklower  *
12*33371Ssklower  *      @(#)ns_output.c	7.2 (Berkeley) 01/20/88
1323211Smckusick  */
1421488Ssklower 
1521488Ssklower #include "param.h"
1621488Ssklower #include "mbuf.h"
1721488Ssklower #include "errno.h"
1821488Ssklower #include "socket.h"
1921488Ssklower #include "socketvar.h"
2021488Ssklower 
2121488Ssklower #include "../net/if.h"
2221488Ssklower #include "../net/route.h"
2321488Ssklower 
2421488Ssklower #include "ns.h"
2521488Ssklower #include "ns_if.h"
2621488Ssklower #include "idp.h"
2721488Ssklower #include "idp_var.h"
2821488Ssklower 
2921488Ssklower #ifdef vax
3021488Ssklower #include "../vax/mtpr.h"
3121488Ssklower #endif
3221745Ssklower int ns_hold_output = 0;
3321745Ssklower int ns_copy_output = 0;
3421745Ssklower int ns_output_cnt = 0;
3521488Ssklower struct mbuf *ns_lastout;
3621488Ssklower 
3721488Ssklower ns_output(m0, ro, flags)
3821488Ssklower 	struct mbuf *m0;
3921488Ssklower 	struct route *ro;
4021488Ssklower 	int flags;
4121488Ssklower {
4221488Ssklower 	register struct idp *idp = mtod(m0, struct idp *);
4325043Ssklower 	register struct ifnet *ifp = 0;
4424226Ssklower 	int error = 0;
4521488Ssklower 	struct route idproute;
4621488Ssklower 	struct sockaddr_ns *dst;
4721488Ssklower 	extern int idpcksum;
4821488Ssklower 
4923501Ssklower 	if (ns_hold_output) {
5023501Ssklower 		if (ns_lastout) {
5126389Skarels 			(void)m_free(ns_lastout);
5221488Ssklower 		}
5324226Ssklower 		ns_lastout = m_copy(m0, 0, (int)M_COPYALL);
5421488Ssklower 	}
5521488Ssklower 	/*
5621488Ssklower 	 * Route packet.
5721488Ssklower 	 */
5821488Ssklower 	if (ro == 0) {
5921488Ssklower 		ro = &idproute;
6021488Ssklower 		bzero((caddr_t)ro, sizeof (*ro));
6121488Ssklower 	}
6221488Ssklower 	dst = (struct sockaddr_ns *)&ro->ro_dst;
6321488Ssklower 	if (ro->ro_rt == 0) {
6421488Ssklower 		dst->sns_family = AF_NS;
6521488Ssklower 		dst->sns_addr = idp->idp_dna;
6623501Ssklower 		dst->sns_addr.x_port = 0;
6721488Ssklower 		/*
6821488Ssklower 		 * If routing to interface only,
6921488Ssklower 		 * short circuit routing lookup.
7021488Ssklower 		 */
7121488Ssklower 		if (flags & NS_ROUTETOIF) {
7225043Ssklower 			struct ns_ifaddr *ia = ns_iaonnetof(&idp->idp_dna);
7324731Ssklower 
7421488Ssklower 			if (ia == 0) {
7521488Ssklower 				error = ENETUNREACH;
7621488Ssklower 				goto bad;
7721488Ssklower 			}
7821488Ssklower 			ifp = ia->ia_ifp;
7921488Ssklower 			goto gotif;
8021488Ssklower 		}
8121488Ssklower 		rtalloc(ro);
8221488Ssklower 	} else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) {
8321488Ssklower 		/*
8421488Ssklower 		 * The old route has gone away; try for a new one.
8521488Ssklower 		 */
8621488Ssklower 		rtfree(ro->ro_rt);
8725510Ssklower 		ro->ro_rt = NULL;
8821488Ssklower 		rtalloc(ro);
8921488Ssklower 	}
9021488Ssklower 	if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
9121488Ssklower 		error = ENETUNREACH;
9221488Ssklower 		goto bad;
9321488Ssklower 	}
9421488Ssklower 	ro->ro_rt->rt_use++;
9521488Ssklower 	if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
9621488Ssklower 		dst = (struct sockaddr_ns *)&ro->ro_rt->rt_gateway;
9721488Ssklower gotif:
9821488Ssklower 
9921488Ssklower 	/*
10021488Ssklower 	 * Look for multicast addresses and
10121488Ssklower 	 * and verify user is allowed to send
10221488Ssklower 	 * such a packet.
10321488Ssklower 	 */
10421488Ssklower 	if (dst->sns_addr.x_host.c_host[0]&1) {
10521488Ssklower 		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
10621488Ssklower 			error = EADDRNOTAVAIL;
10721488Ssklower 			goto bad;
10821488Ssklower 		}
10921488Ssklower 		if ((flags & NS_ALLOWBROADCAST) == 0) {
11021488Ssklower 			error = EACCES;
11121488Ssklower 			goto bad;
11221488Ssklower 		}
11321488Ssklower 	}
11421488Ssklower 
11521488Ssklower 	if (htons(idp->idp_len) <= ifp->if_mtu) {
11621488Ssklower 		ns_output_cnt++;
11725043Ssklower 		if (ns_copy_output) {
11825043Ssklower 			ns_watch_output(m0, ifp);
11925043Ssklower 		}
12021488Ssklower 		error = (*ifp->if_output)(ifp, m0, (struct sockaddr *)dst);
12121488Ssklower 		goto done;
12221488Ssklower 	} else error = EMSGSIZE;
12321488Ssklower 
12421488Ssklower 
12521488Ssklower bad:
12625043Ssklower 	if (ns_copy_output) {
12725043Ssklower 		ns_watch_output(m0, ifp);
12825043Ssklower 	}
12921488Ssklower 	m_freem(m0);
13021488Ssklower done:
13121488Ssklower 	if (ro == &idproute && (flags & NS_ROUTETOIF) == 0 && ro->ro_rt)
13221488Ssklower 		RTFREE(ro->ro_rt);
13321488Ssklower 	return (error);
13421488Ssklower }
135