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