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