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