Deleted Added
full compact
1/*
2 * Copyright (c) 1990,1994 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
4 */
5
6#include <sys/param.h>
7#include <sys/systm.h>
8#include <sys/proc.h>
9#include <sys/malloc.h>
10#include <sys/mbuf.h>
11#include <sys/socket.h>
12#include <sys/socketvar.h>
13#include <sys/protosw.h>
14#include <net/if.h>
15#include <net/route.h>
16
17#include <netatalk/at.h>
18#include <netatalk/at_var.h>
19#include <netatalk/ddp_var.h>
20#include <netatalk/at_extern.h>
21
22static void at_pcbdisconnect( struct ddpcb *ddp );
23static void at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr);
24static int at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr,
25 struct proc *p);
26static int at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr,
27 struct proc *p);
28static void at_pcbdetach(struct socket *so, struct ddpcb *ddp);
29static int at_pcballoc(struct socket *so);
30
31struct ddpcb *ddp_ports[ ATPORT_LAST ];
32struct ddpcb *ddpcb = NULL;
33u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */
34u_long ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at ));
33static u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */
34static u_long ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at ));
35
36
37static int
38ddp_attach(struct socket *so, int proto, struct proc *p)
39{
40 struct ddpcb *ddp;
41 int error = 0;
42 int s;
43
44
45 ddp = sotoddpcb( so );
46 if ( ddp != NULL ) {
47 return( EINVAL);
48 }
49
50 s = splnet();
51 error = at_pcballoc( so );
52 splx(s);
53 if (error) {
54 return (error);
55 }
56 return (soreserve( so, ddp_sendspace, ddp_recvspace ));
57}
58
59static int
60ddp_detach(struct socket *so)
61{
62 struct ddpcb *ddp;
63 int error = 0;
64 int s;
65
66 ddp = sotoddpcb( so );
67 if ( ddp == NULL ) {
68 return( EINVAL);
69 }
70 s = splnet();
71 at_pcbdetach( so, ddp );
72 splx(s);
73 return(0);
74}
75
76static int
77ddp_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
78{
79 struct ddpcb *ddp;
80 int error = 0;
81 int s;
82
83 ddp = sotoddpcb( so );
84 if ( ddp == NULL ) {
85 return( EINVAL);
86 }
87 s = splnet();
88 error = at_pcbsetaddr(ddp, nam, p);
89 splx(s);
90 return (error);
91}
92
93static int
94ddp_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
95{
96 struct ddpcb *ddp;
97 int error = 0;
98 int s;
99
100 ddp = sotoddpcb( so );
101 if ( ddp == NULL ) {
102 return( EINVAL);
103 }
104
105 if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) {
106 return(EISCONN);
107 }
108
109 s = splnet();
110 error = at_pcbconnect( ddp, nam, p );
111 splx(s);
112 if ( error == 0 )
113 soisconnected( so );
114 return(error);
115}
116
117static int
118ddp_disconnect(struct socket *so)
119{
120
121 struct ddpcb *ddp;
122 int error = 0;
123 int s;
124
125 ddp = sotoddpcb( so );
126 if ( ddp == NULL ) {
127 return( EINVAL);
128 }
129 if ( ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE ) {
130 return(ENOTCONN);
131 }
132
133 s = splnet();
134 at_pcbdisconnect( ddp );
135 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
136 splx(s);
137 soisdisconnected( so );
138 return(0);
139}
140
141static int
142ddp_shutdown(struct socket *so)
143{
144 struct ddpcb *ddp;
145 int error = 0;
146 int s;
147
148 ddp = sotoddpcb( so );
149 if ( ddp == NULL ) {
150 return( EINVAL);
151 }
152 socantsendmore( so );
153 return(0);
154}
155
156static int
157ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
158 struct mbuf *control, struct proc *p)
159{
160 struct ddpcb *ddp;
161 int error = 0;
162 int s;
163
164 ddp = sotoddpcb( so );
165 if ( ddp == NULL ) {
166 return(EINVAL);
167 }
168
169 if ( control && control->m_len ) {
170 return(EINVAL);
171 }
172
173 if ( addr ) {
174 if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) {
175 return(EISCONN);
176 }
177
178 s = splnet();
179 error = at_pcbconnect(ddp, addr, p);
180 splx( s );
181 if ( error ) {
182 return(error);
183 }
184 } else {
185 if ( ddp->ddp_fsat.sat_port == ATADDR_ANYPORT ) {
186 return(ENOTCONN);
187 }
188 }
189
190 s = splnet();
191 error = ddp_output( m, so );
192 if ( addr ) {
193 at_pcbdisconnect( ddp );
194 }
195 splx(s);
196 return(error);
197}
198
199static int
200ddp_abort(struct socket *so)
201{
202 struct ddpcb *ddp;
203 int s;
204
205 ddp = sotoddpcb( so );
206 if ( ddp == NULL ) {
207 return(EINVAL);
208 }
209 soisdisconnected( so );
210 s = splnet();
211 at_pcbdetach( so, ddp );
212 splx(s);
213 return(0);
214}
215
216
217static void
218at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr)
219{
220 *addr = dup_sockaddr((struct sockaddr *)&ddp->ddp_lsat, 0);
221}
222
223static int
224at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct proc *p)
225{
226 struct sockaddr_at lsat, *sat;
227 struct at_ifaddr *aa;
228 struct ddpcb *ddpp;
229
230 if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT ) { /* shouldn't be bound */
231 return( EINVAL );
232 }
233
234 if (addr != 0) { /* validate passed address */
235 sat = (struct sockaddr_at *)addr;
236 if (sat->sat_family != AF_APPLETALK) {
237 return(EAFNOSUPPORT);
238 }
239
240 if ( sat->sat_addr.s_node != ATADDR_ANYNODE ||
241 sat->sat_addr.s_net != ATADDR_ANYNET ) {
242 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
243 if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) &&
244 ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) {
245 break;
246 }
247 }
248 if ( !aa ) {
249 return( EADDRNOTAVAIL );
250 }
251 }
252
253 if ( sat->sat_port != ATADDR_ANYPORT ) {
254 if ( sat->sat_port < ATPORT_FIRST ||
255 sat->sat_port >= ATPORT_LAST ) {
256 return( EINVAL );
257 }
258 if ( sat->sat_port < ATPORT_RESERVED &&
259 suser( p->p_ucred, &p->p_acflag ) ) {
260 return( EACCES );
261 }
262 }
263 } else {
264 bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at ));
265 lsat.sat_len = sizeof(struct sockaddr_at);
266 lsat.sat_addr.s_node = ATADDR_ANYNODE;
267 lsat.sat_addr.s_net = ATADDR_ANYNET;
268 lsat.sat_family = AF_APPLETALK;
269 sat = &lsat;
270 }
271
272 if ( sat->sat_addr.s_node == ATADDR_ANYNODE &&
273 sat->sat_addr.s_net == ATADDR_ANYNET ) {
274 if ( at_ifaddr == NULL ) {
275 return( EADDRNOTAVAIL );
276 }
277 sat->sat_addr = AA_SAT( at_ifaddr )->sat_addr;
278 }
279 ddp->ddp_lsat = *sat;
280
281 /*
282 * Choose port.
283 */
284 if ( sat->sat_port == ATADDR_ANYPORT ) {
285 for ( sat->sat_port = ATPORT_RESERVED;
286 sat->sat_port < ATPORT_LAST; sat->sat_port++ ) {
287 if ( ddp_ports[ sat->sat_port - 1 ] == 0 ) {
288 break;
289 }
290 }
291 if ( sat->sat_port == ATPORT_LAST ) {
292 return( EADDRNOTAVAIL );
293 }
294 ddp->ddp_lsat.sat_port = sat->sat_port;
295 ddp_ports[ sat->sat_port - 1 ] = ddp;
296 } else {
297 for ( ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp;
298 ddpp = ddpp->ddp_pnext ) {
299 if ( ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net &&
300 ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node ) {
301 break;
302 }
303 }
304 if ( ddpp != NULL ) {
305 return( EADDRINUSE );
306 }
307 ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ];
308 ddp_ports[ sat->sat_port - 1 ] = ddp;
309 if ( ddp->ddp_pnext ) {
310 ddp->ddp_pnext->ddp_pprev = ddp;
311 }
312 }
313
314 return( 0 );
315}
316
317static int
318at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct proc *p)
319{
320 struct sockaddr_at *sat = (struct sockaddr_at *)addr;
321 struct route *ro;
322 struct at_ifaddr *aa = 0;
323 struct ifnet *ifp;
324 u_short hintnet = 0, net;
325
326 if (sat->sat_family != AF_APPLETALK) {
327 return(EAFNOSUPPORT);
328 }
329
330 /*
331 * Under phase 2, network 0 means "the network". We take "the
332 * network" to mean the network the control block is bound to.
333 * If the control block is not bound, there is an error.
334 */
335 if ( sat->sat_addr.s_net == ATADDR_ANYNET
336 && sat->sat_addr.s_node != ATADDR_ANYNODE ) {
337 if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
338 return( EADDRNOTAVAIL );
339 }
340 hintnet = ddp->ddp_lsat.sat_addr.s_net;
341 }
342
343 ro = &ddp->ddp_route;
344 /*
345 * If we've got an old route for this pcb, check that it is valid.
346 * If we've changed our address, we may have an old "good looking"
347 * route here. Attempt to detect it.
348 */
349 if ( ro->ro_rt ) {
350 if ( hintnet ) {
351 net = hintnet;
352 } else {
353 net = sat->sat_addr.s_net;
354 }
355 aa = 0;
356 if ( ifp = ro->ro_rt->rt_ifp ) {
357 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
358 if ( aa->aa_ifp == ifp &&
359 ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
360 ntohs( net ) <= ntohs( aa->aa_lastnet )) {
361 break;
362 }
363 }
364 }
365 if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net !=
366 ( hintnet ? hintnet : sat->sat_addr.s_net ) ||
367 satosat( &ro->ro_dst )->sat_addr.s_node !=
368 sat->sat_addr.s_node )) {
369 RTFREE( ro->ro_rt );
370 ro->ro_rt = (struct rtentry *)0;
371 }
372 }
373
374 /*
375 * If we've got no route for this interface, try to find one.
376 */
377 if ( ro->ro_rt == (struct rtentry *)0 ||
378 ro->ro_rt->rt_ifp == (struct ifnet *)0 ) {
379 ro->ro_dst.sa_len = sizeof( struct sockaddr_at );
380 ro->ro_dst.sa_family = AF_APPLETALK;
381 if ( hintnet ) {
382 satosat( &ro->ro_dst )->sat_addr.s_net = hintnet;
383 } else {
384 satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net;
385 }
386 satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node;
387 rtalloc( ro );
388 }
389
390 /*
391 * Make sure any route that we have has a valid interface.
392 */
393 aa = 0;
394 if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
395 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
396 if ( aa->aa_ifp == ifp ) {
397 break;
398 }
399 }
400 }
401 if ( aa == 0 ) {
402 return( ENETUNREACH );
403 }
404
405 ddp->ddp_fsat = *sat;
406 if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
407 return(at_pcbsetaddr(ddp, (struct sockaddr *)0, p));
408 }
409 return( 0 );
410}
411
412static void
413at_pcbdisconnect( struct ddpcb *ddp )
414{
415 ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
416 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
417 ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
418}
419
420static int
421at_pcballoc( struct socket *so )
422{
423 struct ddpcb *ddp;
424
425 MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_WAITOK);
426 bzero(ddp, sizeof *ddp);
427 ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
428
429 ddp->ddp_next = ddpcb;
430 ddp->ddp_prev = NULL;
431 ddp->ddp_pprev = NULL;
432 ddp->ddp_pnext = NULL;
433 if (ddpcb) {
434 ddpcb->ddp_prev = ddp;
435 }
436 ddpcb = ddp;
437
438 ddp->ddp_socket = so;
439 so->so_pcb = (caddr_t)ddp;
440 return(0);
441}
442
443static void
444at_pcbdetach( struct socket *so, struct ddpcb *ddp)
445{
446 soisdisconnected( so );
447 so->so_pcb = 0;
448 sofree( so );
449
450 /* remove ddp from ddp_ports list */
451 if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
452 ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL ) {
453 if ( ddp->ddp_pprev != NULL ) {
454 ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
455 } else {
456 ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext;
457 }
458 if ( ddp->ddp_pnext != NULL ) {
459 ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
460 }
461 }
462
463 if ( ddp->ddp_route.ro_rt ) {
464 rtfree( ddp->ddp_route.ro_rt );
465 }
466
467 if ( ddp->ddp_prev ) {
468 ddp->ddp_prev->ddp_next = ddp->ddp_next;
469 } else {
470 ddpcb = ddp->ddp_next;
471 }
472 if ( ddp->ddp_next ) {
473 ddp->ddp_next->ddp_prev = ddp->ddp_prev;
474 }
475 FREE(ddp, M_PCB);
476}
477
478/*
479 * For the moment, this just find the pcb with the correct local address.
480 * In the future, this will actually do some real searching, so we can use
481 * the sender's address to do de-multiplexing on a single port to many
482 * sockets (pcbs).
483 */
484struct ddpcb *
485ddp_search( struct sockaddr_at *from, struct sockaddr_at *to,
486 struct at_ifaddr *aa)
487{
488 struct ddpcb *ddp;
489
490 /*
491 * Check for bad ports.
492 */
493 if ( to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST ) {
494 return( NULL );
495 }
496
497 /*
498 * Make sure the local address matches the sent address. What about
499 * the interface?
500 */
501 for ( ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext ) {
502 /* XXX should we handle 0.YY? */
503
504 /* XXXX.YY to socket on destination interface */
505 if ( to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
506 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node ) {
507 break;
508 }
509
510 /* 0.255 to socket on receiving interface */
511 if ( to->sat_addr.s_node == ATADDR_BCAST && ( to->sat_addr.s_net == 0 ||
512 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net ) &&
513 ddp->ddp_lsat.sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) {
514 break;
515 }
516
517 /* XXXX.0 to socket on destination interface */
518 if ( to->sat_addr.s_net == aa->aa_firstnet &&
519 to->sat_addr.s_node == 0 &&
520 ntohs( ddp->ddp_lsat.sat_addr.s_net ) >=
521 ntohs( aa->aa_firstnet ) &&
522 ntohs( ddp->ddp_lsat.sat_addr.s_net ) <=
523 ntohs( aa->aa_lastnet )) {
524 break;
525 }
526 }
527 return( ddp );
528}
529static int
530at_setpeeraddr(struct socket *so, struct sockaddr **nam)
531{
532 return(EOPNOTSUPP);
533}
534
535static int
536at_setsockaddr(struct socket *so, struct sockaddr **nam)
537{
538 struct ddpcb *ddp;
539 int error = 0;
540 int s;
541
542 ddp = sotoddpcb( so );
543 if ( ddp == NULL ) {
544 return( EINVAL);
545 }
546 at_sockaddr( ddp, nam );
547 return(0);
548}
549
550
551void
552ddp_init(void )
553{
554 atintrq1.ifq_maxlen = IFQ_MAXLEN;
555 atintrq2.ifq_maxlen = IFQ_MAXLEN;
556}
557
558#if 0
559static void
560ddp_clean(void )
561{
562 struct ddpcb *ddp;
563
564 for ( ddp = ddpcb; ddp; ddp = ddp->ddp_next ) {
565 at_pcbdetach( ddp->ddp_socket, ddp );
566 }
567}
568#endif
569
570struct pr_usrreqs ddp_usrreqs = {
571 ddp_abort,
572 pru_accept_notsupp,
573 ddp_attach,
574 ddp_bind,
575 ddp_connect,
576 pru_connect2_notsupp,
577 at_control,
578 ddp_detach,
579 ddp_disconnect,
580 pru_listen_notsupp,
581 at_setpeeraddr,
582 pru_rcvd_notsupp,
583 pru_rcvoob_notsupp,
584 ddp_send,
585 pru_sense_null,
586 ddp_shutdown,
587 at_setsockaddr,
588 sosend,
589 soreceive,
590 sopoll
591};