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