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