1 /* $NetBSD: ddp_usrreq.c,v 1.38 2009/03/18 16:00:22 cegger Exp $ */
4 * Copyright (c) 1990,1991 Regents of The University of Michigan.
7 * Permission to use, copy, modify, and distribute this software and
8 * its documentation for any purpose and without fee is hereby granted,
9 * provided that the above copyright notice appears in all copies and
10 * that both that copyright notice and this permission notice appear
11 * in supporting documentation, and that the name of The University
12 * of Michigan not be used in advertising or publicity pertaining to
13 * distribution of the software without specific, written prior
14 * permission. This software is supplied as is without expressed or
15 * implied warranties of any kind.
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
20 * Research Systems Unix Group
21 * The University of Michigan
23 * 535 W. William Street
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: ddp_usrreq.c,v 1.38 2009/03/18 16:00:22 cegger Exp $");
32 #include "opt_mbuftrace.h"
34 #include <sys/param.h>
35 #include <sys/errno.h>
36 #include <sys/systm.h>
39 #include <sys/ioctl.h>
40 #include <sys/queue.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/protosw.h>
44 #include <sys/kauth.h>
45 #include <sys/sysctl.h>
47 #include <net/route.h>
48 #include <net/if_ether.h>
49 #include <net/net_stats.h>
50 #include <netinet/in.h>
52 #include <netatalk/at.h>
53 #include <netatalk/at_var.h>
54 #include <netatalk/ddp_var.h>
55 #include <netatalk/ddp_private.h>
56 #include <netatalk/aarp.h>
57 #include <netatalk/at_extern.h>
59 static void at_pcbdisconnect(struct ddpcb
*);
60 static void at_sockaddr(struct ddpcb
*, struct mbuf
*);
61 static int at_pcbsetaddr(struct ddpcb
*, struct mbuf
*, struct lwp
*);
62 static int at_pcbconnect(struct ddpcb
*, struct mbuf
*, struct lwp
*);
63 static void at_pcbdetach(struct socket
*, struct ddpcb
*);
64 static int at_pcballoc(struct socket
*);
66 struct ifqueue atintrq1
, atintrq2
;
67 struct ddpcb
*ddp_ports
[ATPORT_LAST
];
68 struct ddpcb
*ddpcb
= NULL
;
69 percpu_t
*ddpstat_percpu
;
70 struct at_ifaddrhead at_ifaddr
; /* Here as inited in this file */
71 u_long ddp_sendspace
= DDP_MAXSZ
; /* Max ddp size + 1 (ddp_type) */
72 u_long ddp_recvspace
= 25 * (587 + sizeof(struct sockaddr_at
));
75 struct mowner atalk_rx_mowner
= MOWNER_INIT("atalk", "rx");
76 struct mowner atalk_tx_mowner
= MOWNER_INIT("atalk", "tx");
81 ddp_usrreq(struct socket
*so
, int req
, struct mbuf
*m
, struct mbuf
*addr
, struct mbuf
*rights
, struct lwp
*l
)
88 if (req
== PRU_CONTROL
) {
89 return (at_control((long) m
, (void *) addr
,
90 (struct ifnet
*) rights
, l
));
92 if (req
== PRU_PURGEIF
) {
93 mutex_enter(softnet_lock
);
94 at_purgeif((struct ifnet
*) rights
);
95 mutex_exit(softnet_lock
);
98 if (rights
&& rights
->m_len
) {
102 if (ddp
== NULL
&& req
!= PRU_ATTACH
) {
113 if ((error
= at_pcballoc(so
)) != 0) {
116 error
= soreserve(so
, ddp_sendspace
, ddp_recvspace
);
120 at_pcbdetach(so
, ddp
);
124 error
= at_pcbsetaddr(ddp
, addr
, l
);
128 at_sockaddr(ddp
, addr
);
132 if (ddp
->ddp_fsat
.sat_port
!= ATADDR_ANYPORT
) {
136 error
= at_pcbconnect(ddp
, addr
, l
);
142 if (ddp
->ddp_fsat
.sat_addr
.s_node
== ATADDR_ANYNODE
) {
146 at_pcbdisconnect(ddp
);
147 soisdisconnected(so
);
158 if (ddp
->ddp_fsat
.sat_port
!= ATADDR_ANYPORT
) {
163 error
= at_pcbconnect(ddp
, addr
, l
);
169 if (ddp
->ddp_fsat
.sat_port
== ATADDR_ANYPORT
) {
175 error
= ddp_output(m
, ddp
);
178 at_pcbdisconnect(ddp
);
185 soisdisconnected(so
);
186 at_pcbdetach(so
, ddp
);
203 * Don't mfree. Good architecture...
209 * 1. Don't return block size.
226 at_sockaddr(struct ddpcb
*ddp
, struct mbuf
*addr
)
228 struct sockaddr_at
*sat
;
230 addr
->m_len
= sizeof(struct sockaddr_at
);
231 sat
= mtod(addr
, struct sockaddr_at
*);
232 *sat
= ddp
->ddp_lsat
;
236 at_pcbsetaddr(struct ddpcb
*ddp
, struct mbuf
*addr
, struct lwp
*l
)
238 struct sockaddr_at lsat
, *sat
;
239 struct at_ifaddr
*aa
;
242 if (ddp
->ddp_lsat
.sat_port
!= ATADDR_ANYPORT
) { /* shouldn't be bound */
245 if (addr
!= 0) { /* validate passed address */
246 sat
= mtod(addr
, struct sockaddr_at
*);
247 if (addr
->m_len
!= sizeof(*sat
))
250 if (sat
->sat_family
!= AF_APPLETALK
)
251 return (EAFNOSUPPORT
);
253 if (sat
->sat_addr
.s_node
!= ATADDR_ANYNODE
||
254 sat
->sat_addr
.s_net
!= ATADDR_ANYNET
) {
255 TAILQ_FOREACH(aa
, &at_ifaddr
, aa_list
) {
256 if ((sat
->sat_addr
.s_net
==
257 AA_SAT(aa
)->sat_addr
.s_net
) &&
258 (sat
->sat_addr
.s_node
==
259 AA_SAT(aa
)->sat_addr
.s_node
))
263 return (EADDRNOTAVAIL
);
265 if (sat
->sat_port
!= ATADDR_ANYPORT
) {
268 if (sat
->sat_port
< ATPORT_FIRST
||
269 sat
->sat_port
>= ATPORT_LAST
)
272 if (sat
->sat_port
< ATPORT_RESERVED
&& l
&&
273 (error
= kauth_authorize_network(l
->l_cred
,
274 KAUTH_NETWORK_BIND
, KAUTH_REQ_NETWORK_BIND_PRIVPORT
,
275 ddpcb
->ddp_socket
, sat
, NULL
)) != 0)
279 memset((void *) & lsat
, 0, sizeof(struct sockaddr_at
));
280 lsat
.sat_len
= sizeof(struct sockaddr_at
);
281 lsat
.sat_addr
.s_node
= ATADDR_ANYNODE
;
282 lsat
.sat_addr
.s_net
= ATADDR_ANYNET
;
283 lsat
.sat_family
= AF_APPLETALK
;
287 if (sat
->sat_addr
.s_node
== ATADDR_ANYNODE
&&
288 sat
->sat_addr
.s_net
== ATADDR_ANYNET
) {
289 if (TAILQ_EMPTY(&at_ifaddr
))
290 return EADDRNOTAVAIL
;
291 sat
->sat_addr
= AA_SAT(TAILQ_FIRST(&at_ifaddr
))->sat_addr
;
293 ddp
->ddp_lsat
= *sat
;
298 if (sat
->sat_port
== ATADDR_ANYPORT
) {
299 for (sat
->sat_port
= ATPORT_RESERVED
;
300 sat
->sat_port
< ATPORT_LAST
; sat
->sat_port
++) {
301 if (ddp_ports
[sat
->sat_port
- 1] == 0)
304 if (sat
->sat_port
== ATPORT_LAST
) {
305 return (EADDRNOTAVAIL
);
307 ddp
->ddp_lsat
.sat_port
= sat
->sat_port
;
308 ddp_ports
[sat
->sat_port
- 1] = ddp
;
310 for (ddpp
= ddp_ports
[sat
->sat_port
- 1]; ddpp
;
311 ddpp
= ddpp
->ddp_pnext
) {
312 if (ddpp
->ddp_lsat
.sat_addr
.s_net
==
313 sat
->sat_addr
.s_net
&&
314 ddpp
->ddp_lsat
.sat_addr
.s_node
==
315 sat
->sat_addr
.s_node
)
321 ddp
->ddp_pnext
= ddp_ports
[sat
->sat_port
- 1];
322 ddp_ports
[sat
->sat_port
- 1] = ddp
;
324 ddp
->ddp_pnext
->ddp_pprev
= ddp
;
331 at_pcbconnect(struct ddpcb
*ddp
, struct mbuf
*addr
, struct lwp
*l
)
334 const struct sockaddr_at
*cdst
;
335 struct sockaddr_at
*sat
= mtod(addr
, struct sockaddr_at
*);
337 struct at_ifaddr
*aa
;
339 u_short hintnet
= 0, net
;
341 if (addr
->m_len
!= sizeof(*sat
))
343 if (sat
->sat_family
!= AF_APPLETALK
) {
347 * Under phase 2, network 0 means "the network". We take "the
348 * network" to mean the network the control block is bound to.
349 * If the control block is not bound, there is an error.
351 if (sat
->sat_addr
.s_net
== ATADDR_ANYNET
352 && sat
->sat_addr
.s_node
!= ATADDR_ANYNODE
) {
353 if (ddp
->ddp_lsat
.sat_port
== ATADDR_ANYPORT
) {
354 return EADDRNOTAVAIL
;
356 hintnet
= ddp
->ddp_lsat
.sat_addr
.s_net
;
358 ro
= &ddp
->ddp_route
;
360 * If we've got an old route for this pcb, check that it is valid.
361 * If we've changed our address, we may have an old "good looking"
362 * route here. Attempt to detect it.
364 if ((rt
= rtcache_validate(ro
)) != NULL
||
365 (rt
= rtcache_update(ro
, 1)) != NULL
) {
369 net
= sat
->sat_addr
.s_net
;
371 if ((ifp
= rt
->rt_ifp
) != NULL
) {
372 TAILQ_FOREACH(aa
, &at_ifaddr
, aa_list
) {
373 if (aa
->aa_ifp
== ifp
&&
374 ntohs(net
) >= ntohs(aa
->aa_firstnet
) &&
375 ntohs(net
) <= ntohs(aa
->aa_lastnet
)) {
381 cdst
= satocsat(rtcache_getdst(ro
));
382 if (aa
== NULL
|| (cdst
->sat_addr
.s_net
!=
383 (hintnet
? hintnet
: sat
->sat_addr
.s_net
) ||
384 cdst
->sat_addr
.s_node
!= sat
->sat_addr
.s_node
)) {
390 * If we've got no route for this interface, try to find one.
395 struct sockaddr_at dsta
;
398 sockaddr_at_init(&u
.dsta
, &sat
->sat_addr
, 0);
400 u
.dsta
.sat_addr
.s_net
= hintnet
;
401 rt
= rtcache_lookup(ro
, &u
.dst
);
404 * Make sure any route that we have has a valid interface.
406 if (rt
!= NULL
&& (ifp
= rt
->rt_ifp
) != NULL
) {
407 TAILQ_FOREACH(aa
, &at_ifaddr
, aa_list
) {
408 if (aa
->aa_ifp
== ifp
)
415 ddp
->ddp_fsat
= *sat
;
416 if (ddp
->ddp_lsat
.sat_port
== ATADDR_ANYPORT
)
417 return at_pcbsetaddr(ddp
, NULL
, l
);
422 at_pcbdisconnect(struct ddpcb
*ddp
)
424 ddp
->ddp_fsat
.sat_addr
.s_net
= ATADDR_ANYNET
;
425 ddp
->ddp_fsat
.sat_addr
.s_node
= ATADDR_ANYNODE
;
426 ddp
->ddp_fsat
.sat_port
= ATADDR_ANYPORT
;
430 at_pcballoc(struct socket
*so
)
434 ddp
= malloc(sizeof(*ddp
), M_PCB
, M_WAITOK
|M_ZERO
);
436 panic("at_pcballoc");
437 ddp
->ddp_lsat
.sat_port
= ATADDR_ANYPORT
;
439 ddp
->ddp_next
= ddpcb
;
440 ddp
->ddp_prev
= NULL
;
441 ddp
->ddp_pprev
= NULL
;
442 ddp
->ddp_pnext
= NULL
;
444 ddpcb
->ddp_prev
= ddp
;
448 ddp
->ddp_socket
= so
;
449 so
->so_pcb
= (void *) ddp
;
451 so
->so_rcv
.sb_mowner
= &atalk_rx_mowner
;
452 so
->so_snd
.sb_mowner
= &atalk_tx_mowner
;
458 at_pcbdetach(struct socket
*so
, struct ddpcb
*ddp
)
460 soisdisconnected(so
);
462 /* sofree drops the lock */
464 mutex_enter(softnet_lock
);
466 /* remove ddp from ddp_ports list */
467 if (ddp
->ddp_lsat
.sat_port
!= ATADDR_ANYPORT
&&
468 ddp_ports
[ddp
->ddp_lsat
.sat_port
- 1] != NULL
) {
469 if (ddp
->ddp_pprev
!= NULL
) {
470 ddp
->ddp_pprev
->ddp_pnext
= ddp
->ddp_pnext
;
472 ddp_ports
[ddp
->ddp_lsat
.sat_port
- 1] = ddp
->ddp_pnext
;
474 if (ddp
->ddp_pnext
!= NULL
) {
475 ddp
->ddp_pnext
->ddp_pprev
= ddp
->ddp_pprev
;
478 rtcache_free(&ddp
->ddp_route
);
480 ddp
->ddp_prev
->ddp_next
= ddp
->ddp_next
;
482 ddpcb
= ddp
->ddp_next
;
485 ddp
->ddp_next
->ddp_prev
= ddp
->ddp_prev
;
491 * For the moment, this just find the pcb with the correct local address.
492 * In the future, this will actually do some real searching, so we can use
493 * the sender's address to do de-multiplexing on a single port to many
498 struct sockaddr_at
*from
,
499 struct sockaddr_at
*to
,
500 struct at_ifaddr
*aa
)
505 * Check for bad ports.
507 if (to
->sat_port
< ATPORT_FIRST
|| to
->sat_port
>= ATPORT_LAST
)
511 * Make sure the local address matches the sent address. What about
514 for (ddp
= ddp_ports
[to
->sat_port
- 1]; ddp
; ddp
= ddp
->ddp_pnext
) {
515 /* XXX should we handle 0.YY? */
517 /* XXXX.YY to socket on destination interface */
518 if (to
->sat_addr
.s_net
== ddp
->ddp_lsat
.sat_addr
.s_net
&&
519 to
->sat_addr
.s_node
== ddp
->ddp_lsat
.sat_addr
.s_node
) {
522 /* 0.255 to socket on receiving interface */
523 if (to
->sat_addr
.s_node
== ATADDR_BCAST
&&
524 (to
->sat_addr
.s_net
== 0 ||
525 to
->sat_addr
.s_net
== ddp
->ddp_lsat
.sat_addr
.s_net
) &&
526 ddp
->ddp_lsat
.sat_addr
.s_net
== AA_SAT(aa
)->sat_addr
.s_net
) {
529 /* XXXX.0 to socket on destination interface */
530 if (to
->sat_addr
.s_net
== aa
->aa_firstnet
&&
531 to
->sat_addr
.s_node
== 0 &&
532 ntohs(ddp
->ddp_lsat
.sat_addr
.s_net
) >=
533 ntohs(aa
->aa_firstnet
) &&
534 ntohs(ddp
->ddp_lsat
.sat_addr
.s_net
) <=
535 ntohs(aa
->aa_lastnet
)) {
543 * Initialize all the ddp & appletalk stuff
549 ddpstat_percpu
= percpu_alloc(sizeof(uint64_t) * DDP_NSTATS
);
551 TAILQ_INIT(&at_ifaddr
);
552 atintrq1
.ifq_maxlen
= IFQ_MAXLEN
;
553 atintrq2
.ifq_maxlen
= IFQ_MAXLEN
;
555 MOWNER_ATTACH(&atalk_tx_mowner
);
556 MOWNER_ATTACH(&atalk_rx_mowner
);
565 for (ddp
= ddpcb
; ddp
; ddp
= ddp
->ddp_next
)
566 at_pcbdetach(ddp
->ddp_socket
, ddp
);
571 sysctl_net_atalk_ddp_stats(SYSCTLFN_ARGS
)
574 return (NETSTAT_SYSCTL(ddpstat_percpu
, DDP_NSTATS
));
578 * Sysctl for DDP variables.
580 SYSCTL_SETUP(sysctl_net_atalk_ddp_setup
, "sysctl net.atalk.ddp subtree setup")
583 sysctl_createv(clog
, 0, NULL
, NULL
,
585 CTLTYPE_NODE
, "net", NULL
,
588 sysctl_createv(clog
, 0, NULL
, NULL
,
590 CTLTYPE_NODE
, "atalk", NULL
,
592 CTL_NET
, PF_APPLETALK
, CTL_EOL
);
593 sysctl_createv(clog
, 0, NULL
, NULL
,
596 SYSCTL_DESCR("DDP related settings"),
598 CTL_NET
, PF_APPLETALK
, ATPROTO_DDP
, CTL_EOL
);
600 sysctl_createv(clog
, 0, NULL
, NULL
,
602 CTLTYPE_STRUCT
, "stats",
603 SYSCTL_DESCR("DDP statistics"),
604 sysctl_net_atalk_ddp_stats
, 0, NULL
, 0,
605 CTL_NET
, PF_APPLETALK
, ATPROTO_DDP
, CTL_CREATE
,