2 * Copyright (c) 2004-2005 Robert N. M. Watson
3 * Copyright (c) 1990,1994 Regents of The University of Michigan.
6 * Permission to use, copy, modify, and distribute this software and
7 * its documentation for any purpose and without fee is hereby granted,
8 * provided that the above copyright notice appears in all copies and
9 * that both that copyright notice and this permission notice appear
10 * in supporting documentation, and that the name of The University
11 * of Michigan not be used in advertising or publicity pertaining to
12 * distribution of the software without specific, written prior
13 * permission. This software is supplied as is without expressed or
14 * implied warranties of any kind.
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
19 * Research Systems Unix Group
20 * The University of Michigan
22 * 535 W. William Street
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/malloc.h>
33 #include <sys/socket.h>
34 #include <sys/socketvar.h>
35 #include <sys/protosw.h>
37 #include <net/route.h>
38 #include <net/netisr.h>
40 #include <netatalk/at.h>
41 #include <netatalk/at_var.h>
42 #include <netatalk/ddp_var.h>
43 #include <netatalk/ddp_pcb.h>
44 #include <netatalk/at_extern.h>
46 struct mtx ddp_list_mtx;
47 static struct ddpcb *ddp_ports[ ATPORT_LAST ];
48 struct ddpcb *ddpcb_list = NULL;
51 at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr)
55 * Prevent modification of ddp during copy of addr.
58 *addr = sodupsockaddr((struct sockaddr *)&ddp->ddp_lsat, M_NOWAIT);
62 at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
64 struct sockaddr_at lsat, *sat;
69 * We read and write both the ddp passed in, and also ddp_ports.
71 DDP_LIST_XLOCK_ASSERT();
74 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) { /* shouldn't be bound */
78 if (addr != NULL) { /* validate passed address */
79 sat = (struct sockaddr_at *)addr;
80 if (sat->sat_family != AF_APPLETALK) {
81 return (EAFNOSUPPORT);
84 if (sat->sat_addr.s_node != ATADDR_ANYNODE ||
85 sat->sat_addr.s_net != ATADDR_ANYNET) {
86 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
87 if ((sat->sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) &&
88 (sat->sat_addr.s_node == AA_SAT(aa)->sat_addr.s_node)) {
93 return (EADDRNOTAVAIL);
97 if (sat->sat_port != ATADDR_ANYPORT) {
98 if (sat->sat_port < ATPORT_FIRST ||
99 sat->sat_port >= ATPORT_LAST) {
102 if (sat->sat_port < ATPORT_RESERVED &&
108 bzero((caddr_t)&lsat, sizeof(struct sockaddr_at));
109 lsat.sat_len = sizeof(struct sockaddr_at);
110 lsat.sat_addr.s_node = ATADDR_ANYNODE;
111 lsat.sat_addr.s_net = ATADDR_ANYNET;
112 lsat.sat_family = AF_APPLETALK;
116 if (sat->sat_addr.s_node == ATADDR_ANYNODE &&
117 sat->sat_addr.s_net == ATADDR_ANYNET) {
118 if (at_ifaddr_list == NULL) {
119 return (EADDRNOTAVAIL);
121 sat->sat_addr = AA_SAT(at_ifaddr_list)->sat_addr;
123 ddp->ddp_lsat = *sat;
128 if (sat->sat_port == ATADDR_ANYPORT) {
129 for (sat->sat_port = ATPORT_RESERVED;
130 sat->sat_port < ATPORT_LAST; sat->sat_port++) {
131 if (ddp_ports[ sat->sat_port - 1 ] == NULL) {
135 if (sat->sat_port == ATPORT_LAST) {
136 return (EADDRNOTAVAIL);
138 ddp->ddp_lsat.sat_port = sat->sat_port;
139 ddp_ports[ sat->sat_port - 1 ] = ddp;
141 for (ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp;
142 ddpp = ddpp->ddp_pnext) {
143 if (ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net &&
144 ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node) {
151 ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ];
152 ddp_ports[ sat->sat_port - 1 ] = ddp;
153 if (ddp->ddp_pnext) {
154 ddp->ddp_pnext->ddp_pprev = ddp;
162 at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td)
164 struct sockaddr_at *sat = (struct sockaddr_at *)addr;
166 struct at_ifaddr *aa = NULL;
168 u_short hintnet = 0, net;
170 DDP_LIST_XLOCK_ASSERT();
171 DDP_LOCK_ASSERT(ddp);
173 if (sat->sat_family != AF_APPLETALK) {
174 return (EAFNOSUPPORT);
178 * Under phase 2, network 0 means "the network". We take "the
179 * network" to mean the network the control block is bound to.
180 * If the control block is not bound, there is an error.
182 if (sat->sat_addr.s_net == ATADDR_ANYNET
183 && sat->sat_addr.s_node != ATADDR_ANYNODE) {
184 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) {
185 return (EADDRNOTAVAIL);
187 hintnet = ddp->ddp_lsat.sat_addr.s_net;
190 ro = &ddp->ddp_route;
192 * If we've got an old route for this pcb, check that it is valid.
193 * If we've changed our address, we may have an old "good looking"
194 * route here. Attempt to detect it.
200 net = sat->sat_addr.s_net;
203 if ((ifp = ro->ro_rt->rt_ifp) != NULL) {
204 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
205 if (aa->aa_ifp == ifp &&
206 ntohs(net) >= ntohs(aa->aa_firstnet) &&
207 ntohs(net) <= ntohs(aa->aa_lastnet)) {
212 if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net !=
213 (hintnet ? hintnet : sat->sat_addr.s_net) ||
214 satosat(&ro->ro_dst)->sat_addr.s_node !=
215 sat->sat_addr.s_node)) {
222 * If we've got no route for this interface, try to find one.
224 if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) {
225 ro->ro_dst.sa_len = sizeof(struct sockaddr_at);
226 ro->ro_dst.sa_family = AF_APPLETALK;
228 satosat(&ro->ro_dst)->sat_addr.s_net = hintnet;
230 satosat(&ro->ro_dst)->sat_addr.s_net = sat->sat_addr.s_net;
232 satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node;
237 * Make sure any route that we have has a valid interface.
240 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) {
241 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
242 if (aa->aa_ifp == ifp) {
248 return (ENETUNREACH);
251 ddp->ddp_fsat = *sat;
252 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) {
253 return (at_pcbsetaddr(ddp, NULL, td));
259 at_pcbdisconnect(struct ddpcb *ddp)
262 DDP_LOCK_ASSERT(ddp);
264 ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
265 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
266 ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
270 at_pcballoc(struct socket *so)
274 DDP_LIST_XLOCK_ASSERT();
276 MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO);
280 ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
282 ddp->ddp_socket = so;
283 so->so_pcb = (caddr_t)ddp;
285 ddp->ddp_next = ddpcb_list;
286 ddp->ddp_prev = NULL;
287 ddp->ddp_pprev = NULL;
288 ddp->ddp_pnext = NULL;
289 if (ddpcb_list != NULL) {
290 ddpcb_list->ddp_prev = ddp;
297 at_pcbdetach(struct socket *so, struct ddpcb *ddp)
301 * We modify ddp, ddp_ports, and the global list.
303 DDP_LIST_XLOCK_ASSERT();
304 DDP_LOCK_ASSERT(ddp);
306 soisdisconnected(so);
312 /* remove ddp from ddp_ports list */
313 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
314 ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL) {
315 if (ddp->ddp_pprev != NULL) {
316 ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
318 ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext;
320 if (ddp->ddp_pnext != NULL) {
321 ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
325 if (ddp->ddp_route.ro_rt) {
326 RTFREE(ddp->ddp_route.ro_rt);
330 ddp->ddp_prev->ddp_next = ddp->ddp_next;
332 ddpcb_list = ddp->ddp_next;
335 ddp->ddp_next->ddp_prev = ddp->ddp_prev;
338 DDP_LOCK_DESTROY(ddp);
343 * For the moment, this just find the pcb with the correct local address.
344 * In the future, this will actually do some real searching, so we can use
345 * the sender's address to do de-multiplexing on a single port to many
349 ddp_search(struct sockaddr_at *from, struct sockaddr_at *to,
350 struct at_ifaddr *aa)
354 DDP_LIST_SLOCK_ASSERT();
357 * Check for bad ports.
359 if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) {
364 * Make sure the local address matches the sent address. What about
367 for (ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext) {
369 /* XXX should we handle 0.YY? */
371 /* XXXX.YY to socket on destination interface */
372 if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
373 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) {
378 /* 0.255 to socket on receiving interface */
379 if (to->sat_addr.s_node == ATADDR_BCAST && (to->sat_addr.s_net == 0 ||
380 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) &&
381 ddp->ddp_lsat.sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) {
386 /* XXXX.0 to socket on destination interface */
387 if (to->sat_addr.s_net == aa->aa_firstnet &&
388 to->sat_addr.s_node == 0 &&
389 ntohs(ddp->ddp_lsat.sat_addr.s_net) >=
390 ntohs(aa->aa_firstnet) &&
391 ntohs(ddp->ddp_lsat.sat_addr.s_net) <=
392 ntohs(aa->aa_lastnet)) {