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