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