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