2 * Copyright (c) 1990,1994 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
5 * $DragonFly: src/sys/netproto/atalk/ddp_usrreq.c,v 1.11 2007/04/21 02:26:48 dillon Exp $
11 #include <sys/malloc.h>
13 #include <sys/socket.h>
14 #include <sys/socketvar.h>
15 #include <sys/protosw.h>
16 #include <sys/thread2.h>
18 #include <net/netisr.h>
19 #include <net/route.h>
24 #include "at_extern.h"
26 static void at_pcbdisconnect( struct ddpcb
*ddp
);
27 static void at_sockaddr(struct ddpcb
*ddp
, struct sockaddr
**addr
);
28 static int at_pcbsetaddr(struct ddpcb
*ddp
, struct sockaddr
*addr
,
30 static int at_pcbconnect(struct ddpcb
*ddp
, struct sockaddr
*addr
,
32 static void at_pcbdetach(struct socket
*so
, struct ddpcb
*ddp
);
33 static int at_pcballoc(struct socket
*so
);
35 struct ddpcb
*ddp_ports
[ ATPORT_LAST
];
36 struct ddpcb
*ddpcb
= NULL
;
37 static u_long ddp_sendspace
= DDP_MAXSZ
; /* Max ddp size + 1 (ddp_type) */
38 static u_long ddp_recvspace
= 10 * ( 587 + sizeof( struct sockaddr_at
));
41 ddp_attach(struct socket
*so
, int proto
, struct pru_attach_info
*ai
)
47 ddp
= sotoddpcb( so
);
53 error
= at_pcballoc( so
);
58 return (soreserve( so
, ddp_sendspace
, ddp_recvspace
, ai
->sb_rlimit
));
62 ddp_detach(struct socket
*so
)
66 ddp
= sotoddpcb( so
);
71 at_pcbdetach( so
, ddp
);
77 ddp_bind(struct socket
*so
, struct sockaddr
*nam
, struct thread
*td
)
82 ddp
= sotoddpcb( so
);
87 error
= at_pcbsetaddr(ddp
, nam
, td
);
93 ddp_connect(struct socket
*so
, struct sockaddr
*nam
, struct thread
*td
)
98 ddp
= sotoddpcb( so
);
103 if ( ddp
->ddp_fsat
.sat_port
!= ATADDR_ANYPORT
) {
108 error
= at_pcbconnect( ddp
, nam
, td
);
116 ddp_disconnect(struct socket
*so
)
121 ddp
= sotoddpcb( so
);
125 if ( ddp
->ddp_fsat
.sat_addr
.s_node
== ATADDR_ANYNODE
) {
130 at_pcbdisconnect( ddp
);
131 ddp
->ddp_fsat
.sat_addr
.s_node
= ATADDR_ANYNODE
;
133 soisdisconnected( so
);
138 ddp_shutdown(struct socket
*so
)
142 ddp
= sotoddpcb( so
);
146 socantsendmore( so
);
151 ddp_send(struct socket
*so
, int flags
, struct mbuf
*m
, struct sockaddr
*addr
,
152 struct mbuf
*control
, struct thread
*td
)
157 ddp
= sotoddpcb( so
);
162 if ( control
&& control
->m_len
) {
167 if ( ddp
->ddp_fsat
.sat_port
!= ATADDR_ANYPORT
) {
172 error
= at_pcbconnect(ddp
, addr
, td
);
178 if ( ddp
->ddp_fsat
.sat_port
== ATADDR_ANYPORT
) {
184 error
= ddp_output( m
, so
);
186 at_pcbdisconnect( ddp
);
193 ddp_abort(struct socket
*so
)
197 ddp
= sotoddpcb( so
);
201 soisdisconnected( so
);
203 at_pcbdetach( so
, ddp
);
210 at_sockaddr(struct ddpcb
*ddp
, struct sockaddr
**addr
)
212 *addr
= dup_sockaddr((struct sockaddr
*)&ddp
->ddp_lsat
);
216 at_pcbsetaddr(struct ddpcb
*ddp
, struct sockaddr
*addr
, struct thread
*td
)
218 struct sockaddr_at lsat
, *sat
;
219 struct at_ifaddr
*aa
;
222 if ( ddp
->ddp_lsat
.sat_port
!= ATADDR_ANYPORT
) { /* shouldn't be bound */
226 if (addr
!= 0) { /* validate passed address */
227 sat
= (struct sockaddr_at
*)addr
;
228 if (sat
->sat_family
!= AF_APPLETALK
) {
229 return(EAFNOSUPPORT
);
232 if ( sat
->sat_addr
.s_node
!= ATADDR_ANYNODE
||
233 sat
->sat_addr
.s_net
!= ATADDR_ANYNET
) {
234 for ( aa
= at_ifaddr
; aa
; aa
= aa
->aa_next
) {
235 if (( sat
->sat_addr
.s_net
== AA_SAT( aa
)->sat_addr
.s_net
) &&
236 ( sat
->sat_addr
.s_node
== AA_SAT( aa
)->sat_addr
.s_node
)) {
241 return( EADDRNOTAVAIL
);
245 if ( sat
->sat_port
!= ATADDR_ANYPORT
) {
246 if ( sat
->sat_port
< ATPORT_FIRST
||
247 sat
->sat_port
>= ATPORT_LAST
) {
250 if ( sat
->sat_port
< ATPORT_RESERVED
&&
256 bzero( (caddr_t
)&lsat
, sizeof( struct sockaddr_at
));
257 lsat
.sat_len
= sizeof(struct sockaddr_at
);
258 lsat
.sat_addr
.s_node
= ATADDR_ANYNODE
;
259 lsat
.sat_addr
.s_net
= ATADDR_ANYNET
;
260 lsat
.sat_family
= AF_APPLETALK
;
264 if ( sat
->sat_addr
.s_node
== ATADDR_ANYNODE
&&
265 sat
->sat_addr
.s_net
== ATADDR_ANYNET
) {
266 if ( at_ifaddr
== NULL
) {
267 return( EADDRNOTAVAIL
);
269 sat
->sat_addr
= AA_SAT( at_ifaddr
)->sat_addr
;
271 ddp
->ddp_lsat
= *sat
;
276 if ( sat
->sat_port
== ATADDR_ANYPORT
) {
277 for ( sat
->sat_port
= ATPORT_RESERVED
;
278 sat
->sat_port
< ATPORT_LAST
; sat
->sat_port
++ ) {
279 if ( ddp_ports
[ sat
->sat_port
- 1 ] == 0 ) {
283 if ( sat
->sat_port
== ATPORT_LAST
) {
284 return( EADDRNOTAVAIL
);
286 ddp
->ddp_lsat
.sat_port
= sat
->sat_port
;
287 ddp_ports
[ sat
->sat_port
- 1 ] = ddp
;
289 for ( ddpp
= ddp_ports
[ sat
->sat_port
- 1 ]; ddpp
;
290 ddpp
= ddpp
->ddp_pnext
) {
291 if ( ddpp
->ddp_lsat
.sat_addr
.s_net
== sat
->sat_addr
.s_net
&&
292 ddpp
->ddp_lsat
.sat_addr
.s_node
== sat
->sat_addr
.s_node
) {
296 if ( ddpp
!= NULL
) {
297 return( EADDRINUSE
);
299 ddp
->ddp_pnext
= ddp_ports
[ sat
->sat_port
- 1 ];
300 ddp_ports
[ sat
->sat_port
- 1 ] = ddp
;
301 if ( ddp
->ddp_pnext
) {
302 ddp
->ddp_pnext
->ddp_pprev
= ddp
;
310 at_pcbconnect(struct ddpcb
*ddp
, struct sockaddr
*addr
, struct thread
*td
)
312 struct sockaddr_at
*sat
= (struct sockaddr_at
*)addr
;
314 struct at_ifaddr
*aa
= 0;
316 u_short hintnet
= 0, net
;
318 if (sat
->sat_family
!= AF_APPLETALK
) {
319 return(EAFNOSUPPORT
);
323 * Under phase 2, network 0 means "the network". We take "the
324 * network" to mean the network the control block is bound to.
325 * If the control block is not bound, there is an error.
327 if ( sat
->sat_addr
.s_net
== ATADDR_ANYNET
328 && sat
->sat_addr
.s_node
!= ATADDR_ANYNODE
) {
329 if ( ddp
->ddp_lsat
.sat_port
== ATADDR_ANYPORT
) {
330 return( EADDRNOTAVAIL
);
332 hintnet
= ddp
->ddp_lsat
.sat_addr
.s_net
;
335 ro
= &ddp
->ddp_route
;
337 * If we've got an old route for this pcb, check that it is valid.
338 * If we've changed our address, we may have an old "good looking"
339 * route here. Attempt to detect it.
345 net
= sat
->sat_addr
.s_net
;
348 if ((ifp
= ro
->ro_rt
->rt_ifp
) != NULL
) {
349 for ( aa
= at_ifaddr
; aa
; aa
= aa
->aa_next
) {
350 if ( aa
->aa_ifp
== ifp
&&
351 ntohs( net
) >= ntohs( aa
->aa_firstnet
) &&
352 ntohs( net
) <= ntohs( aa
->aa_lastnet
)) {
357 if ( aa
== NULL
|| ( satosat( &ro
->ro_dst
)->sat_addr
.s_net
!=
358 ( hintnet
? hintnet
: sat
->sat_addr
.s_net
) ||
359 satosat( &ro
->ro_dst
)->sat_addr
.s_node
!=
360 sat
->sat_addr
.s_node
)) {
362 ro
->ro_rt
= (struct rtentry
*)0;
367 * If we've got no route for this interface, try to find one.
369 if ( ro
->ro_rt
== (struct rtentry
*)0 ||
370 ro
->ro_rt
->rt_ifp
== (struct ifnet
*)0 ) {
371 ro
->ro_dst
.sa_len
= sizeof( struct sockaddr_at
);
372 ro
->ro_dst
.sa_family
= AF_APPLETALK
;
374 satosat( &ro
->ro_dst
)->sat_addr
.s_net
= hintnet
;
376 satosat( &ro
->ro_dst
)->sat_addr
.s_net
= sat
->sat_addr
.s_net
;
378 satosat( &ro
->ro_dst
)->sat_addr
.s_node
= sat
->sat_addr
.s_node
;
383 * Make sure any route that we have has a valid interface.
386 if ( ro
->ro_rt
&& ( ifp
= ro
->ro_rt
->rt_ifp
)) {
387 for ( aa
= at_ifaddr
; aa
; aa
= aa
->aa_next
) {
388 if ( aa
->aa_ifp
== ifp
) {
394 return( ENETUNREACH
);
397 ddp
->ddp_fsat
= *sat
;
398 if ( ddp
->ddp_lsat
.sat_port
== ATADDR_ANYPORT
) {
399 return(at_pcbsetaddr(ddp
, (struct sockaddr
*)0, td
));
405 at_pcbdisconnect( struct ddpcb
*ddp
)
407 ddp
->ddp_fsat
.sat_addr
.s_net
= ATADDR_ANYNET
;
408 ddp
->ddp_fsat
.sat_addr
.s_node
= ATADDR_ANYNODE
;
409 ddp
->ddp_fsat
.sat_port
= ATADDR_ANYPORT
;
413 at_pcballoc( struct socket
*so
)
417 MALLOC(ddp
, struct ddpcb
*, sizeof *ddp
, M_PCB
, M_WAITOK
);
418 bzero(ddp
, sizeof *ddp
);
419 ddp
->ddp_lsat
.sat_port
= ATADDR_ANYPORT
;
421 ddp
->ddp_next
= ddpcb
;
422 ddp
->ddp_prev
= NULL
;
423 ddp
->ddp_pprev
= NULL
;
424 ddp
->ddp_pnext
= NULL
;
426 ddpcb
->ddp_prev
= ddp
;
430 ddp
->ddp_socket
= so
;
431 so
->so_pcb
= (caddr_t
)ddp
;
436 at_pcbdetach( struct socket
*so
, struct ddpcb
*ddp
)
438 soisdisconnected( so
);
442 /* remove ddp from ddp_ports list */
443 if ( ddp
->ddp_lsat
.sat_port
!= ATADDR_ANYPORT
&&
444 ddp_ports
[ ddp
->ddp_lsat
.sat_port
- 1 ] != NULL
) {
445 if ( ddp
->ddp_pprev
!= NULL
) {
446 ddp
->ddp_pprev
->ddp_pnext
= ddp
->ddp_pnext
;
448 ddp_ports
[ ddp
->ddp_lsat
.sat_port
- 1 ] = ddp
->ddp_pnext
;
450 if ( ddp
->ddp_pnext
!= NULL
) {
451 ddp
->ddp_pnext
->ddp_pprev
= ddp
->ddp_pprev
;
455 if ( ddp
->ddp_route
.ro_rt
) {
456 rtfree( ddp
->ddp_route
.ro_rt
);
459 if ( ddp
->ddp_prev
) {
460 ddp
->ddp_prev
->ddp_next
= ddp
->ddp_next
;
462 ddpcb
= ddp
->ddp_next
;
464 if ( ddp
->ddp_next
) {
465 ddp
->ddp_next
->ddp_prev
= ddp
->ddp_prev
;
471 * For the moment, this just find the pcb with the correct local address.
472 * In the future, this will actually do some real searching, so we can use
473 * the sender's address to do de-multiplexing on a single port to many
477 ddp_search( struct sockaddr_at
*from
, struct sockaddr_at
*to
,
478 struct at_ifaddr
*aa
)
483 * Check for bad ports.
485 if ( to
->sat_port
< ATPORT_FIRST
|| to
->sat_port
>= ATPORT_LAST
) {
490 * Make sure the local address matches the sent address. What about
493 for ( ddp
= ddp_ports
[ to
->sat_port
- 1 ]; ddp
; ddp
= ddp
->ddp_pnext
) {
494 /* XXX should we handle 0.YY? */
496 /* XXXX.YY to socket on destination interface */
497 if ( to
->sat_addr
.s_net
== ddp
->ddp_lsat
.sat_addr
.s_net
&&
498 to
->sat_addr
.s_node
== ddp
->ddp_lsat
.sat_addr
.s_node
) {
502 /* 0.255 to socket on receiving interface */
503 if ( to
->sat_addr
.s_node
== ATADDR_BCAST
&& ( to
->sat_addr
.s_net
== 0 ||
504 to
->sat_addr
.s_net
== ddp
->ddp_lsat
.sat_addr
.s_net
) &&
505 ddp
->ddp_lsat
.sat_addr
.s_net
== AA_SAT( aa
)->sat_addr
.s_net
) {
509 /* XXXX.0 to socket on destination interface */
510 if ( to
->sat_addr
.s_net
== aa
->aa_firstnet
&&
511 to
->sat_addr
.s_node
== 0 &&
512 ntohs( ddp
->ddp_lsat
.sat_addr
.s_net
) >=
513 ntohs( aa
->aa_firstnet
) &&
514 ntohs( ddp
->ddp_lsat
.sat_addr
.s_net
) <=
515 ntohs( aa
->aa_lastnet
)) {
522 at_setpeeraddr(struct socket
*so
, struct sockaddr
**nam
)
528 at_setsockaddr(struct socket
*so
, struct sockaddr
**nam
)
532 ddp
= sotoddpcb( so
);
536 at_sockaddr( ddp
, nam
);
544 netisr_register(NETISR_ATALK1
, cpu0_portfn
, at1intr
);
545 netisr_register(NETISR_ATALK2
, cpu0_portfn
, at2intr
);
546 netisr_register(NETISR_AARP
, cpu0_portfn
, aarpintr
);
555 for ( ddp
= ddpcb
; ddp
; ddp
= ddp
->ddp_next
) {
556 at_pcbdetach( ddp
->ddp_socket
, ddp
);
561 struct pr_usrreqs ddp_usrreqs
= {
562 .pru_abort
= ddp_abort
,
563 .pru_accept
= pru_accept_notsupp
,
564 .pru_attach
= ddp_attach
,
565 .pru_bind
= ddp_bind
,
566 .pru_connect
= ddp_connect
,
567 .pru_connect2
= pru_connect2_notsupp
,
568 .pru_control
= at_control
,
569 .pru_detach
= ddp_detach
,
570 .pru_disconnect
= ddp_disconnect
,
571 .pru_listen
= pru_listen_notsupp
,
572 .pru_peeraddr
= at_setpeeraddr
,
573 .pru_rcvd
= pru_rcvd_notsupp
,
574 .pru_rcvoob
= pru_rcvoob_notsupp
,
575 .pru_send
= ddp_send
,
576 .pru_sense
= pru_sense_null
,
577 .pru_shutdown
= ddp_shutdown
,
578 .pru_sockaddr
= at_setsockaddr
,
579 .pru_sosend
= sosend
,
580 .pru_soreceive
= soreceive
,