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