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