ddp_usrreq.c revision 1.2 1 /* $NetBSD: ddp_usrreq.c,v 1.2 1997/04/29 13:44:47 christos 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
230 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) { /* shouldn't be bound */
231 return (EINVAL);
232 }
233 if (addr != 0) { /* validate passed address */
234 sat = mtod(addr, struct sockaddr_at *);
235 if (addr->m_len != sizeof(*sat))
236 return (EINVAL);
237
238 if (sat->sat_family != AF_APPLETALK)
239 return (EAFNOSUPPORT);
240
241 if (sat->sat_addr.s_node != ATADDR_ANYNODE ||
242 sat->sat_addr.s_net != ATADDR_ANYNET) {
243 for (aa = at_ifaddr.tqh_first; aa;
244 aa = aa->aa_list.tqe_next) {
245 if ((sat->sat_addr.s_net ==
246 AA_SAT(aa)->sat_addr.s_net) &&
247 (sat->sat_addr.s_node ==
248 AA_SAT(aa)->sat_addr.s_node))
249 break;
250 }
251 if (!aa)
252 return (EADDRNOTAVAIL);
253 }
254 if (sat->sat_port != ATADDR_ANYPORT) {
255 if (sat->sat_port < ATPORT_FIRST ||
256 sat->sat_port >= ATPORT_LAST)
257 return (EINVAL);
258
259 if (sat->sat_port < ATPORT_RESERVED &&
260 suser(p->p_ucred, &p->p_acflag))
261 return (EACCES);
262 }
263 } else {
264 bzero((caddr_t) & lsat, sizeof(struct sockaddr_at));
265 lsat.sat_len = sizeof(struct sockaddr_at);
266 lsat.sat_addr.s_node = ATADDR_ANYNODE;
267 lsat.sat_addr.s_net = ATADDR_ANYNET;
268 lsat.sat_family = AF_APPLETALK;
269 sat = &lsat;
270 }
271
272 if (sat->sat_addr.s_node == ATADDR_ANYNODE &&
273 sat->sat_addr.s_net == ATADDR_ANYNET) {
274 if (at_ifaddr.tqh_first == NULL)
275 return (EADDRNOTAVAIL);
276 sat->sat_addr = AA_SAT(at_ifaddr.tqh_first)->sat_addr;
277 }
278 ddp->ddp_lsat = *sat;
279
280 /*
281 * Choose port.
282 */
283 if (sat->sat_port == ATADDR_ANYPORT) {
284 for (sat->sat_port = ATPORT_RESERVED;
285 sat->sat_port < ATPORT_LAST; sat->sat_port++) {
286 if (ddp_ports[sat->sat_port - 1] == 0)
287 break;
288 }
289 if (sat->sat_port == ATPORT_LAST) {
290 return (EADDRNOTAVAIL);
291 }
292 ddp->ddp_lsat.sat_port = sat->sat_port;
293 ddp_ports[sat->sat_port - 1] = ddp;
294 } else {
295 for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp;
296 ddpp = ddpp->ddp_pnext) {
297 if (ddpp->ddp_lsat.sat_addr.s_net ==
298 sat->sat_addr.s_net &&
299 ddpp->ddp_lsat.sat_addr.s_node ==
300 sat->sat_addr.s_node)
301 break;
302 }
303 if (ddpp != NULL)
304 return (EADDRINUSE);
305
306 ddp->ddp_pnext = ddp_ports[sat->sat_port - 1];
307 ddp_ports[sat->sat_port - 1] = ddp;
308 if (ddp->ddp_pnext)
309 ddp->ddp_pnext->ddp_pprev = ddp;
310 }
311
312 return 0;
313 }
314
315 static int
316 at_pcbconnect(ddp, addr, p)
317 struct ddpcb *ddp;
318 struct mbuf *addr;
319 struct proc *p;
320 {
321 struct sockaddr_at *sat = mtod(addr, struct sockaddr_at *);
322 struct route *ro;
323 struct at_ifaddr *aa = 0;
324 struct ifnet *ifp;
325 u_short hintnet = 0, net;
326
327 if (addr->m_len != sizeof(*sat))
328 return (EINVAL);
329 if (sat->sat_family != AF_APPLETALK) {
330 return (EAFNOSUPPORT);
331 }
332 /*
333 * Under phase 2, network 0 means "the network". We take "the
334 * network" to mean the network the control block is bound to.
335 * If the control block is not bound, there is an error.
336 */
337 if (sat->sat_addr.s_net == ATADDR_ANYNET
338 && sat->sat_addr.s_node != ATADDR_ANYNODE) {
339 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) {
340 return (EADDRNOTAVAIL);
341 }
342 hintnet = ddp->ddp_lsat.sat_addr.s_net;
343 }
344 ro = &ddp->ddp_route;
345 /*
346 * If we've got an old route for this pcb, check that it is valid.
347 * If we've changed our address, we may have an old "good looking"
348 * route here. Attempt to detect it.
349 */
350 if (ro->ro_rt) {
351 if (hintnet) {
352 net = hintnet;
353 } else {
354 net = sat->sat_addr.s_net;
355 }
356 aa = 0;
357 if ((ifp = ro->ro_rt->rt_ifp) != NULL) {
358 for (aa = at_ifaddr.tqh_first; aa;
359 aa = aa->aa_list.tqe_next) {
360 if (aa->aa_ifp == ifp &&
361 ntohs(net) >= ntohs(aa->aa_firstnet) &&
362 ntohs(net) <= ntohs(aa->aa_lastnet)) {
363 break;
364 }
365 }
366 }
367 if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net !=
368 (hintnet ? hintnet : sat->sat_addr.s_net) ||
369 satosat(&ro->ro_dst)->sat_addr.s_node !=
370 sat->sat_addr.s_node)) {
371 RTFREE(ro->ro_rt);
372 ro->ro_rt = (struct rtentry *) 0;
373 }
374 }
375 /*
376 * If we've got no route for this interface, try to find one.
377 */
378 if (ro->ro_rt == (struct rtentry *) 0 ||
379 ro->ro_rt->rt_ifp == (struct ifnet *) 0) {
380 bzero(&ro->ro_dst, sizeof(struct sockaddr_at));
381 ro->ro_dst.sa_len = sizeof(struct sockaddr_at);
382 ro->ro_dst.sa_family = AF_APPLETALK;
383 if (hintnet) {
384 satosat(&ro->ro_dst)->sat_addr.s_net = hintnet;
385 } else {
386 satosat(&ro->ro_dst)->sat_addr.s_net =
387 sat->sat_addr.s_net;
388 }
389 satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node;
390 rtalloc(ro);
391 }
392 /*
393 * Make sure any route that we have has a valid interface.
394 */
395 aa = 0;
396 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) {
397 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) {
398 if (aa->aa_ifp == ifp) {
399 break;
400 }
401 }
402 }
403 if (aa == 0) {
404 return (ENETUNREACH);
405 }
406 ddp->ddp_fsat = *sat;
407 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) {
408 return (at_pcbsetaddr(ddp, (struct mbuf *) 0, p));
409 }
410 return (0);
411 }
412
413 static void
414 at_pcbdisconnect(ddp)
415 struct ddpcb *ddp;
416 {
417 ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
418 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
419 ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
420 }
421
422 static int
423 at_pcballoc(so)
424 struct socket *so;
425 {
426 struct ddpcb *ddp;
427
428 MALLOC(ddp, struct ddpcb *, sizeof(*ddp), M_PCB, M_WAIT);
429 if (!ddp)
430 panic("at_pcballoc");
431 bzero((caddr_t) ddp, sizeof *ddp);
432 ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
433
434 ddp->ddp_next = ddpcb;
435 ddp->ddp_prev = NULL;
436 ddp->ddp_pprev = NULL;
437 ddp->ddp_pnext = NULL;
438 if (ddpcb) {
439 ddpcb->ddp_prev = ddp;
440 }
441 ddpcb = ddp;
442
443 ddp->ddp_socket = so;
444 so->so_pcb = (caddr_t) ddp;
445 return (0);
446 }
447
448 static void
449 at_pcbdetach(so, ddp)
450 struct socket *so;
451 struct ddpcb *ddp;
452 {
453 soisdisconnected(so);
454 so->so_pcb = 0;
455 sofree(so);
456
457 /* remove ddp from ddp_ports list */
458 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
459 ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) {
460 if (ddp->ddp_pprev != NULL) {
461 ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
462 } else {
463 ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext;
464 }
465 if (ddp->ddp_pnext != NULL) {
466 ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
467 }
468 }
469 if (ddp->ddp_route.ro_rt) {
470 rtfree(ddp->ddp_route.ro_rt);
471 }
472 if (ddp->ddp_prev) {
473 ddp->ddp_prev->ddp_next = ddp->ddp_next;
474 } else {
475 ddpcb = ddp->ddp_next;
476 }
477 if (ddp->ddp_next) {
478 ddp->ddp_next->ddp_prev = ddp->ddp_prev;
479 }
480 free(ddp, M_PCB);
481 }
482
483 /*
484 * For the moment, this just find the pcb with the correct local address.
485 * In the future, this will actually do some real searching, so we can use
486 * the sender's address to do de-multiplexing on a single port to many
487 * sockets (pcbs).
488 */
489 struct ddpcb *
490 ddp_search(from, to, aa)
491 struct sockaddr_at *from;
492 struct sockaddr_at *to;
493 struct at_ifaddr *aa;
494 {
495 struct ddpcb *ddp;
496
497 /*
498 * Check for bad ports.
499 */
500 if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) {
501 return (NULL);
502 }
503 /*
504 * Make sure the local address matches the sent address. What about
505 * the interface?
506 */
507 for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) {
508 /* XXX should we handle 0.YY? */
509
510 /* XXXX.YY to socket on destination interface */
511 if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
512 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) {
513 break;
514 }
515 /* 0.255 to socket on receiving interface */
516 if (to->sat_addr.s_node == ATADDR_BCAST &&
517 (to->sat_addr.s_net == 0 ||
518 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) &&
519 ddp->ddp_lsat.sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) {
520 break;
521 }
522 /* XXXX.0 to socket on destination interface */
523 if (to->sat_addr.s_net == aa->aa_firstnet &&
524 to->sat_addr.s_node == 0 &&
525 ntohs(ddp->ddp_lsat.sat_addr.s_net) >=
526 ntohs(aa->aa_firstnet) &&
527 ntohs(ddp->ddp_lsat.sat_addr.s_net) <=
528 ntohs(aa->aa_lastnet)) {
529 break;
530 }
531 }
532 return (ddp);
533 }
534
535 /*
536 * Initialize all the ddp & appletalk stuff
537 */
538 void
539 ddp_init()
540 {
541 TAILQ_INIT(&at_ifaddr);
542 atintrq1.ifq_maxlen = IFQ_MAXLEN;
543 atintrq2.ifq_maxlen = IFQ_MAXLEN;
544 }
545
546 #if 0
547 static void
548 ddp_clean()
549 {
550 struct ddpcb *ddp;
551
552 for (ddp = ddpcb; ddp; ddp = ddp->ddp_next)
553 at_pcbdetach(ddp->ddp_socket, ddp);
554 }
555 #endif
556