xref: /csrg-svn/sys/netns/ns_output.c (revision 34856)
1 /*
2  * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)ns_output.c	7.3 (Berkeley) 06/29/88
18  */
19 
20 #include "param.h"
21 #include "mbuf.h"
22 #include "errno.h"
23 #include "socket.h"
24 #include "socketvar.h"
25 
26 #include "../net/if.h"
27 #include "../net/route.h"
28 
29 #include "ns.h"
30 #include "ns_if.h"
31 #include "idp.h"
32 #include "idp_var.h"
33 
34 #ifdef vax
35 #include "../vax/mtpr.h"
36 #endif
37 int ns_hold_output = 0;
38 int ns_copy_output = 0;
39 int ns_output_cnt = 0;
40 struct mbuf *ns_lastout;
41 
42 ns_output(m0, ro, flags)
43 	struct mbuf *m0;
44 	struct route *ro;
45 	int flags;
46 {
47 	register struct idp *idp = mtod(m0, struct idp *);
48 	register struct ifnet *ifp = 0;
49 	int error = 0;
50 	struct route idproute;
51 	struct sockaddr_ns *dst;
52 	extern int idpcksum;
53 
54 	if (ns_hold_output) {
55 		if (ns_lastout) {
56 			(void)m_free(ns_lastout);
57 		}
58 		ns_lastout = m_copy(m0, 0, (int)M_COPYALL);
59 	}
60 	/*
61 	 * Route packet.
62 	 */
63 	if (ro == 0) {
64 		ro = &idproute;
65 		bzero((caddr_t)ro, sizeof (*ro));
66 	}
67 	dst = (struct sockaddr_ns *)&ro->ro_dst;
68 	if (ro->ro_rt == 0) {
69 		dst->sns_family = AF_NS;
70 		dst->sns_addr = idp->idp_dna;
71 		dst->sns_addr.x_port = 0;
72 		/*
73 		 * If routing to interface only,
74 		 * short circuit routing lookup.
75 		 */
76 		if (flags & NS_ROUTETOIF) {
77 			struct ns_ifaddr *ia = ns_iaonnetof(&idp->idp_dna);
78 
79 			if (ia == 0) {
80 				error = ENETUNREACH;
81 				goto bad;
82 			}
83 			ifp = ia->ia_ifp;
84 			goto gotif;
85 		}
86 		rtalloc(ro);
87 	} else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) {
88 		/*
89 		 * The old route has gone away; try for a new one.
90 		 */
91 		rtfree(ro->ro_rt);
92 		ro->ro_rt = NULL;
93 		rtalloc(ro);
94 	}
95 	if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
96 		error = ENETUNREACH;
97 		goto bad;
98 	}
99 	ro->ro_rt->rt_use++;
100 	if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
101 		dst = (struct sockaddr_ns *)&ro->ro_rt->rt_gateway;
102 gotif:
103 
104 	/*
105 	 * Look for multicast addresses and
106 	 * and verify user is allowed to send
107 	 * such a packet.
108 	 */
109 	if (dst->sns_addr.x_host.c_host[0]&1) {
110 		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
111 			error = EADDRNOTAVAIL;
112 			goto bad;
113 		}
114 		if ((flags & NS_ALLOWBROADCAST) == 0) {
115 			error = EACCES;
116 			goto bad;
117 		}
118 	}
119 
120 	if (htons(idp->idp_len) <= ifp->if_mtu) {
121 		ns_output_cnt++;
122 		if (ns_copy_output) {
123 			ns_watch_output(m0, ifp);
124 		}
125 		error = (*ifp->if_output)(ifp, m0, (struct sockaddr *)dst);
126 		goto done;
127 	} else error = EMSGSIZE;
128 
129 
130 bad:
131 	if (ns_copy_output) {
132 		ns_watch_output(m0, ifp);
133 	}
134 	m_freem(m0);
135 done:
136 	if (ro == &idproute && (flags & NS_ROUTETOIF) == 0 && ro->ro_rt)
137 		RTFREE(ro->ro_rt);
138 	return (error);
139 }
140