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