xref: /csrg-svn/sys/netns/ns_pcb.c (revision 21489)
1 /*	ns_pcb.c	6.1	85/05/30	*/
2 
3 #include "param.h"
4 #include "systm.h"
5 #include "dir.h"
6 #include "user.h"
7 #include "mbuf.h"
8 #include "socket.h"
9 #include "socketvar.h"
10 #include "../net/if.h"
11 #include "../net/route.h"
12 #include "protosw.h"
13 
14 #include "ns.h"
15 #include "ns_if.h"
16 #include "ns_pcb.h"
17 
18 struct	ns_addr zerons_addr;
19 
20 ns_pcballoc(so, head)
21 	struct socket *so;
22 	struct nsp *head;
23 {
24 	struct mbuf *m;
25 	register struct nspcb *nsp;
26 
27 	m = m_getclr(M_DONTWAIT, MT_PCB);
28 	if (m == NULL)
29 		return (ENOBUFS);
30 	nsp = mtod(m, struct nspcb *);
31 	nsp->nsp_socket = so;
32 	insque(nsp, head);
33 	so->so_pcb = (caddr_t)nsp;
34 	return (0);
35 }
36 
37 ns_pcbbind(nsp, nam)
38 	register struct nspcb *nsp;
39 	struct mbuf *nam;
40 {
41 	register struct sockaddr_ns *sns;
42 	u_short lport = 0;
43 
44 	if(nsp->nsp_lport || !ns_nullhost(nsp->nsp_laddr))
45 		return (EINVAL);
46 	if (nam == 0)
47 		goto noname;
48 	sns = mtod(nam, struct sockaddr_ns *);
49 	if (nam->m_len != sizeof (*sns))
50 		return (EINVAL);
51 	if (!ns_nullhost(sns->sns_addr)) {
52 		int tport = sns->sns_port;
53 
54 		sns->sns_port = 0;		/* yech... */
55 		if (ifa_ifwithaddr((struct sockaddr *)sns) == 0)
56 			return (EADDRNOTAVAIL);
57 		sns->sns_port = tport;
58 	}
59 	lport = sns->sns_port;
60 	if (lport) {
61 		u_short aport = ntohs(lport);
62 
63 		if (aport < NSPORT_RESERVED && u.u_uid != 0)
64 			return (EACCES);
65 		if (ns_pcblookup(&zerons_addr, lport, 0))
66 			return (EADDRINUSE);
67 	}
68 	nsp->nsp_laddr = sns->sns_addr;
69 noname:
70 	if (lport == 0)
71 		do {
72 			if (nspcb.nsp_lport++ < NSPORT_RESERVED)
73 				nspcb.nsp_lport = NSPORT_RESERVED;
74 			lport = htons(nspcb.nsp_lport);
75 		} while (ns_pcblookup(&zerons_addr, lport, 0));
76 	nsp->nsp_lport = lport;
77 	return (0);
78 }
79 
80 /*
81  * Connect from a socket to a specified address.
82  * Both address and port must be specified in argument sns.
83  * If don't have a local address for this socket yet,
84  * then pick one.
85  */
86 ns_pcbconnect(nsp, nam)
87 	struct nspcb *nsp;
88 	struct mbuf *nam;
89 {
90 	struct ns_ifaddr *ia;
91 	struct sockaddr_ns *ifaddr;
92 	register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
93 
94 	if (nam->m_len != sizeof (*sns))
95 		return (EINVAL);
96 	if (sns->sns_family != AF_NS)
97 		return (EAFNOSUPPORT);
98 	if (sns->sns_port==0 || ns_nullhost(sns->sns_addr))
99 		return (EADDRNOTAVAIL);
100 	if (ns_nullhost(nsp->nsp_laddr) &&
101 	    ((*(long *)&nsp->nsp_lastnet)!=ns_netof(sns->sns_addr))) {
102 		ia = (struct ns_ifaddr *)ifa_ifwithnet((struct sockaddr *)sns);
103 		if (ia == 0) {
104 			register struct route *ro;
105 			struct ifnet *ifp;
106 
107 			/*
108 			 * If route is known or can be allocated now,
109 			 * our src addr is taken from the i/f, else punt.
110 			 */
111 			ro = &nsp->nsp_route;
112 #define	satosns(sa)	((struct sockaddr_ns *)(sa))
113 			if (ro->ro_rt &&
114 				!ns_hosteq(satosns(&ro->ro_dst)->sns_addr,
115 					sns->sns_addr)) {
116 				RTFREE(ro->ro_rt);
117 				ro->ro_rt = (struct rtentry *)0;
118 			}
119 			if ((ro->ro_rt == (struct rtentry *)0) ||
120 			    (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0) {
121 				/* No route yet, so try to acquire one */
122 				ro->ro_dst.sa_family = AF_NS;
123 				((struct sockaddr_ns *) &ro->ro_dst)->sns_addr =
124 					sns->sns_addr;
125 				rtalloc(ro);
126 				if (ro->ro_rt == 0)
127 					ia = (struct ns_ifaddr *) 0;
128 				else
129 				    for (ia = ns_ifaddr; ia; ia = ia->ia_next)
130 					if (ia->ia_ifp == ifp)
131 					    break;
132 			}
133 			if (ia == 0)
134 				ia = ns_ifaddr;
135 			if (ia == 0)
136 				return (EADDRNOTAVAIL);
137 		}
138 		ifaddr = (struct sockaddr_ns *)&ia->ia_addr;
139 		nsp->nsp_laddr.x_net = ifaddr->sns_addr.x_net;
140 		nsp->nsp_lastnet = sns->sns_addr.x_net;
141 	}
142 	if (ns_pcblookup(&sns->sns_addr, nsp->nsp_lport, 0))
143 		return (EADDRINUSE);
144 	if (ns_nullhost(nsp->nsp_laddr)) {
145 		if (nsp->nsp_lport == 0)
146 			ns_pcbbind(nsp, (struct mbuf *)0);
147 		nsp->nsp_laddr.x_host = ns_thishost;
148 	}
149 	nsp->nsp_faddr = sns->sns_addr;
150 	/* Includes nsp->nsp_fport = sns->sns_port; */
151 	return (0);
152 }
153 
154 ns_pcbdisconnect(nsp)
155 	struct nspcb *nsp;
156 {
157 
158 	nsp->nsp_faddr = zerons_addr;
159 	if (nsp->nsp_socket->so_state & SS_NOFDREF)
160 		ns_pcbdetach(nsp);
161 }
162 
163 ns_pcbdetach(nsp)
164 	struct nspcb *nsp;
165 {
166 	struct socket *so = nsp->nsp_socket;
167 
168 	so->so_pcb = 0;
169 	sofree(so);
170 	if (nsp->nsp_route.ro_rt)
171 		rtfree(nsp->nsp_route.ro_rt);
172 	remque(nsp);
173 	(void) m_free(dtom(nsp));
174 }
175 
176 ns_setsockaddr(nsp, nam)
177 	register struct nspcb *nsp;
178 	struct mbuf *nam;
179 {
180 	register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
181 
182 	nam->m_len = sizeof (*sns);
183 	sns = mtod(nam, struct sockaddr_ns *);
184 	bzero((caddr_t)sns, sizeof (*sns));
185 	sns->sns_family = AF_NS;
186 	sns->sns_addr = nsp->nsp_laddr;
187 }
188 
189 ns_setpeeraddr(nsp, nam)
190 	register struct nspcb *nsp;
191 	struct mbuf *nam;
192 {
193 	register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
194 
195 	nam->m_len = sizeof (*sns);
196 	sns = mtod(nam, struct sockaddr_ns *);
197 	bzero((caddr_t)sns, sizeof (*sns));
198 	sns->sns_family = AF_NS;
199 	sns->sns_addr  = nsp->nsp_faddr;
200 }
201 
202 /*
203  * Pass some notification to all connections of a protocol
204  * associated with address dst.  Call the
205  * protocol specific routine to handle each connection.
206  * Also pass an extra paramter via the nspcb. (which may in fact
207  * be a parameter list!)
208  */
209 ns_pcbnotify(dst, errno, notify, param)
210 	register struct ns_addr *dst;
211 	long param;
212 	int errno, (*notify)();
213 {
214 	register struct nspcb *nsp, *oinp;
215 	int s = splimp();
216 
217 	for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb);) {
218 		if (!ns_hosteq(*dst,nsp->nsp_faddr)) {
219 	next:
220 			nsp = nsp->nsp_next;
221 			continue;
222 		}
223 		if (nsp->nsp_socket == 0)
224 			goto next;
225 		if (errno)
226 			nsp->nsp_socket->so_error = errno;
227 		oinp = nsp;
228 		nsp = nsp->nsp_next;
229 		oinp->nsp_notify_param = param;
230 		(*notify)(oinp);
231 	}
232 	splx(s);
233 }
234 
235 /*
236  * After a routing change, flush old routing
237  * and allocate a (hopefully) better one.
238  */
239 ns_rtchange(nsp)
240 	struct nspcb *nsp;
241 {
242 	if (nsp->nsp_route.ro_rt) {
243 		rtfree(nsp->nsp_route.ro_rt);
244 		nsp->nsp_route.ro_rt = 0;
245 		/*
246 		 * A new route can be allocated the next time
247 		 * output is attempted.
248 		 */
249 	}
250 	/* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
251 }
252 
253 struct nspcb *
254 ns_pcblookup(faddr, lport, wildp)
255 	struct ns_addr *faddr;
256 	u_short lport;
257 {
258 	register struct nspcb *nsp, *match = 0;
259 	int matchwild = 3, wildcard;
260 	u_short fport;
261 
262 	fport = faddr->x_port;
263 	for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb); nsp = nsp->nsp_next) {
264 		if (nsp->nsp_lport != lport)
265 			continue;
266 		wildcard = 0;
267 		if (ns_nullhost(nsp->nsp_faddr)) {
268 			if (!ns_nullhost(*faddr))
269 				wildcard++;
270 		} else {
271 			if (ns_nullhost(*faddr))
272 				wildcard++;
273 			else {
274 				if (!ns_hosteq(nsp->nsp_faddr, *faddr))
275 					continue;
276 				if( nsp->nsp_fport != fport) {
277 					if(nsp->nsp_fport != 0)
278 						continue;
279 					else
280 						wildcard++;
281 				}
282 			}
283 		}
284 		if (wildcard && wildp==0)
285 			continue;
286 		if (wildcard < matchwild) {
287 			match = nsp;
288 			matchwild = wildcard;
289 			if (wildcard == 0)
290 				break;
291 		}
292 	}
293 	return (match);
294 }
295