ddp_pcb.c revision 165974
1139827Simp/*-
2139597Srwatson * Copyright (c) 2004-2005 Robert N. M. Watson
3165891Srwatson * All rights reserved.
4165891Srwatson *
5165891Srwatson * Redistribution and use in source and binary forms, with or without
6165891Srwatson * modification, are permitted provided that the following conditions
7165891Srwatson * are met:
8165891Srwatson * 1. Redistributions of source code must retain the above copyright
9165891Srwatson *    notice, this list of conditions and the following disclaimer.
10165891Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11165891Srwatson *    notice, this list of conditions and the following disclaimer in the
12165891Srwatson *    documentation and/or other materials provided with the distribution.
13165891Srwatson *
14165891Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15165891Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16165891Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17165891Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18165891Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19165891Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20165891Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21165891Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22165891Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23165891Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24165891Srwatson * SUCH DAMAGE.
25165891Srwatson *
26165974Srwatson * Copyright (c) 1990, 1994 Regents of The University of Michigan.
27139827Simp * All Rights Reserved.
2867893Sphk *
29139827Simp * Permission to use, copy, modify, and distribute this software and
30139827Simp * its documentation for any purpose and without fee is hereby granted,
31139827Simp * provided that the above copyright notice appears in all copies and
32139827Simp * that both that copyright notice and this permission notice appear
33139827Simp * in supporting documentation, and that the name of The University
34139827Simp * of Michigan not be used in advertising or publicity pertaining to
35139827Simp * distribution of the software without specific, written prior
36139827Simp * permission. This software is supplied as is without expressed or
37139827Simp * implied warranties of any kind.
38139827Simp *
39139827Simp * This product includes software developed by the University of
40139827Simp * California, Berkeley and its contributors.
41139827Simp *
42139827Simp *	Research Systems Unix Group
43139827Simp *	The University of Michigan
44139827Simp *	c/o Wesley Craig
45139827Simp *	535 W. William Street
46139827Simp *	Ann Arbor, Michigan
47139827Simp *	+1-313-764-2278
48139827Simp *	netatalk@umich.edu
4967893Sphk * $FreeBSD: head/sys/netatalk/ddp_pcb.c 165974 2007-01-12 15:07:51Z rwatson $
5015885Sjulian */
5115885Sjulian
5215885Sjulian#include <sys/param.h>
5315885Sjulian#include <sys/systm.h>
5429024Sbde#include <sys/malloc.h>
5515885Sjulian#include <sys/mbuf.h>
56164033Srwatson#include <sys/priv.h>
5715885Sjulian#include <sys/socket.h>
5815885Sjulian#include <sys/socketvar.h>
5915885Sjulian#include <sys/protosw.h>
6015885Sjulian#include <net/if.h>
6115885Sjulian#include <net/route.h>
62111888Sjlemon#include <net/netisr.h>
6315885Sjulian
6418207Sbde#include <netatalk/at.h>
6518207Sbde#include <netatalk/at_var.h>
6618207Sbde#include <netatalk/ddp_var.h>
67127195Srwatson#include <netatalk/ddp_pcb.h>
6815885Sjulian#include <netatalk/at_extern.h>
6915885Sjulian
70132043Srwatsonstruct mtx		 ddp_list_mtx;
71165974Srwatsonstatic struct ddpcb	*ddp_ports[ATPORT_LAST];
72132043Srwatsonstruct ddpcb		*ddpcb_list = NULL;
7315885Sjulian
74127195Srwatsonvoid
7528270Swollmanat_sockaddr(struct ddpcb *ddp, struct sockaddr **addr)
7615885Sjulian{
77132043Srwatson
78165974Srwatson	/*
79165974Srwatson	 * Prevent modification of ddp during copy of addr.
80165974Srwatson	 */
81165974Srwatson	DDP_LOCK_ASSERT(ddp);
82165974Srwatson	*addr = sodupsockaddr((struct sockaddr *)&ddp->ddp_lsat, M_NOWAIT);
8315885Sjulian}
8415885Sjulian
85127195Srwatsonint
8683366Sjulianat_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
8715885Sjulian{
88165974Srwatson	struct sockaddr_at lsat, *sat;
89165974Srwatson	struct at_ifaddr *aa;
90165974Srwatson	struct ddpcb *ddpp;
9115885Sjulian
92165974Srwatson	/*
93165974Srwatson	 * We read and write both the ddp passed in, and also ddp_ports.
94165974Srwatson	 */
95165974Srwatson	DDP_LIST_XLOCK_ASSERT();
96165974Srwatson	DDP_LOCK_ASSERT(ddp);
97132043Srwatson
98165974Srwatson	/*
99165974Srwatson	 * Shouldn't be bound.
100165974Srwatson	 */
101165974Srwatson	if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT)
102165974Srwatson		return (EINVAL);
10315885Sjulian
104165974Srwatson	/*
105165974Srwatson	 * Validate passed address.
106165974Srwatson	 */
107165974Srwatson	if (addr != NULL) {
108165974Srwatson		sat = (struct sockaddr_at *)addr;
109165974Srwatson		if (sat->sat_family != AF_APPLETALK)
110165974Srwatson			return (EAFNOSUPPORT);
11115885Sjulian
112165974Srwatson		if (sat->sat_addr.s_node != ATADDR_ANYNODE ||
113165974Srwatson		    sat->sat_addr.s_net != ATADDR_ANYNET) {
114165974Srwatson			for (aa = at_ifaddr_list; aa != NULL;
115165974Srwatson			    aa = aa->aa_next) {
116165974Srwatson				if ((sat->sat_addr.s_net ==
117165974Srwatson				    AA_SAT(aa)->sat_addr.s_net) &&
118165974Srwatson				    (sat->sat_addr.s_node ==
119165974Srwatson				    AA_SAT(aa)->sat_addr.s_node))
120165974Srwatson					break;
121165974Srwatson			}
122165974Srwatson			if (aa == NULL)
123165974Srwatson				return (EADDRNOTAVAIL);
12415885Sjulian		}
12515885Sjulian
126165974Srwatson		if (sat->sat_port != ATADDR_ANYPORT) {
127165974Srwatson			if (sat->sat_port < ATPORT_FIRST ||
128165974Srwatson			    sat->sat_port >= ATPORT_LAST)
129165974Srwatson				return (EINVAL);
130165974Srwatson			if (sat->sat_port < ATPORT_RESERVED &&
131165974Srwatson			    priv_check(td, PRIV_NETATALK_RESERVEDPORT))
132165974Srwatson				return (EACCES);
133165974Srwatson		}
134165974Srwatson	} else {
135165974Srwatson		bzero((caddr_t)&lsat, sizeof(struct sockaddr_at));
136165974Srwatson		lsat.sat_len = sizeof(struct sockaddr_at);
137165974Srwatson		lsat.sat_addr.s_node = ATADDR_ANYNODE;
138165974Srwatson		lsat.sat_addr.s_net = ATADDR_ANYNET;
139165974Srwatson		lsat.sat_family = AF_APPLETALK;
140165974Srwatson		sat = &lsat;
14115885Sjulian	}
14215885Sjulian
143165974Srwatson	if (sat->sat_addr.s_node == ATADDR_ANYNODE &&
144127288Srwatson	    sat->sat_addr.s_net == ATADDR_ANYNET) {
145165974Srwatson		if (at_ifaddr_list == NULL)
146165974Srwatson			return (EADDRNOTAVAIL);
147165974Srwatson		sat->sat_addr = AA_SAT(at_ifaddr_list)->sat_addr;
14815885Sjulian	}
149165974Srwatson	ddp->ddp_lsat = *sat;
15015885Sjulian
151165974Srwatson	/*
152165974Srwatson	 * Choose port.
153165974Srwatson	 */
154165974Srwatson	if (sat->sat_port == ATADDR_ANYPORT) {
155165974Srwatson		for (sat->sat_port = ATPORT_RESERVED;
156165974Srwatson		    sat->sat_port < ATPORT_LAST; sat->sat_port++) {
157165974Srwatson			if (ddp_ports[sat->sat_port - 1] == NULL)
158165974Srwatson				break;
159165974Srwatson		}
160165974Srwatson		if (sat->sat_port == ATPORT_LAST)
161165974Srwatson			return (EADDRNOTAVAIL);
162165974Srwatson		ddp->ddp_lsat.sat_port = sat->sat_port;
163165974Srwatson		ddp_ports[sat->sat_port - 1] = ddp;
164165974Srwatson	} else {
165165974Srwatson		for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp;
166165974Srwatson		    ddpp = ddpp->ddp_pnext) {
167165974Srwatson			if (ddpp->ddp_lsat.sat_addr.s_net ==
168165974Srwatson			    sat->sat_addr.s_net &&
169165974Srwatson			    ddpp->ddp_lsat.sat_addr.s_node ==
170165974Srwatson			    sat->sat_addr.s_node)
171165974Srwatson				break;
172165974Srwatson		}
173165974Srwatson		if (ddpp != NULL)
174165974Srwatson			return (EADDRINUSE);
175165974Srwatson		ddp->ddp_pnext = ddp_ports[sat->sat_port - 1];
176165974Srwatson		ddp_ports[sat->sat_port - 1] = ddp;
177165974Srwatson		if (ddp->ddp_pnext != NULL)
178165974Srwatson			ddp->ddp_pnext->ddp_pprev = ddp;
17915885Sjulian	}
18015885Sjulian
181165974Srwatson	return (0);
18215885Sjulian}
18315885Sjulian
184127195Srwatsonint
18583366Sjulianat_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
18615885Sjulian{
187165974Srwatson	struct sockaddr_at	*sat = (struct sockaddr_at *)addr;
188165974Srwatson	struct route	*ro;
189165974Srwatson	struct at_ifaddr	*aa = NULL;
190165974Srwatson	struct ifnet	*ifp;
191165974Srwatson	u_short		hintnet = 0, net;
19215885Sjulian
193165974Srwatson	DDP_LIST_XLOCK_ASSERT();
194165974Srwatson	DDP_LOCK_ASSERT(ddp);
195132043Srwatson
196165974Srwatson	if (sat->sat_family != AF_APPLETALK)
197165974Srwatson		return (EAFNOSUPPORT);
19815885Sjulian
199165974Srwatson	/*
200165974Srwatson	 * Under phase 2, network 0 means "the network".  We take "the
201165974Srwatson	 * network" to mean the network the control block is bound to.  If
202165974Srwatson	 * the control block is not bound, there is an error.
203165974Srwatson	 */
204165974Srwatson	if (sat->sat_addr.s_net == ATADDR_ANYNET &&
205165974Srwatson	    sat->sat_addr.s_node != ATADDR_ANYNODE) {
206165974Srwatson		if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT)
207165974Srwatson			return (EADDRNOTAVAIL);
208165974Srwatson		hintnet = ddp->ddp_lsat.sat_addr.s_net;
20915885Sjulian	}
21015885Sjulian
211165974Srwatson	ro = &ddp->ddp_route;
212165974Srwatson	/*
213165974Srwatson	 * If we've got an old route for this pcb, check that it is valid.
214165974Srwatson	 * If we've changed our address, we may have an old "good looking"
215165974Srwatson	 * route here.  Attempt to detect it.
216165974Srwatson	 */
217165974Srwatson	if (ro->ro_rt) {
218165974Srwatson		if (hintnet)
219165974Srwatson			net = hintnet;
220165974Srwatson		else
221165974Srwatson			net = sat->sat_addr.s_net;
222165974Srwatson		aa = NULL;
223165974Srwatson		if ((ifp = ro->ro_rt->rt_ifp) != NULL) {
224165974Srwatson			for (aa = at_ifaddr_list; aa != NULL;
225165974Srwatson			    aa = aa->aa_next) {
226165974Srwatson				if (aa->aa_ifp == ifp &&
227165974Srwatson				    ntohs(net) >= ntohs(aa->aa_firstnet) &&
228165974Srwatson				    ntohs(net) <= ntohs(aa->aa_lastnet))
229165974Srwatson					break;
230165974Srwatson			}
23115885Sjulian		}
232165974Srwatson		if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net !=
233165974Srwatson		    (hintnet ? hintnet : sat->sat_addr.s_net) ||
234165974Srwatson		    satosat(&ro->ro_dst)->sat_addr.s_node !=
235165974Srwatson		    sat->sat_addr.s_node)) {
236165974Srwatson			RTFREE(ro->ro_rt);
237165974Srwatson			ro->ro_rt = NULL;
238165974Srwatson		}
23915885Sjulian	}
24015885Sjulian
241165974Srwatson	/*
242165974Srwatson	 * If we've got no route for this interface, try to find one.
243165974Srwatson	 */
244165974Srwatson	if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) {
245165974Srwatson		ro->ro_dst.sa_len = sizeof(struct sockaddr_at);
246165974Srwatson		ro->ro_dst.sa_family = AF_APPLETALK;
247165974Srwatson		if (hintnet)
248165974Srwatson			satosat(&ro->ro_dst)->sat_addr.s_net = hintnet;
249165974Srwatson		else
250165974Srwatson			satosat(&ro->ro_dst)->sat_addr.s_net =
251165974Srwatson			    sat->sat_addr.s_net;
252165974Srwatson		satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node;
253165974Srwatson		rtalloc(ro);
25415885Sjulian	}
25515885Sjulian
256165974Srwatson	/*
257165974Srwatson	 * Make sure any route that we have has a valid interface.
258165974Srwatson	 */
259165974Srwatson	aa = NULL;
260165974Srwatson	if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) {
261165974Srwatson		for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
262165974Srwatson			if (aa->aa_ifp == ifp)
263165974Srwatson				break;
264165974Srwatson		}
26515885Sjulian	}
266165974Srwatson	if (aa == NULL)
267165974Srwatson		return (ENETUNREACH);
26815885Sjulian
269165974Srwatson	ddp->ddp_fsat = *sat;
270165974Srwatson	if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT)
271165974Srwatson		return (at_pcbsetaddr(ddp, NULL, td));
272165974Srwatson	return (0);
27315885Sjulian}
27415885Sjulian
275127195Srwatsonvoid
276127288Srwatsonat_pcbdisconnect(struct ddpcb	*ddp)
27715885Sjulian{
278132043Srwatson
279165974Srwatson	DDP_LOCK_ASSERT(ddp);
280132043Srwatson
281165974Srwatson	ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
282165974Srwatson	ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
283165974Srwatson	ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
28415885Sjulian}
28515885Sjulian
286127195Srwatsonint
287127288Srwatsonat_pcballoc(struct socket *so)
28815885Sjulian{
289165974Srwatson	struct ddpcb *ddp;
29015885Sjulian
291132043Srwatson	DDP_LIST_XLOCK_ASSERT();
292132043Srwatson
293132043Srwatson	MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO);
294139597Srwatson	if (ddp == NULL)
295139597Srwatson		return (ENOBUFS);
296132043Srwatson	DDP_LOCK_INIT(ddp);
29728270Swollman	ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
29815885Sjulian
299132043Srwatson	ddp->ddp_socket = so;
300132043Srwatson	so->so_pcb = (caddr_t)ddp;
301132043Srwatson
302127293Srwatson	ddp->ddp_next = ddpcb_list;
30328270Swollman	ddp->ddp_prev = NULL;
30428270Swollman	ddp->ddp_pprev = NULL;
30528270Swollman	ddp->ddp_pnext = NULL;
306165974Srwatson	if (ddpcb_list != NULL)
307127293Srwatson		ddpcb_list->ddp_prev = ddp;
308127293Srwatson	ddpcb_list = ddp;
309132043Srwatson	return(0);
31015885Sjulian}
31115885Sjulian
312127195Srwatsonvoid
313127288Srwatsonat_pcbdetach(struct socket *so, struct ddpcb *ddp)
31415885Sjulian{
315132043Srwatson
316165974Srwatson	/*
317165974Srwatson	 * We modify ddp, ddp_ports, and the global list.
318165974Srwatson	 */
319165974Srwatson	DDP_LIST_XLOCK_ASSERT();
320165974Srwatson	DDP_LOCK_ASSERT(ddp);
321165974Srwatson	KASSERT(so->so_pcb != NULL, ("at_pcbdetach: so_pcb == NULL"));
322132043Srwatson
323165974Srwatson	so->so_pcb = NULL;
32415885Sjulian
325165974Srwatson	/* Remove ddp from ddp_ports list. */
326165974Srwatson	if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
327165974Srwatson	    ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) {
328165974Srwatson		if (ddp->ddp_pprev != NULL)
329165974Srwatson			ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
330165974Srwatson		else
331165974Srwatson			ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext;
332165974Srwatson		if (ddp->ddp_pnext != NULL)
333165974Srwatson			ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
33415885Sjulian	}
33515885Sjulian
336165974Srwatson	if (ddp->ddp_route.ro_rt)
337165974Srwatson		RTFREE(ddp->ddp_route.ro_rt);
33815885Sjulian
339165974Srwatson	if (ddp->ddp_prev)
340165974Srwatson		ddp->ddp_prev->ddp_next = ddp->ddp_next;
341165974Srwatson	else
342165974Srwatson		ddpcb_list = ddp->ddp_next;
343165974Srwatson	if (ddp->ddp_next)
344165974Srwatson		ddp->ddp_next->ddp_prev = ddp->ddp_prev;
345165974Srwatson	DDP_UNLOCK(ddp);
346165974Srwatson	DDP_LOCK_DESTROY(ddp);
347165974Srwatson	FREE(ddp, M_PCB);
34815885Sjulian}
34915885Sjulian
35015885Sjulian/*
351165974Srwatson * For the moment, this just find the pcb with the correct local address.  In
352165974Srwatson * the future, this will actually do some real searching, so we can use the
353165974Srwatson * sender's address to do de-multiplexing on a single port to many sockets
354165974Srwatson * (pcbs).
35515885Sjulian */
35615885Sjulianstruct ddpcb *
357127288Srwatsonddp_search(struct sockaddr_at *from, struct sockaddr_at *to,
358165974Srwatson    struct at_ifaddr *aa)
35915885Sjulian{
360165974Srwatson	struct ddpcb *ddp;
36115885Sjulian
362165974Srwatson	DDP_LIST_SLOCK_ASSERT();
363132043Srwatson
364165974Srwatson	/*
365165974Srwatson	 * Check for bad ports.
366165974Srwatson	 */
367165974Srwatson	if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST)
368165974Srwatson		return (NULL);
36915885Sjulian
370165974Srwatson	/*
371165974Srwatson	 * Make sure the local address matches the sent address.  What about
372165974Srwatson	 * the interface?
373165974Srwatson	 */
374165974Srwatson	for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) {
375165974Srwatson		DDP_LOCK(ddp);
376165974Srwatson		/* XXX should we handle 0.YY? */
377165974Srwatson		/* XXXX.YY to socket on destination interface */
378165974Srwatson		if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
379165974Srwatson		    to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) {
380165974Srwatson			DDP_UNLOCK(ddp);
381165974Srwatson			break;
382165974Srwatson		}
38315885Sjulian
384165974Srwatson		/* 0.255 to socket on receiving interface */
385165974Srwatson		if (to->sat_addr.s_node == ATADDR_BCAST &&
386165974Srwatson		    (to->sat_addr.s_net == 0 ||
387165974Srwatson		    to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) &&
388165974Srwatson		    ddp->ddp_lsat.sat_addr.s_net ==
389165974Srwatson		    AA_SAT(aa)->sat_addr.s_net) {
390165974Srwatson			DDP_UNLOCK(ddp);
391165974Srwatson			break;
392165974Srwatson		}
39315885Sjulian
394165974Srwatson		/* XXXX.0 to socket on destination interface */
395165974Srwatson		if (to->sat_addr.s_net == aa->aa_firstnet &&
396165974Srwatson		    to->sat_addr.s_node == 0 &&
397165974Srwatson		    ntohs(ddp->ddp_lsat.sat_addr.s_net) >=
398165974Srwatson		    ntohs(aa->aa_firstnet) &&
399165974Srwatson		    ntohs(ddp->ddp_lsat.sat_addr.s_net) <=
400165974Srwatson		    ntohs(aa->aa_lastnet)) {
401165974Srwatson			DDP_UNLOCK(ddp);
402165974Srwatson			break;
403165974Srwatson		}
404165974Srwatson		DDP_UNLOCK(ddp);
40515885Sjulian	}
406165974Srwatson	return (ddp);
40715885Sjulian}
408