]> git.saurik.com Git - apple/xnu.git/blob - bsd/netns/ns_pcb.c
c02bb6a5c1b9e9799f9e5df990d349ae8a99eff9
[apple/xnu.git] / bsd / netns / ns_pcb.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1984, 1985, 1986, 1987, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)ns_pcb.c 8.1 (Berkeley) 6/10/93
55 */
56
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/mbuf.h>
60 #include <sys/errno.h>
61 #include <sys/socket.h>
62 #include <sys/socketvar.h>
63 #include <sys/protosw.h>
64
65 #include <net/if.h>
66 #include <net/route.h>
67
68 #include <netns/ns.h>
69 #include <netns/ns_if.h>
70 #include <netns/ns_pcb.h>
71
72 struct ns_addr zerons_addr;
73
74 ns_pcballoc(so, head)
75 struct socket *so;
76 struct nspcb *head;
77 {
78 struct mbuf *m;
79 register struct nspcb *nsp;
80
81 m = m_getclr(M_DONTWAIT, MT_PCB);
82 if (m == NULL)
83 return (ENOBUFS);
84 nsp = mtod(m, struct nspcb *);
85 nsp->nsp_socket = so;
86 insque(nsp, head);
87 so->so_pcb = (caddr_t)nsp;
88 return (0);
89 }
90
91 ns_pcbbind(nsp, nam)
92 register struct nspcb *nsp;
93 struct mbuf *nam;
94 {
95 register struct sockaddr_ns *sns;
96 u_short lport = 0;
97
98 if (nsp->nsp_lport || !ns_nullhost(nsp->nsp_laddr))
99 return (EINVAL);
100 if (nam == 0)
101 goto noname;
102 sns = mtod(nam, struct sockaddr_ns *);
103 if (nam->m_len != sizeof (*sns))
104 return (EINVAL);
105 if (!ns_nullhost(sns->sns_addr)) {
106 int tport = sns->sns_port;
107
108 sns->sns_port = 0; /* yech... */
109 if (ifa_ifwithaddr((struct sockaddr *)sns) == 0)
110 return (EADDRNOTAVAIL);
111 sns->sns_port = tport;
112 }
113 lport = sns->sns_port;
114 if (lport) {
115 u_short aport = ntohs(lport);
116
117 if (aport < NSPORT_RESERVED &&
118 (nsp->nsp_socket->so_state & SS_PRIV) == 0)
119 return (EACCES);
120 if (ns_pcblookup(&zerons_addr, lport, 0))
121 return (EADDRINUSE);
122 }
123 nsp->nsp_laddr = sns->sns_addr;
124 noname:
125 if (lport == 0)
126 do {
127 if (nspcb.nsp_lport++ < NSPORT_RESERVED)
128 nspcb.nsp_lport = NSPORT_RESERVED;
129 lport = htons(nspcb.nsp_lport);
130 } while (ns_pcblookup(&zerons_addr, lport, 0));
131 nsp->nsp_lport = lport;
132 return (0);
133 }
134
135 /*
136 * Connect from a socket to a specified address.
137 * Both address and port must be specified in argument sns.
138 * If don't have a local address for this socket yet,
139 * then pick one.
140 */
141 ns_pcbconnect(nsp, nam)
142 struct nspcb *nsp;
143 struct mbuf *nam;
144 {
145 struct ns_ifaddr *ia;
146 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
147 register struct ns_addr *dst;
148 register struct route *ro;
149 struct ifnet *ifp;
150
151 if (nam->m_len != sizeof (*sns))
152 return (EINVAL);
153 if (sns->sns_family != AF_NS)
154 return (EAFNOSUPPORT);
155 if (sns->sns_port==0 || ns_nullhost(sns->sns_addr))
156 return (EADDRNOTAVAIL);
157 /*
158 * If we haven't bound which network number to use as ours,
159 * we will use the number of the outgoing interface.
160 * This depends on having done a routing lookup, which
161 * we will probably have to do anyway, so we might
162 * as well do it now. On the other hand if we are
163 * sending to multiple destinations we may have already
164 * done the lookup, so see if we can use the route
165 * from before. In any case, we only
166 * chose a port number once, even if sending to multiple
167 * destinations.
168 */
169 ro = &nsp->nsp_route;
170 dst = &satons_addr(ro->ro_dst);
171 if (nsp->nsp_socket->so_options & SO_DONTROUTE)
172 goto flush;
173 if (!ns_neteq(nsp->nsp_lastdst, sns->sns_addr))
174 goto flush;
175 if (!ns_hosteq(nsp->nsp_lastdst, sns->sns_addr)) {
176 if (ro->ro_rt && ! (ro->ro_rt->rt_flags & RTF_HOST)) {
177 /* can patch route to avoid rtalloc */
178 *dst = sns->sns_addr;
179 } else {
180 flush:
181 if (ro->ro_rt)
182 RTFREE(ro->ro_rt);
183 ro->ro_rt = (struct rtentry *)0;
184 nsp->nsp_laddr.x_net = ns_zeronet;
185 }
186 }/* else cached route is ok; do nothing */
187 nsp->nsp_lastdst = sns->sns_addr;
188 if ((nsp->nsp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
189 (ro->ro_rt == (struct rtentry *)0 ||
190 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
191 /* No route yet, so try to acquire one */
192 ro->ro_dst.sa_family = AF_NS;
193 ro->ro_dst.sa_len = sizeof(ro->ro_dst);
194 *dst = sns->sns_addr;
195 dst->x_port = 0;
196 rtalloc(ro);
197 }
198 if (ns_neteqnn(nsp->nsp_laddr.x_net, ns_zeronet)) {
199 /*
200 * If route is known or can be allocated now,
201 * our src addr is taken from the i/f, else punt.
202 */
203
204 ia = (struct ns_ifaddr *)0;
205 /*
206 * If we found a route, use the address
207 * corresponding to the outgoing interface
208 */
209 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp))
210 for (ia = ns_ifaddr; ia; ia = ia->ia_next)
211 if (ia->ia_ifp == ifp)
212 break;
213 if (ia == 0) {
214 u_short fport = sns->sns_addr.x_port;
215 sns->sns_addr.x_port = 0;
216 ia = (struct ns_ifaddr *)
217 ifa_ifwithdstaddr((struct sockaddr *)sns);
218 sns->sns_addr.x_port = fport;
219 if (ia == 0)
220 ia = ns_iaonnetof(&sns->sns_addr);
221 if (ia == 0)
222 ia = ns_ifaddr;
223 if (ia == 0)
224 return (EADDRNOTAVAIL);
225 }
226 nsp->nsp_laddr.x_net = satons_addr(ia->ia_addr).x_net;
227 }
228 if (ns_pcblookup(&sns->sns_addr, nsp->nsp_lport, 0))
229 return (EADDRINUSE);
230 if (ns_nullhost(nsp->nsp_laddr)) {
231 if (nsp->nsp_lport == 0)
232 (void) ns_pcbbind(nsp, (struct mbuf *)0);
233 nsp->nsp_laddr.x_host = ns_thishost;
234 }
235 nsp->nsp_faddr = sns->sns_addr;
236 /* Includes nsp->nsp_fport = sns->sns_port; */
237 return (0);
238 }
239
240 ns_pcbdisconnect(nsp)
241 struct nspcb *nsp;
242 {
243
244 nsp->nsp_faddr = zerons_addr;
245 if (nsp->nsp_socket->so_state & SS_NOFDREF)
246 ns_pcbdetach(nsp);
247 }
248
249 ns_pcbdetach(nsp)
250 struct nspcb *nsp;
251 {
252 struct socket *so = nsp->nsp_socket;
253
254 so->so_pcb = 0;
255 sofree(so);
256 if (nsp->nsp_route.ro_rt)
257 rtfree(nsp->nsp_route.ro_rt);
258 remque(nsp);
259 (void) m_free(dtom(nsp));
260 }
261
262 ns_setsockaddr(nsp, nam)
263 register struct nspcb *nsp;
264 struct mbuf *nam;
265 {
266 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
267
268 nam->m_len = sizeof (*sns);
269 sns = mtod(nam, struct sockaddr_ns *);
270 bzero((caddr_t)sns, sizeof (*sns));
271 sns->sns_len = sizeof(*sns);
272 sns->sns_family = AF_NS;
273 sns->sns_addr = nsp->nsp_laddr;
274 }
275
276 ns_setpeeraddr(nsp, nam)
277 register struct nspcb *nsp;
278 struct mbuf *nam;
279 {
280 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
281
282 nam->m_len = sizeof (*sns);
283 sns = mtod(nam, struct sockaddr_ns *);
284 bzero((caddr_t)sns, sizeof (*sns));
285 sns->sns_len = sizeof(*sns);
286 sns->sns_family = AF_NS;
287 sns->sns_addr = nsp->nsp_faddr;
288 }
289
290 /*
291 * Pass some notification to all connections of a protocol
292 * associated with address dst. Call the
293 * protocol specific routine to handle each connection.
294 * Also pass an extra paramter via the nspcb. (which may in fact
295 * be a parameter list!)
296 */
297 ns_pcbnotify(dst, errno, notify, param)
298 register struct ns_addr *dst;
299 long param;
300 int errno, (*notify)();
301 {
302 register struct nspcb *nsp, *oinp;
303 int s = splimp();
304
305 for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb);) {
306 if (!ns_hosteq(*dst,nsp->nsp_faddr)) {
307 next:
308 nsp = nsp->nsp_next;
309 continue;
310 }
311 if (nsp->nsp_socket == 0)
312 goto next;
313 if (errno)
314 nsp->nsp_socket->so_error = errno;
315 oinp = nsp;
316 nsp = nsp->nsp_next;
317 oinp->nsp_notify_param = param;
318 (*notify)(oinp);
319 }
320 splx(s);
321 }
322
323 #ifdef notdef
324 /*
325 * After a routing change, flush old routing
326 * and allocate a (hopefully) better one.
327 */
328 ns_rtchange(nsp)
329 struct nspcb *nsp;
330 {
331 if (nsp->nsp_route.ro_rt) {
332 rtfree(nsp->nsp_route.ro_rt);
333 nsp->nsp_route.ro_rt = 0;
334 /*
335 * A new route can be allocated the next time
336 * output is attempted.
337 */
338 }
339 /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
340 }
341 #endif
342
343 struct nspcb *
344 ns_pcblookup(faddr, lport, wildp)
345 struct ns_addr *faddr;
346 u_short lport;
347 {
348 register struct nspcb *nsp, *match = 0;
349 int matchwild = 3, wildcard;
350 u_short fport;
351
352 fport = faddr->x_port;
353 for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb); nsp = nsp->nsp_next) {
354 if (nsp->nsp_lport != lport)
355 continue;
356 wildcard = 0;
357 if (ns_nullhost(nsp->nsp_faddr)) {
358 if (!ns_nullhost(*faddr))
359 wildcard++;
360 } else {
361 if (ns_nullhost(*faddr))
362 wildcard++;
363 else {
364 if (!ns_hosteq(nsp->nsp_faddr, *faddr))
365 continue;
366 if (nsp->nsp_fport != fport) {
367 if (nsp->nsp_fport != 0)
368 continue;
369 else
370 wildcard++;
371 }
372 }
373 }
374 if (wildcard && wildp==0)
375 continue;
376 if (wildcard < matchwild) {
377 match = nsp;
378 matchwild = wildcard;
379 if (wildcard == 0)
380 break;
381 }
382 }
383 return (match);
384 }