]> git.saurik.com Git - apple/xnu.git/blob - bsd/netat/sys_glue.c
c8a0f11494b54ae3f83b01102009f80d67b10c28
[apple/xnu.git] / bsd / netat / sys_glue.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1995 Apple Computer, Inc.
27 *
28 * Change Log:
29 * Created, March 17, 1997 by Tuyen Nguyen for MacOSX.
30 */
31
32 #include <sys/errno.h>
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <machine/spl.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/proc.h>
39 #include <sys/filedesc.h>
40 #include <sys/fcntl.h>
41 #include <sys/mbuf.h>
42 #include <sys/ioctl.h>
43 #include <sys/malloc.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/ioccom.h>
47
48 #include <sys/sysctl.h>
49
50 #include <net/if.h>
51
52 #include <netat/sysglue.h>
53 #include <netat/appletalk.h>
54 #include <netat/ddp.h>
55 #include <netat/at_pcb.h>
56 #include <netat/at_var.h>
57 #include <netat/routing_tables.h>
58 #include <netat/debug.h>
59
60 extern struct atpcb ddp_head;
61
62 extern void
63 ddp_putmsg(gref_t *gref, gbuf_t *m),
64 elap_wput(gref_t *gref, gbuf_t *m),
65 atp_wput(gref_t *gref, gbuf_t *m),
66 asp_wput(gref_t *gref, gbuf_t *m),
67 #ifdef AURP_SUPPORT
68 aurp_wput(gref_t *gref, gbuf_t *m),
69 #endif
70 adsp_wput(gref_t *gref, gbuf_t *m);
71
72 int atp_free_cluster_timeout_set = 0;
73
74
75 void atalk_putnext(gref_t *gref, gbuf_t *m);
76 /* bms: make gref_close non static so its callable from kernel */
77 int gref_close(gref_t *gref);
78
79 SYSCTL_DECL(_net_appletalk);
80 dbgBits_t dbgBits;
81 SYSCTL_STRUCT(_net_appletalk, OID_AUTO, debug, CTLFLAG_WR,
82 &dbgBits, dbgBits, "AppleTalk Debug Flags");
83 volatile int RouterMix = RT_MIX_DEFAULT; /* default for nbr of ppsec */
84 SYSCTL_INT(_net_appletalk, OID_AUTO, routermix, CTLFLAG_WR,
85 &RouterMix, 0, "Appletalk RouterMix");
86 at_ddp_stats_t at_ddp_stats; /* DDP statistics */
87 SYSCTL_STRUCT(_net_appletalk, OID_AUTO, ddpstats, CTLFLAG_RD,
88 &at_ddp_stats, at_ddp_stats, "AppleTalk DDP Stats");
89
90 atlock_t refall_lock;
91
92 caddr_t atp_free_cluster_list = 0;
93
94 void gref_wput(gref, m)
95 gref_t *gref;
96 gbuf_t *m;
97 {
98 switch (gref->proto) {
99 case ATPROTO_DDP:
100 ddp_putmsg(gref, m); break;
101 case ATPROTO_LAP:
102 elap_wput(gref, m); break;
103 case ATPROTO_ATP:
104 atp_wput(gref, m); break;
105 case ATPROTO_ASP:
106 asp_wput(gref, m); break;
107 #ifdef AURP_SUPPORT
108 case ATPROTO_AURP:
109 aurp_wput(gref, m); break;
110 #endif
111 case ATPROTO_ADSP:
112 adsp_wput(gref, m); break;
113 case ATPROTO_NONE:
114 if (gbuf_type(m) == MSG_IOCTL) {
115 gbuf_freem(gbuf_cont(m));
116 gbuf_cont(m) = 0;
117 ((ioc_t *)gbuf_rptr(m))->ioc_rval = -1;
118 ((ioc_t *)gbuf_rptr(m))->ioc_error = EPROTO;
119 gbuf_set_type(m, MSG_IOCNAK);
120 atalk_putnext(gref, m);
121 } else
122 gbuf_freem(m);
123 break;
124 default:
125 gbuf_freem(m);
126 break;
127 }
128 }
129
130 int _ATsocket(proto, err, proc)
131 int proto;
132 int *err;
133 void *proc;
134 {
135 int fd;
136 gref_t *gref;
137
138 /* make sure the specified protocol id is valid */
139 switch (proto) {
140
141 /* ATPROTO_DDP and ATPROTO_LAP have been replaced with
142 BSD-style socket interface. */
143
144 case ATPROTO_ATP:
145 case ATPROTO_ASP:
146 case ATPROTO_AURP:
147 case ATPROTO_ADSP:
148 break;
149 default:
150 *err = EPROTOTYPE;
151 #ifdef APPLETALK_DEBUG
152 kprintf("_ATsocket: error EPROTOTYPE =%d\n", *err);
153 #endif
154 return -1;
155 }
156
157 /* allocate a protocol channel */
158 if ((*err = gref_alloc(&gref)) != 0) {
159 #ifdef APPLETALK_DEBUG
160 kprintf("_ATsocket: error gref_open =%d\n", *err);
161 #endif
162 return -1;
163 }
164 gref->proto = proto;
165 gref->pid = ((struct proc *)proc)->p_pid;
166
167 /* open the specified protocol */
168 switch (gref->proto) {
169
170 /* ATPROTO_DDP and ATPROTO_LAP have been replaced with
171 BSD-style socket interface. */
172
173 case ATPROTO_ATP:
174 *err = atp_open(gref, 1); break;
175 case ATPROTO_ASP:
176 *err = asp_open(gref); break;
177 #ifdef AURP_SUPPORT
178 case ATPROTO_AURP:
179 *err = aurp_open(gref); break;
180 #endif
181 case ATPROTO_ADSP:
182 *err = adsp_open(gref); break;
183 }
184
185 /* create the descriptor for the channel */
186 if (*err) {
187 #ifdef APPLETALK_DEBUG
188 kprintf("_ATsocket: open failed for %d proto; err = %d\n",
189 gref->proto, *err);
190 #endif
191 gref->proto = ATPROTO_NONE;
192 }
193 if (*err || (*err = atalk_openref(gref, &fd, proc))) {
194 #ifdef APPLETALK_DEBUG
195 kprintf("_ATsocket: error atalk_openref =%d\n", *err);
196 #endif
197 (void)gref_close(gref);
198 return -1;
199 }
200 /*
201 kprintf("_ATsocket: proto=%d return=%d fd=%d\n", proto, *err, fd);
202 */
203 return fd;
204 } /* _ATsocket */
205
206 int _ATgetmsg(fd, ctlptr, datptr, flags, err, proc)
207 int fd;
208 strbuf_t *ctlptr;
209 strbuf_t *datptr;
210 int *flags;
211 int *err;
212 void *proc;
213 {
214 int rc = -1;
215 gref_t *gref;
216
217 if ((*err = atalk_getref(0, fd, &gref, proc)) == 0) {
218 switch (gref->proto) {
219 case ATPROTO_ASP:
220 rc = ASPgetmsg(gref, ctlptr, datptr, NULL, flags, err);
221 break;
222 case ATPROTO_AURP:
223 #ifdef AURP_SUPPORT
224 rc = AURPgetmsg(err);
225 break;
226 #endif
227 default:
228 *err = EPROTONOSUPPORT;
229 break;
230 }
231 }
232
233 /* kprintf("_ATgetmsg: return=%d\n", *err);*/
234 return rc;
235 }
236
237 int _ATputmsg(fd, ctlptr, datptr, flags, err, proc)
238 int fd;
239 strbuf_t *ctlptr;
240 strbuf_t *datptr;
241 int flags;
242 int *err;
243 void *proc;
244 {
245 int rc = -1;
246 gref_t *gref;
247
248 if ((*err = atalk_getref(0, fd, &gref, proc)) == 0) {
249 switch (gref->proto) {
250 case ATPROTO_ASP:
251 rc = ASPputmsg(gref, ctlptr, datptr, NULL, flags, err); break;
252 default:
253 *err = EPROTONOSUPPORT; break;
254 }
255 }
256
257 /* kprintf("_ATputmsg: return=%d\n", *err); */
258 return rc;
259 }
260
261 int _ATclose(fp, proc)
262 struct file *fp;
263 struct proc *proc;
264 {
265 int err;
266 gref_t *gref;
267
268 if ((err = atalk_closeref(fp, &gref)) == 0) {
269 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
270 (void)gref_close(gref);
271 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
272 }
273
274 return err;
275 }
276
277 int _ATrw(fp, rw, uio, ext)
278 void *fp;
279 enum uio_rw rw;
280 struct uio *uio;
281 int ext;
282 {
283 int s, err, len, clen = 0, res;
284 gref_t *gref;
285 gbuf_t *m, *mhead, *mprev;
286
287 if ((err = atalk_getref(fp, 0, &gref, 0)) != 0)
288 return err;
289
290 if ((len = uio->uio_resid) == 0)
291 return 0;
292
293 ATDISABLE(s, gref->lock);
294
295 if (rw == UIO_READ) {
296 KERNEL_DEBUG(DBG_ADSP_ATRW, 0, gref, len, gref->rdhead, 0);
297 while ((gref->errno == 0) && ((mhead = gref->rdhead) == 0)) {
298 gref->sevents |= POLLMSG;
299 err = tsleep(&gref->event, PSOCK | PCATCH, "AT read", 0);
300 gref->sevents &= ~POLLMSG;
301 if (err != 0) {
302 ATENABLE(s, gref->lock);
303 return err;
304 }
305 KERNEL_DEBUG(DBG_ADSP_ATRW, 1, gref, gref->rdhead, mhead, gbuf_next(mhead));
306 }
307
308 if (gref->errno) {
309 ATENABLE(s, gref->lock);
310 return EPIPE;
311 }
312 if ((gref->rdhead = gbuf_next(mhead)) == 0)
313 gref->rdtail = 0;
314
315 KERNEL_DEBUG(DBG_ADSP_ATRW, 2, gref, gref->rdhead, mhead, gbuf_next(mhead));
316
317 ATENABLE(s, gref->lock);
318
319 //##### LD TEST 08/05
320 // simple_lock(&gref->lock);
321
322 gbuf_next(mhead) = 0;
323
324 for (mprev=0, m=mhead; m && len; len-=clen) {
325 if ((clen = gbuf_len(m)) > 0) {
326 if (clen > len)
327 clen = len;
328 uio->uio_rw = UIO_READ;
329 if ((res = uiomove((caddr_t)gbuf_rptr(m),
330 clen, uio))) {
331 KERNEL_DEBUG(DBG_ADSP_ATRW, 3, m, clen,
332 len, gbuf_cont(m));
333 break;
334 }
335 if (gbuf_len(m) > len) {
336 gbuf_rinc(m,clen);
337 break;
338 }
339 }
340 mprev = m;
341 m = gbuf_cont(m);
342 }
343 if (m) {
344 KERNEL_DEBUG(DBG_ADSP_ATRW, 4, m, gbuf_len(m), mprev, gref->rdhead);
345 if (mprev)
346 gbuf_cont(mprev) = 0;
347 else
348 mhead = 0;
349 ATDISABLE(s, gref->lock);
350 if (gref->rdhead == 0)
351 gref->rdtail = m;
352 gbuf_next(m) = gref->rdhead;
353 gref->rdhead = m;
354 ATENABLE(s, gref->lock);
355 }
356 if (mhead)
357 gbuf_freem(mhead);
358 //### LD TEST
359 // simple_unlock(&gref->lock);
360 } else {
361 if (gref->writeable) {
362 while (!(*gref->writeable)(gref)) {
363 /* flow control on, wait to be enabled to write */
364 gref->sevents |= POLLSYNC;
365 err = tsleep(&gref->event, PSOCK | PCATCH, "AT write", 0);
366 gref->sevents &= ~POLLSYNC;
367 if (err != 0) {
368 ATENABLE(s, gref->lock);
369 return err;
370 }
371 }
372 }
373
374 ATENABLE(s, gref->lock);
375
376 /* allocate a buffer to copy in the write data */
377 if ((m = gbuf_alloc(AT_WR_OFFSET+len, PRI_MED)) == 0)
378 return ENOBUFS;
379 gbuf_rinc(m,AT_WR_OFFSET);
380 gbuf_wset(m,len);
381
382 /* copy in the write data */
383 uio->uio_rw = UIO_WRITE;
384 if ((res = uiomove((caddr_t)gbuf_rptr(m), len, uio))) {
385 #ifdef APPLETALK_DEBUG
386 kprintf("_ATrw: UIO_WRITE: res=%d\n", res);
387 #endif
388 gbuf_freeb(m);
389 return EIO;
390 }
391
392 /* forward the write data to the appropriate protocol module */
393 gref_wput(gref, m);
394 }
395
396 return 0;
397 } /* _ATrw */
398
399 int _ATread(fp, uio, cred, flags, p)
400 void *fp;
401 struct uio *uio;
402 void *cred;
403 int flags;
404 struct proc *p;
405 {
406 int stat;
407
408 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
409 stat = _ATrw(fp, UIO_READ, uio, 0);
410 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
411 return stat;
412 }
413
414 int _ATwrite(fp, uio, cred, flags, p)
415 void *fp;
416 struct uio *uio;
417 void *cred;
418 int flags;
419 struct proc *p;
420 {
421 int stat;
422
423
424 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
425 stat = _ATrw(fp, UIO_WRITE, uio, 0);
426 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
427
428 return stat;
429 }
430
431 /* Most of the processing from _ATioctl, so that it can be called
432 from the new ioctl code */
433 /* bms: update to be callable from kernel */
434 int at_ioctl(gref_t *gref, u_long cmd, caddr_t arg, int fromKernel)
435 {
436 int s, err = 0, len;
437 gbuf_t *m, *mdata;
438 ioc_t *ioc;
439 ioccmd_t ioccmd;
440
441 /* error if not for us */
442 if ((cmd & 0xffff) != 0xff99)
443 return EOPNOTSUPP;
444
445 /* copy in ioc command info */
446 /*
447 kprintf("at_ioctl: arg ioccmd.ic_cmd=%x ic_len=%x gref->lock=%x, gref->event=%x\n",
448 ((ioccmd_t *)arg)->ic_cmd, ((ioccmd_t *)arg)->ic_len,
449 gref->lock, gref->event);
450 */
451 if (fromKernel)
452 bcopy (arg, &ioccmd, sizeof (ioccmd_t));
453 else {
454 if ((err = copyin((caddr_t)arg, (caddr_t)&ioccmd, sizeof(ioccmd_t))) != 0) {
455 #ifdef APPLETALK_DEBUG
456 kprintf("at_ioctl: err = %d, copyin(%x, %x, %d)\n", err,
457 (caddr_t)arg, (caddr_t)&ioccmd, sizeof(ioccmd_t));
458 #endif
459 return err;
460 }
461 }
462
463 /* allocate a buffer to create an ioc command
464 first mbuf contains ioc command */
465 if ((m = gbuf_alloc(sizeof(ioc_t), PRI_HI)) == 0)
466 return ENOBUFS;
467 gbuf_wset(m, sizeof(ioc_t)); /* mbuf->m_len */
468 gbuf_set_type(m, MSG_IOCTL); /* mbuf->m_type */
469
470 /* create the ioc command
471 second mbuf contains the actual ASP command */
472 if (ioccmd.ic_len) {
473 if ((gbuf_cont(m) = gbuf_alloc(ioccmd.ic_len, PRI_HI)) == 0) {
474 gbuf_freem(m);
475 #ifdef APPLETALK_DEBUG
476 kprintf("at_ioctl: gbuf_alloc err=%d\n",ENOBUFS);
477 #endif
478 return ENOBUFS;
479 }
480 gbuf_wset(gbuf_cont(m), ioccmd.ic_len); /* mbuf->m_len */
481 if (fromKernel)
482 bcopy (ioccmd.ic_dp, gbuf_rptr(gbuf_cont(m)), ioccmd.ic_len);
483 else {
484 if ((err = copyin((caddr_t)ioccmd.ic_dp, (caddr_t)gbuf_rptr(gbuf_cont(m)), ioccmd.ic_len)) != 0) {
485 gbuf_freem(m);
486 return err;
487 }
488 }
489 }
490 ioc = (ioc_t *) gbuf_rptr(m);
491 ioc->ioc_cmd = ioccmd.ic_cmd;
492 ioc->ioc_count = ioccmd.ic_len;
493 ioc->ioc_error = 0;
494 ioc->ioc_rval = 0;
495
496 /* send the ioc command to the appropriate recipient */
497 gref_wput(gref, m);
498
499 /* wait for the ioc ack */
500 ATDISABLE(s, gref->lock);
501 while ((m = gref->ichead) == 0) {
502 gref->sevents |= POLLPRI;
503 #ifdef APPLETALK_DEBUG
504 kprintf("sleep gref = 0x%x\n", (unsigned)gref);
505 #endif
506 err = tsleep(&gref->iocevent, PSOCK | PCATCH, "AT ioctl", 0);
507 gref->sevents &= ~POLLPRI;
508 if (err != 0) {
509 ATENABLE(s, gref->lock);
510 #ifdef APPLETALK_DEBUG
511 kprintf("at_ioctl: EINTR\n");
512 #endif
513 return err;
514 }
515 }
516
517 /* PR-2224797 */
518 if (gbuf_next(m) == m) /* error case */
519 gbuf_next(m) = 0;
520
521 gref->ichead = gbuf_next(m);
522
523 ATENABLE(s, gref->lock);
524
525 #ifdef APPLETALK_DEBUG
526 kprintf("at_ioctl: woke up from ioc sleep gref = 0x%x\n",
527 (unsigned)gref);
528 #endif
529
530 /* process the ioc response */
531 ioc = (ioc_t *) gbuf_rptr(m);
532 if ((err = ioc->ioc_error) == 0) {
533 ioccmd.ic_timout = ioc->ioc_rval;
534 ioccmd.ic_len = 0;
535 mdata = gbuf_cont(m);
536 if (mdata && ioccmd.ic_dp) {
537 ioccmd.ic_len = gbuf_msgsize(mdata);
538 for (len = 0; mdata; mdata = gbuf_cont(mdata)) {
539 if (fromKernel)
540 bcopy (gbuf_rptr(mdata), &ioccmd.ic_dp[len], gbuf_len(mdata));
541 else {
542 if ((err = copyout((caddr_t)gbuf_rptr(mdata), (caddr_t)&ioccmd.ic_dp[len], gbuf_len(mdata))) < 0) {
543 #ifdef APPLETALK_DEBUG
544 kprintf("at_ioctl: len=%d error copyout=%d from=%x to=%x gbuf_len=%x\n",
545 len, err, (caddr_t)gbuf_rptr(mdata), (caddr_t)&ioccmd.ic_dp[len], gbuf_len(mdata));
546 #endif
547 goto l_done;
548 }
549 }
550 len += gbuf_len(mdata);
551 }
552 }
553
554 if (fromKernel)
555 bcopy (&ioccmd, arg, sizeof(ioccmd_t));
556 else {
557 if ((err = copyout((caddr_t)&ioccmd, (caddr_t)arg, sizeof(ioccmd_t))) != 0) {
558 #ifdef APPLETALK_DEBUG
559 kprintf("at_ioctl: error copyout2=%d from=%x to=%x len=%d\n",
560 err, &ioccmd, arg, sizeof(ioccmd_t));
561 #endif
562 goto l_done;
563 }
564 }
565 }
566
567 l_done:
568 gbuf_freem(m);
569 /*kprintf("at_ioctl: I_done=%d\n", err);*/
570 return err;
571 } /* at_ioctl */
572
573 int _ATioctl(fp, cmd, arg, proc)
574 void *fp;
575 u_long cmd;
576 register caddr_t arg;
577 void *proc;
578 {
579 int err;
580 gref_t *gref;
581
582 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
583 if ((err = atalk_getref(fp, 0, &gref, 0)) != 0) {
584 #ifdef APPLETALK_DEBUG
585 kprintf("_ATioctl: atalk_getref err = %d\n", err);
586 #endif
587 }
588 else
589 err = at_ioctl(gref, cmd, arg, 0);
590
591 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
592
593 return err;
594 }
595
596 int _ATselect(fp, which, wql, proc)
597 struct file *fp;
598 int which;
599 void * wql;
600 struct proc *proc;
601 {
602 int s, err, rc = 0;
603 gref_t *gref;
604
605 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
606 err = atalk_getref(fp, 0, &gref, 0);
607 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
608
609 if (err != 0)
610 rc = 1;
611 else {
612 ATDISABLE(s, gref->lock);
613 if (which == FREAD) {
614 if (gref->rdhead || (gref->readable && (*gref->readable)(gref)))
615 rc = 1;
616 else {
617 gref->sevents |= POLLIN;
618 selrecord(proc, &gref->si, wql);
619 }
620 }
621 else if (which == POLLOUT) {
622 if (gref->writeable) {
623 if ((*gref->writeable)(gref))
624 rc = 1;
625 else {
626 gref->sevents |= POLLOUT;
627 selrecord(proc, &gref->si, wql);
628 }
629 } else
630 rc = 1;
631 }
632 ATENABLE(s, gref->lock);
633 }
634
635 return rc;
636 }
637
638 void atalk_putnext(gref, m)
639 gref_t *gref;
640 gbuf_t *m;
641 {
642 int s;
643
644 ATDISABLE(s, gref->lock);
645
646 /* *** potential leak? *** */
647 gbuf_next(m) = 0;
648
649 switch (gbuf_type(m)) {
650 case MSG_IOCACK:
651 case MSG_IOCNAK:
652 if (gref->ichead)
653 gbuf_next(gref->ichead) = m;
654 else {
655 gref->ichead = m;
656 if (gref->sevents & POLLPRI) {
657 #ifdef APPLETALK_DEBUG
658 kprintf("wakeup gref = 0x%x\n", (unsigned)gref);
659 #endif
660 wakeup(&gref->iocevent);
661 }
662 }
663 break;
664 case MSG_ERROR:
665 /* *** this processing was moved to atalk_notify *** */
666 panic("atalk_putnext receved MSG_ERROR");
667 break;
668 default:
669 if (gref->errno)
670 gbuf_freem(m);
671 else
672 if (gref->rdhead) {
673 gbuf_next(gref->rdtail) = m;
674 gref->rdtail = m;
675 } else {
676 gref->rdhead = m;
677 if (gref->sevents & POLLMSG) {
678 gref->sevents &= ~POLLMSG;
679 wakeup(&gref->event);
680 }
681 if (gref->sevents & POLLIN) {
682 gref->sevents &= ~POLLIN;
683 selwakeup(&gref->si);
684 }
685 gref->rdtail = m;
686 }
687 } /* switch gbuf_type(m) */
688
689 ATENABLE(s, gref->lock);
690 } /* atalk_putnext */
691
692 void atalk_enablew(gref)
693 gref_t *gref;
694 {
695 if (gref->sevents & POLLSYNC)
696 wakeup(&gref->event);
697 }
698
699 void atalk_flush(gref)
700 gref_t *gref;
701 {
702 int s;
703
704 ATDISABLE(s, gref->lock);
705 if (gref->rdhead) {
706 gbuf_freel(gref->rdhead);
707 gref->rdhead = 0;
708 }
709 if (gref->ichead) {
710 gbuf_freel(gref->ichead);
711 gref->ichead = 0;
712 }
713 ATENABLE(s, gref->lock);
714 }
715
716 /*
717 * Notify an appletalk user of an asynchronous error;
718 * just wake up so that he can collect error status.
719 */
720 void atalk_notify(gref, errno)
721 register gref_t *gref;
722 int errno;
723 {
724 int s;
725 ATDISABLE(s, gref->lock);
726
727 if (gref->atpcb_socket) {
728 /* For DDP --
729 This section is patterned after udp_notify() in
730 netinet/udp_usrreq.c
731 */
732 gref->atpcb_socket->so_error = errno;
733 sorwakeup(gref->atpcb_socket);
734 sowwakeup(gref->atpcb_socket);
735 } else {
736 /* for ATP, ASP, and ADSP */
737 if (gref->errno == 0) {
738 gref->errno = errno;
739 /* clear out data waiting to be read */
740 if (gref->rdhead) {
741 gbuf_freel(gref->rdhead);
742 gref->rdhead = 0;
743 }
744 /* blocked read */
745 if (gref->sevents & POLLMSG) {
746 gref->sevents &= ~POLLMSG;
747 wakeup(&gref->event);
748 }
749 /* select */
750 if (gref->sevents & POLLIN) {
751 gref->sevents &= ~POLLIN;
752 selwakeup(&gref->si);
753 }
754 }
755 }
756 ATENABLE(s, gref->lock);
757 } /* atalk_notify */
758
759 void atalk_notify_sel(gref)
760 gref_t *gref;
761 {
762 int s;
763
764 ATDISABLE(s, gref->lock);
765 if (gref->sevents & POLLIN) {
766 gref->sevents &= ~POLLIN;
767 selwakeup(&gref->si);
768 }
769 ATENABLE(s, gref->lock);
770 }
771
772 int atalk_peek(gref, event)
773 gref_t *gref;
774 unsigned char *event;
775 {
776 int s, rc;
777
778 ATDISABLE(s, gref->lock);
779 if (gref->rdhead) {
780 *event = *gbuf_rptr(gref->rdhead);
781 rc = 0;
782 } else
783 rc = -1;
784 ATENABLE(s, gref->lock);
785
786 return rc;
787 }
788
789 static gbuf_t *trace_msg;
790
791 void atalk_settrace(str, p1, p2, p3, p4, p5)
792 char *str;
793 {
794 int len;
795 gbuf_t *m, *nextm;
796 char trace_buf[256];
797
798 sprintf(trace_buf, str, p1, p2, p3, p4, p5);
799 len = strlen(trace_buf);
800 #ifdef APPLETALK_DEBUG
801 kprintf("atalk_settrace: gbufalloc size=%d\n", len+1);
802 #endif
803 if ((m = gbuf_alloc(len+1, PRI_MED)) == 0)
804 return;
805 gbuf_wset(m,len);
806 strcpy(gbuf_rptr(m), trace_buf);
807 if (trace_msg) {
808 for (nextm=trace_msg; gbuf_cont(nextm); nextm=gbuf_cont(nextm)) ;
809 gbuf_cont(nextm) = m;
810 } else
811 trace_msg = m;
812 }
813
814 void atalk_gettrace(m)
815 gbuf_t *m;
816 {
817 if (trace_msg) {
818 gbuf_cont(m) = trace_msg;
819 trace_msg = 0;
820 }
821 }
822
823 #define GREF_PER_BLK 32
824 static gref_t *gref_free_list = 0;
825
826 int gref_alloc(grefp)
827 gref_t **grefp;
828 {
829 extern gbuf_t *atp_resource_m;
830 int i, s;
831 gbuf_t *m;
832 gref_t *gref, *gref_array;
833
834 *grefp = (gref_t *)NULL;
835
836 ATDISABLE(s, refall_lock);
837 if (gref_free_list == 0) {
838 ATENABLE(s, refall_lock);
839 #ifdef APPLETALK_DEBUG
840 kprintf("gref_alloc: gbufalloc size=%d\n", GREF_PER_BLK*sizeof(gref_t));
841 #endif
842 if ((m = gbuf_alloc(GREF_PER_BLK*sizeof(gref_t),PRI_HI)) == 0)
843 return ENOBUFS;
844 bzero(gbuf_rptr(m), GREF_PER_BLK*sizeof(gref_t));
845 gref_array = (gref_t *)gbuf_rptr(m);
846 for (i=0; i < GREF_PER_BLK-1; i++)
847 gref_array[i].atpcb_next = (gref_t *)&gref_array[i+1];
848 ATDISABLE(s, refall_lock);
849 gbuf_cont(m) = atp_resource_m;
850 atp_resource_m = m;
851 gref_array[i].atpcb_next = gref_free_list;
852 gref_free_list = (gref_t *)&gref_array[0];
853 }
854
855 gref = gref_free_list;
856 gref_free_list = gref->atpcb_next;
857 ATENABLE(s, refall_lock);
858 ATLOCKINIT(gref->lock);
859 //### LD Test 08/05/98
860 // simple_lock_init(&gref->lock);
861 ATEVENTINIT(gref->event);
862 ATEVENTINIT(gref->iocevent);
863
864 /* *** just for now *** */
865 gref->atpcb_socket = (struct socket *)NULL;
866
867 *grefp = gref;
868 return 0;
869 } /* gref_alloc */
870
871 /* bms: make gref_close callable from kernel */
872 int gref_close(gref_t *gref)
873 {
874 int s, rc;
875
876 switch (gref->proto) {
877
878 /* ATPROTO_DDP and ATPROTO_LAP have been replaced with
879 BSD-style socket interface. */
880
881 case ATPROTO_ATP:
882 rc = atp_close(gref, 1); break;
883 case ATPROTO_ASP:
884 rc = asp_close(gref); break;
885 #ifdef AURP_SUPPORT
886 case ATPROTO_AURP:
887 rc = aurp_close(gref); break;
888 break;
889 #endif
890 case ATPROTO_ADSP:
891 rc = adsp_close(gref); break;
892 default:
893 rc = 0;
894 break;
895 }
896
897 if (rc == 0) {
898 atalk_flush(gref);
899 selthreadclear(&gref->si);
900
901 /* from original gref_free() */
902 ATDISABLE(s, refall_lock);
903 bzero((char *)gref, sizeof(gref_t));
904 gref->atpcb_next = gref_free_list;
905 gref_free_list = gref;
906 ATENABLE(s, refall_lock);
907 }
908
909 return rc;
910 }
911 \f
912 /*
913 Buffer Routines
914
915 *** Some to be replaced with mbuf routines, some to be re-written
916 as mbuf routines (and moved to kern/uicp_mbuf.c or sys/mbuf.h?).
917 ***
918
919 */
920
921 /*
922 * LD 5/12/97 Added for MacOSX, defines a m_clattach function that:
923 * "Allocates an mbuf structure and attaches an external cluster."
924 */
925
926 struct mbuf *m_clattach(extbuf, extfree, extsize, extarg, wait)
927 caddr_t extbuf;
928 int (*extfree)();
929 int extsize;
930 int extarg;
931 int wait;
932 {
933 struct mbuf *m;
934
935 if ((m = m_gethdr(wait, MSG_DATA)) == NULL)
936 return (NULL);
937
938 m->m_ext.ext_buf = extbuf;
939 m->m_ext.ext_free = extfree;
940 m->m_ext.ext_size = extsize;
941 m->m_ext.ext_arg = extarg;
942 m->m_ext.ext_refs.forward =
943 m->m_ext.ext_refs.backward = &m->m_ext.ext_refs;
944 m->m_data = extbuf;
945 m->m_flags |= M_EXT;
946
947 return (m);
948 }
949
950
951
952 /*
953 temp fix for bug 2731148 - until this code is re-written to use standard clusters
954 Deletes any free clusters on the free list.
955 */
956 void atp_delete_free_clusters()
957 {
958 caddr_t cluster;
959 caddr_t cluster_list;
960
961
962 /* check for free clusters on the free_cluster_list to be deleted */
963 MBUF_LOCK(); /* lock used by mbuf routines */
964
965 untimeout(&atp_delete_free_clusters, NULL);
966 atp_free_cluster_timeout_set = 0;
967
968 cluster_list = atp_free_cluster_list;
969 atp_free_cluster_list = 0;
970
971 MBUF_UNLOCK();
972
973 while (cluster = cluster_list)
974 {
975 cluster_list = *((caddr_t*)cluster);
976 FREE(cluster, M_MCLUST);
977 }
978
979 }
980
981
982 /*
983 Used as the "free" routine for over-size clusters allocated using
984 m_lgbuf_alloc(). Called by m_free while under MBUF_LOCK.
985 */
986
987 void m_lgbuf_free(buf, size, arg)
988 void *buf;
989 int size, arg; /* not needed, but they're in m_free() */
990 {
991 /* FREE(buf, M_MCLUST); - can't free here - called from m_free while under lock */
992
993 /* move to free_cluster_list to be deleted later */
994 caddr_t cluster = (caddr_t)buf;
995
996 /* don't need a lock because this is only called called from m_free which */
997 /* is under MBUF_LOCK */
998 *((caddr_t*)cluster) = atp_free_cluster_list;
999 atp_free_cluster_list = cluster;
1000
1001 if (atp_free_cluster_timeout_set == 0)
1002 {
1003 atp_free_cluster_timeout_set = 1;
1004 timeout(&atp_delete_free_clusters, NULL, (1 * HZ));
1005 }
1006 }
1007
1008 /*
1009 Used to allocate an mbuf when there is the possibility that it may
1010 need to be larger than the size of a standard cluster.
1011 */
1012
1013 struct mbuf *m_lgbuf_alloc(size, wait)
1014 int size, wait;
1015 {
1016 struct mbuf *m;
1017
1018 if (atp_free_cluster_list)
1019 atp_delete_free_clusters(); /* delete any free clusters on the free list */
1020
1021 /* If size is too large, allocate a cluster, otherwise, use the
1022 standard mbuf allocation routines.*/
1023 if (size > MCLBYTES) {
1024 void *buf;
1025 if (NULL ==
1026 (buf = (void *)_MALLOC(size, M_MCLUST,
1027 (wait)? M_WAITOK: M_NOWAIT))) {
1028 return(NULL);
1029 }
1030 if (NULL ==
1031 (m = m_clattach(buf, m_lgbuf_free, size, 0,
1032 (wait)? M_WAIT: M_DONTWAIT))) {
1033 m_lgbuf_free(buf);
1034 return(NULL);
1035 }
1036 } else {
1037 m = m_gethdr(((wait)? M_WAIT: M_DONTWAIT), MSG_DATA);
1038 if (m && (size > MHLEN)) {
1039 MCLGET(m, ((wait)? M_WAIT: M_DONTWAIT));
1040 if (!(m->m_flags & M_EXT)) {
1041 (void)m_free(m);
1042 return(NULL);
1043 }
1044 }
1045 }
1046
1047 return(m);
1048 } /* m_lgbuf_alloc */
1049
1050 /*
1051 gbuf_alloc() is a wrapper for m_lgbuf_alloc(), which is used to
1052 allocate an mbuf when there is the possibility that it may need
1053 to be larger than the size of a standard cluster.
1054
1055 gbuf_alloc() sets the mbuf lengths, unlike the standard mbuf routines.
1056 */
1057
1058 gbuf_t *gbuf_alloc_wait(size, wait)
1059 int size, wait;
1060 {
1061 gbuf_t *m = (gbuf_t *)m_lgbuf_alloc(size, wait);
1062
1063 /* Standard mbuf allocation routines assume that the caller
1064 will set the size. */
1065 if (m) {
1066 (struct mbuf *)m->m_pkthdr.len = size;
1067 (struct mbuf *)m->m_len = size;
1068 }
1069
1070 return(m);
1071 }
1072
1073 int gbuf_msgsize(m)
1074 gbuf_t *m;
1075 {
1076 int size;
1077
1078 for (size=0; m; m=gbuf_cont(m))
1079 size += gbuf_len(m);
1080 return size;
1081 }
1082
1083 int append_copy(m1, m2, wait)
1084 struct mbuf *m1, *m2;
1085 int wait;
1086 {
1087 if ((!(m1->m_flags & M_EXT)) && (!(m2->m_flags & M_EXT)) &&
1088 (m_trailingspace(m1) >= m2->m_len)) {
1089 /* splat the data from one into the other */
1090 bcopy(mtod(m2, caddr_t), mtod(m1, caddr_t) + m1->m_len,
1091 (u_int)m2->m_len);
1092 m1->m_len += m2->m_len;
1093 if (m1->m_flags & M_PKTHDR)
1094 m1->m_pkthdr.len += m2->m_len;
1095 return 1;
1096 }
1097 if ((m1->m_next = m_copym(m2, 0, m2->m_len,
1098 (wait)? M_WAIT: M_DONTWAIT)) == NULL)
1099 return 0;
1100 return 1;
1101 } /* append_copy */
1102
1103 /*
1104 Copy an mbuf chain, referencing existing external storage, if any.
1105 Leave space for a header in the new chain, if the space has been
1106 left in the origin chain.
1107 */
1108 struct mbuf *copy_pkt(mlist, pad)
1109 struct mbuf *mlist; /* the mbuf chain to be copied */
1110 int pad; /* hint as to how long the header might be
1111 If pad is < 0, leave the same amount of space
1112 as there was in the original. */
1113 {
1114 struct mbuf *new_m;
1115 int len;
1116
1117 if (pad < 0)
1118 len = m_leadingspace(mlist);
1119 else
1120 len = min(pad, m_leadingspace(mlist));
1121
1122 /* preserve space for the header at the beginning of the mbuf */
1123 if (len) {
1124 mlist->m_data -= (len);
1125 mlist->m_len += (len);
1126 if (mlist->m_flags & M_PKTHDR)
1127 mlist->m_pkthdr.len += (len);
1128 new_m = m_copym(mlist, 0, M_COPYALL, M_DONTWAIT);
1129 m_adj(mlist, len);
1130 m_adj(new_m, len);
1131 } else
1132 new_m = m_copym(mlist, 0, M_COPYALL, M_DONTWAIT);
1133
1134 return(new_m);
1135 }
1136
1137 void gbuf_linkb(m1, m2)
1138 gbuf_t *m1;
1139 gbuf_t *m2;
1140 {
1141 while (gbuf_cont(m1) != 0)
1142 m1 = gbuf_cont(m1);
1143 gbuf_cont(m1) = m2;
1144 }
1145
1146 void gbuf_linkpkt(m1, m2)
1147 gbuf_t *m1;
1148 gbuf_t *m2;
1149 {
1150 while (gbuf_next(m1) != 0)
1151 m1 = gbuf_next(m1);
1152 gbuf_next(m1) = m2;
1153 }
1154
1155 int gbuf_freel(m)
1156 gbuf_t *m;
1157 {
1158 gbuf_t *tmp_m;
1159
1160 while ((tmp_m = m) != 0) {
1161 m = gbuf_next(m);
1162 gbuf_next(tmp_m) = 0;
1163 gbuf_freem(tmp_m);
1164 }
1165 return (0);
1166 }
1167
1168 /* free empty mbufs at the front of the chain */
1169 gbuf_t *gbuf_strip(m)
1170 gbuf_t *m;
1171 {
1172 gbuf_t *tmp_m;
1173
1174 while (m && gbuf_len(m) == 0) {
1175 tmp_m = m;
1176 m = gbuf_cont(m);
1177 gbuf_freeb(tmp_m);
1178 }
1179 return(m);
1180 }
1181 \f
1182 /**************************************/
1183
1184 int ddp_adjmsg(m, len)
1185 gbuf_t *m;
1186 int len;
1187 {
1188 int buf_len;
1189 gbuf_t *curr_m, *prev_m;
1190
1191 if (m == (gbuf_t *)0)
1192 return 0;
1193
1194 if (len > 0) {
1195 for (curr_m=m; curr_m;) {
1196 buf_len = gbuf_len(curr_m);
1197 if (len < buf_len) {
1198 gbuf_rinc(curr_m,len);
1199 return 1;
1200 }
1201 len -= buf_len;
1202 gbuf_rinc(curr_m,buf_len);
1203 if ((curr_m = gbuf_cont(curr_m)) == 0) {
1204 gbuf_freem(m);
1205 return 0;
1206 }
1207 }
1208
1209 } else if (len < 0) {
1210 len = -len;
1211 l_cont: prev_m = 0;
1212 for (curr_m=m; gbuf_cont(curr_m);
1213 prev_m=curr_m, curr_m=gbuf_cont(curr_m)) ;
1214 buf_len = gbuf_len(curr_m);
1215 if (len < buf_len) {
1216 gbuf_wdec(curr_m,len);
1217 return 1;
1218 }
1219 if (prev_m == 0)
1220 return 0;
1221 gbuf_cont(prev_m) = 0;
1222 gbuf_freeb(curr_m);
1223 len -= buf_len;
1224 goto l_cont;
1225
1226 } else
1227 return 1;
1228 }
1229
1230 /*
1231 * The message chain, m is grown in size by len contiguous bytes.
1232 * If len is non-negative, len bytes are added to the
1233 * end of the gbuf_t chain. If len is negative, the
1234 * bytes are added to the front. ddp_growmsg only adds bytes to
1235 * message blocks of the same type.
1236 * It returns a pointer to the new gbuf_t on sucess, 0 on failure.
1237 */
1238
1239 gbuf_t *ddp_growmsg(mp, len)
1240 gbuf_t *mp;
1241 int len;
1242 {
1243 gbuf_t *m, *d;
1244
1245 if ((m = mp) == (gbuf_t *) 0)
1246 return ((gbuf_t *) 0);
1247
1248 if (len <= 0) {
1249 len = -len;
1250 if ((d = gbuf_alloc(len, PRI_MED)) == 0)
1251 return ((gbuf_t *) 0);
1252 gbuf_set_type(d, gbuf_type(m));
1253 gbuf_wset(d,len);
1254 /* link in new gbuf_t */
1255 gbuf_cont(d) = m;
1256 return (d);
1257
1258 } else {
1259 register int count;
1260 /*
1261 * Add to tail.
1262 */
1263 if ((count = gbuf_msgsize(m)) < 0)
1264 return ((gbuf_t *) 0);
1265 /* find end of chain */
1266 for ( ; m; m = gbuf_cont(m)) {
1267 if (gbuf_len(m) >= count)
1268 break;
1269 count -= gbuf_len(m);
1270 }
1271 /* m now points to gbuf_t to add to */
1272 if ((d = gbuf_alloc(len, PRI_MED)) == 0)
1273 return ((gbuf_t *) 0);
1274 gbuf_set_type(d, gbuf_type(m));
1275 /* link in new gbuf_t */
1276 gbuf_cont(d) = gbuf_cont(m);
1277 gbuf_cont(m) = d;
1278 gbuf_wset(d,len);
1279 return (d);
1280 }
1281 }
1282
1283 /*
1284 * return the MSG_IOCACK/MSG_IOCNAK. Note that the same message
1285 * block is used as the vehicle, and that if there is an error return,
1286 * then linked blocks are lopped off. BEWARE of multiple references.
1287 * Used by other appletalk modules, so it is not static!
1288 */
1289
1290 void ioc_ack(errno, m, gref)
1291 int errno;
1292 register gbuf_t *m;
1293 register gref_t *gref;
1294 {
1295 ioc_t *iocbp = (ioc_t *)gbuf_rptr(m);
1296
1297 /*kprintf("ioc_ack: m=%x gref=%x errno=%d\n", m, gref, errno);*/
1298 if ((iocbp->ioc_error = errno) != 0)
1299 { /* errno != 0, then there is an error, get rid of linked blocks! */
1300
1301 if (gbuf_cont(m)) {
1302 gbuf_freem(gbuf_cont(m));
1303 gbuf_cont(m) = 0;
1304 }
1305 gbuf_set_type(m, MSG_IOCNAK);
1306 iocbp->ioc_count = 0; /* only make zero length if error */
1307 iocbp->ioc_rval = -1;
1308 } else
1309 gbuf_set_type(m, MSG_IOCACK);
1310
1311 atalk_putnext(gref, m);
1312 }
1313