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