|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)uipc_socket2.c 7.15 (Berkeley) 6/28/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "user.h" ! 26: #include "proc.h" ! 27: #include "file.h" ! 28: #include "buf.h" ! 29: #include "malloc.h" ! 30: #include "mbuf.h" ! 31: #include "protosw.h" ! 32: #include "socket.h" ! 33: #include "socketvar.h" ! 34: ! 35: /* ! 36: * Primitive routines for operating on sockets and socket buffers ! 37: */ ! 38: ! 39: /* strings for sleep message: */ ! 40: char netio[] = "netio"; ! 41: char netcon[] = "netcon"; ! 42: char netcls[] = "netcls"; ! 43: ! 44: u_long sb_max = SB_MAX; /* patchable */ ! 45: ! 46: /* ! 47: * Procedures to manipulate state flags of socket ! 48: * and do appropriate wakeups. Normal sequence from the ! 49: * active (originating) side is that soisconnecting() is ! 50: * called during processing of connect() call, ! 51: * resulting in an eventual call to soisconnected() if/when the ! 52: * connection is established. When the connection is torn down ! 53: * soisdisconnecting() is called during processing of disconnect() call, ! 54: * and soisdisconnected() is called when the connection to the peer ! 55: * is totally severed. The semantics of these routines are such that ! 56: * connectionless protocols can call soisconnected() and soisdisconnected() ! 57: * only, bypassing the in-progress calls when setting up a ``connection'' ! 58: * takes no time. ! 59: * ! 60: * From the passive side, a socket is created with ! 61: * two queues of sockets: so_q0 for connections in progress ! 62: * and so_q for connections already made and awaiting user acceptance. ! 63: * As a protocol is preparing incoming connections, it creates a socket ! 64: * structure queued on so_q0 by calling sonewconn(). When the connection ! 65: * is established, soisconnected() is called, and transfers the ! 66: * socket structure to so_q, making it available to accept(). ! 67: * ! 68: * If a socket is closed with sockets on either ! 69: * so_q0 or so_q, these sockets are dropped. ! 70: * ! 71: * If higher level protocols are implemented in ! 72: * the kernel, the wakeups done here will sometimes ! 73: * cause software-interrupt process scheduling. ! 74: */ ! 75: ! 76: soisconnecting(so) ! 77: register struct socket *so; ! 78: { ! 79: ! 80: so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); ! 81: so->so_state |= SS_ISCONNECTING; ! 82: } ! 83: ! 84: soisconnected(so) ! 85: register struct socket *so; ! 86: { ! 87: register struct socket *head = so->so_head; ! 88: ! 89: so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); ! 90: so->so_state |= SS_ISCONNECTED; ! 91: if (head && soqremque(so, 0)) { ! 92: soqinsque(head, so, 1); ! 93: sorwakeup(head); ! 94: wakeup((caddr_t)&head->so_timeo); ! 95: } else { ! 96: wakeup((caddr_t)&so->so_timeo); ! 97: sorwakeup(so); ! 98: sowwakeup(so); ! 99: } ! 100: } ! 101: ! 102: soisdisconnecting(so) ! 103: register struct socket *so; ! 104: { ! 105: ! 106: so->so_state &= ~SS_ISCONNECTING; ! 107: so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); ! 108: wakeup((caddr_t)&so->so_timeo); ! 109: sowwakeup(so); ! 110: sorwakeup(so); ! 111: } ! 112: ! 113: soisdisconnected(so) ! 114: register struct socket *so; ! 115: { ! 116: ! 117: so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); ! 118: so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); ! 119: wakeup((caddr_t)&so->so_timeo); ! 120: sowwakeup(so); ! 121: sorwakeup(so); ! 122: } ! 123: ! 124: /* ! 125: * When an attempt at a new connection is noted on a socket ! 126: * which accepts connections, sonewconn is called. If the ! 127: * connection is possible (subject to space constraints, etc.) ! 128: * then we allocate a new structure, propoerly linked into the ! 129: * data structure of the original socket, and return this. ! 130: * Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED. ! 131: * ! 132: * Currently, sonewconn() is defined as sonewconn1() in socketvar.h ! 133: * to catch calls that are missing the (new) second parameter. ! 134: */ ! 135: struct socket * ! 136: sonewconn1(head, connstatus) ! 137: register struct socket *head; ! 138: int connstatus; ! 139: { ! 140: register struct socket *so; ! 141: int soqueue = connstatus ? 1 : 0; ! 142: ! 143: if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2) ! 144: return ((struct socket *)0); ! 145: MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_DONTWAIT); ! 146: if (so == NULL) ! 147: return ((struct socket *)0); ! 148: bzero((caddr_t)so, sizeof(*so)); ! 149: so->so_type = head->so_type; ! 150: so->so_options = head->so_options &~ SO_ACCEPTCONN; ! 151: so->so_linger = head->so_linger; ! 152: so->so_state = head->so_state | SS_NOFDREF; ! 153: so->so_proto = head->so_proto; ! 154: so->so_timeo = head->so_timeo; ! 155: so->so_pgid = head->so_pgid; ! 156: (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); ! 157: soqinsque(head, so, soqueue); ! 158: if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH, ! 159: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)) { ! 160: (void) soqremque(so, soqueue); ! 161: (void) free((caddr_t)so, M_SOCKET); ! 162: return ((struct socket *)0); ! 163: } ! 164: if (connstatus) { ! 165: sorwakeup(head); ! 166: wakeup((caddr_t)&head->so_timeo); ! 167: so->so_state |= connstatus; ! 168: } ! 169: return (so); ! 170: } ! 171: ! 172: soqinsque(head, so, q) ! 173: register struct socket *head, *so; ! 174: int q; ! 175: { ! 176: ! 177: register struct socket **prev; ! 178: so->so_head = head; ! 179: if (q == 0) { ! 180: head->so_q0len++; ! 181: so->so_q0 = 0; ! 182: for (prev = &(head->so_q0); *prev; ) ! 183: prev = &((*prev)->so_q0); ! 184: } else { ! 185: head->so_qlen++; ! 186: so->so_q = 0; ! 187: for (prev = &(head->so_q); *prev; ) ! 188: prev = &((*prev)->so_q); ! 189: } ! 190: *prev = so; ! 191: } ! 192: ! 193: soqremque(so, q) ! 194: register struct socket *so; ! 195: int q; ! 196: { ! 197: register struct socket *head, *prev, *next; ! 198: ! 199: head = so->so_head; ! 200: prev = head; ! 201: for (;;) { ! 202: next = q ? prev->so_q : prev->so_q0; ! 203: if (next == so) ! 204: break; ! 205: if (next == 0) ! 206: return (0); ! 207: prev = next; ! 208: } ! 209: if (q == 0) { ! 210: prev->so_q0 = next->so_q0; ! 211: head->so_q0len--; ! 212: } else { ! 213: prev->so_q = next->so_q; ! 214: head->so_qlen--; ! 215: } ! 216: next->so_q0 = next->so_q = 0; ! 217: next->so_head = 0; ! 218: return (1); ! 219: } ! 220: ! 221: /* ! 222: * Socantsendmore indicates that no more data will be sent on the ! 223: * socket; it would normally be applied to a socket when the user ! 224: * informs the system that no more data is to be sent, by the protocol ! 225: * code (in case PRU_SHUTDOWN). Socantrcvmore indicates that no more data ! 226: * will be received, and will normally be applied to the socket by a ! 227: * protocol when it detects that the peer will send no more data. ! 228: * Data queued for reading in the socket may yet be read. ! 229: */ ! 230: ! 231: socantsendmore(so) ! 232: struct socket *so; ! 233: { ! 234: ! 235: so->so_state |= SS_CANTSENDMORE; ! 236: sowwakeup(so); ! 237: } ! 238: ! 239: socantrcvmore(so) ! 240: struct socket *so; ! 241: { ! 242: ! 243: so->so_state |= SS_CANTRCVMORE; ! 244: sorwakeup(so); ! 245: } ! 246: ! 247: /* ! 248: * Socket select/wakeup routines. ! 249: */ ! 250: ! 251: /* ! 252: * Queue a process for a select on a socket buffer. ! 253: */ ! 254: sbselqueue(sb) ! 255: struct sockbuf *sb; ! 256: { ! 257: struct proc *p; ! 258: ! 259: if ((p = sb->sb_sel) && p->p_wchan == (caddr_t)&selwait) ! 260: sb->sb_flags |= SB_COLL; ! 261: else { ! 262: sb->sb_sel = u.u_procp; ! 263: sb->sb_flags |= SB_SEL; ! 264: } ! 265: } ! 266: ! 267: /* ! 268: * Wait for data to arrive at/drain from a socket buffer. ! 269: */ ! 270: sbwait(sb) ! 271: struct sockbuf *sb; ! 272: { ! 273: ! 274: sb->sb_flags |= SB_WAIT; ! 275: return (tsleep((caddr_t)&sb->sb_cc, ! 276: (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, netio, ! 277: sb->sb_timeo)); ! 278: } ! 279: ! 280: /* ! 281: * Lock a sockbuf already known to be locked; ! 282: * return any error returned from sleep (EINTR). ! 283: */ ! 284: sb_lock(sb) ! 285: register struct sockbuf *sb; ! 286: { ! 287: int error; ! 288: ! 289: while (sb->sb_flags & SB_LOCK) { ! 290: sb->sb_flags |= SB_WANT; ! 291: if (error = tsleep((caddr_t)&sb->sb_flags, ! 292: (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK|PCATCH, ! 293: netio, 0)) ! 294: return (error); ! 295: } ! 296: sb->sb_flags |= SB_LOCK; ! 297: return (0); ! 298: } ! 299: ! 300: /* ! 301: * Wakeup processes waiting on a socket buffer. ! 302: * Do asynchronous notification via SIGIO ! 303: * if the socket has the SS_ASYNC flag set. ! 304: */ ! 305: sowakeup(so, sb) ! 306: register struct socket *so; ! 307: register struct sockbuf *sb; ! 308: { ! 309: struct proc *p; ! 310: ! 311: if (sb->sb_sel) { ! 312: selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL); ! 313: sb->sb_sel = 0; ! 314: sb->sb_flags &= ~(SB_SEL|SB_COLL); ! 315: } ! 316: if (sb->sb_flags & SB_WAIT) { ! 317: sb->sb_flags &= ~SB_WAIT; ! 318: wakeup((caddr_t)&sb->sb_cc); ! 319: } ! 320: if (so->so_state & SS_ASYNC) { ! 321: if (so->so_pgid < 0) ! 322: gsignal(-so->so_pgid, SIGIO); ! 323: else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) ! 324: psignal(p, SIGIO); ! 325: } ! 326: } ! 327: ! 328: /* ! 329: * Socket buffer (struct sockbuf) utility routines. ! 330: * ! 331: * Each socket contains two socket buffers: one for sending data and ! 332: * one for receiving data. Each buffer contains a queue of mbufs, ! 333: * information about the number of mbufs and amount of data in the ! 334: * queue, and other fields allowing select() statements and notification ! 335: * on data availability to be implemented. ! 336: * ! 337: * Data stored in a socket buffer is maintained as a list of records. ! 338: * Each record is a list of mbufs chained together with the m_next ! 339: * field. Records are chained together with the m_nextpkt field. The upper ! 340: * level routine soreceive() expects the following conventions to be ! 341: * observed when placing information in the receive buffer: ! 342: * ! 343: * 1. If the protocol requires each message be preceded by the sender's ! 344: * name, then a record containing that name must be present before ! 345: * any associated data (mbuf's must be of type MT_SONAME). ! 346: * 2. If the protocol supports the exchange of ``access rights'' (really ! 347: * just additional data associated with the message), and there are ! 348: * ``rights'' to be received, then a record containing this data ! 349: * should be present (mbuf's must be of type MT_RIGHTS). ! 350: * 3. If a name or rights record exists, then it must be followed by ! 351: * a data record, perhaps of zero length. ! 352: * ! 353: * Before using a new socket structure it is first necessary to reserve ! 354: * buffer space to the socket, by calling sbreserve(). This should commit ! 355: * some of the available buffer space in the system buffer pool for the ! 356: * socket (currently, it does nothing but enforce limits). The space ! 357: * should be released by calling sbrelease() when the socket is destroyed. ! 358: */ ! 359: ! 360: soreserve(so, sndcc, rcvcc) ! 361: register struct socket *so; ! 362: u_long sndcc, rcvcc; ! 363: { ! 364: ! 365: if (sbreserve(&so->so_snd, sndcc) == 0) ! 366: goto bad; ! 367: if (sbreserve(&so->so_rcv, rcvcc) == 0) ! 368: goto bad2; ! 369: if (so->so_rcv.sb_lowat == 0) ! 370: so->so_rcv.sb_lowat = 1; ! 371: if (so->so_snd.sb_lowat == 0) ! 372: so->so_snd.sb_lowat = MCLBYTES; ! 373: if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat) ! 374: so->so_snd.sb_lowat = so->so_snd.sb_hiwat; ! 375: return (0); ! 376: bad2: ! 377: sbrelease(&so->so_snd); ! 378: bad: ! 379: return (ENOBUFS); ! 380: } ! 381: ! 382: /* ! 383: * Allot mbufs to a sockbuf. ! 384: * Attempt to scale mbmax so that mbcnt doesn't become limiting ! 385: * if buffering efficiency is near the normal case. ! 386: */ ! 387: sbreserve(sb, cc) ! 388: struct sockbuf *sb; ! 389: u_long cc; ! 390: { ! 391: ! 392: if (cc > sb_max * MCLBYTES / (MSIZE + MCLBYTES)) ! 393: return (0); ! 394: sb->sb_hiwat = cc; ! 395: sb->sb_mbmax = min(cc * 2, sb_max); ! 396: if (sb->sb_lowat > sb->sb_hiwat) ! 397: sb->sb_lowat = sb->sb_hiwat; ! 398: return (1); ! 399: } ! 400: ! 401: /* ! 402: * Free mbufs held by a socket, and reserved mbuf space. ! 403: */ ! 404: sbrelease(sb) ! 405: struct sockbuf *sb; ! 406: { ! 407: ! 408: sbflush(sb); ! 409: sb->sb_hiwat = sb->sb_mbmax = 0; ! 410: } ! 411: ! 412: /* ! 413: * Routines to add and remove ! 414: * data from an mbuf queue. ! 415: * ! 416: * The routines sbappend() or sbappendrecord() are normally called to ! 417: * append new mbufs to a socket buffer, after checking that adequate ! 418: * space is available, comparing the function sbspace() with the amount ! 419: * of data to be added. sbappendrecord() differs from sbappend() in ! 420: * that data supplied is treated as the beginning of a new record. ! 421: * To place a sender's address, optional access rights, and data in a ! 422: * socket receive buffer, sbappendaddr() should be used. To place ! 423: * access rights and data in a socket receive buffer, sbappendrights() ! 424: * should be used. In either case, the new data begins a new record. ! 425: * Note that unlike sbappend() and sbappendrecord(), these routines check ! 426: * for the caller that there will be enough space to store the data. ! 427: * Each fails if there is not enough space, or if it cannot find mbufs ! 428: * to store additional information in. ! 429: * ! 430: * Reliable protocols may use the socket send buffer to hold data ! 431: * awaiting acknowledgement. Data is normally copied from a socket ! 432: * send buffer in a protocol with m_copy for output to a peer, ! 433: * and then removing the data from the socket buffer with sbdrop() ! 434: * or sbdroprecord() when the data is acknowledged by the peer. ! 435: */ ! 436: ! 437: /* ! 438: * Append mbuf chain m to the last record in the ! 439: * socket buffer sb. The additional space associated ! 440: * the mbuf chain is recorded in sb. Empty mbufs are ! 441: * discarded and mbufs are compacted where possible. ! 442: */ ! 443: sbappend(sb, m) ! 444: struct sockbuf *sb; ! 445: struct mbuf *m; ! 446: { ! 447: register struct mbuf *n; ! 448: ! 449: if (m == 0) ! 450: return; ! 451: if (n = sb->sb_mb) { ! 452: while (n->m_nextpkt) ! 453: n = n->m_nextpkt; ! 454: while (n->m_next) ! 455: if (n->m_flags & M_EOR) { ! 456: sbappendrecord(sb, m); /* XXXXXX!!!! */ ! 457: return; ! 458: } else ! 459: n = n->m_next; ! 460: } ! 461: sbcompress(sb, m, n); ! 462: } ! 463: ! 464: #ifdef SOCKBUF_DEBUG ! 465: sbcheck(sb) ! 466: register struct sockbuf *sb; ! 467: { ! 468: register struct mbuf *m; ! 469: register int len = 0, mbcnt = 0; ! 470: ! 471: for (m = sb->sb_mb; m; m = m->m_next) { ! 472: len += m->m_len; ! 473: mbcnt += MSIZE; ! 474: if (m->m_flags & M_EXT) ! 475: mbcnt += m->m_ext.ext_size; ! 476: if (m->m_nextpkt) ! 477: panic("sbcheck nextpkt"); ! 478: } ! 479: if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { ! 480: printf("cc %d != %d || mbcnt %d != %d\n", len, sb->sb_cc, ! 481: mbcnt, sb->sb_mbcnt); ! 482: panic("sbcheck"); ! 483: } ! 484: } ! 485: #endif ! 486: ! 487: /* ! 488: * As above, except the mbuf chain ! 489: * begins a new record. ! 490: */ ! 491: sbappendrecord(sb, m0) ! 492: register struct sockbuf *sb; ! 493: register struct mbuf *m0; ! 494: { ! 495: register struct mbuf *m; ! 496: ! 497: if (m0 == 0) ! 498: return; ! 499: if (m = sb->sb_mb) ! 500: while (m->m_nextpkt) ! 501: m = m->m_nextpkt; ! 502: /* ! 503: * Put the first mbuf on the queue. ! 504: * Note this permits zero length records. ! 505: */ ! 506: sballoc(sb, m0); ! 507: if (m) ! 508: m->m_nextpkt = m0; ! 509: else ! 510: sb->sb_mb = m0; ! 511: m = m0->m_next; ! 512: m0->m_next = 0; ! 513: if (m && (m0->m_flags & M_EOR)) { ! 514: m0->m_flags &= ~M_EOR; ! 515: m->m_flags |= M_EOR; ! 516: } ! 517: sbcompress(sb, m, m0); ! 518: } ! 519: ! 520: /* ! 521: * As above except that OOB data ! 522: * is inserted at the beginning of the sockbuf, ! 523: * but after any other OOB data. ! 524: */ ! 525: sbinsertoob(sb, m0) ! 526: register struct sockbuf *sb; ! 527: register struct mbuf *m0; ! 528: { ! 529: register struct mbuf *m; ! 530: register struct mbuf **mp; ! 531: ! 532: if (m0 == 0) ! 533: return; ! 534: for (mp = &sb->sb_mb; m = *mp; mp = &((*mp)->m_nextpkt)) { ! 535: again: ! 536: switch (m->m_type) { ! 537: ! 538: case MT_OOBDATA: ! 539: continue; /* WANT next train */ ! 540: ! 541: case MT_CONTROL: ! 542: if (m = m->m_next) ! 543: goto again; /* inspect THIS train further */ ! 544: } ! 545: break; ! 546: } ! 547: /* ! 548: * Put the first mbuf on the queue. ! 549: * Note this permits zero length records. ! 550: */ ! 551: sballoc(sb, m0); ! 552: m0->m_nextpkt = *mp; ! 553: *mp = m0; ! 554: m = m0->m_next; ! 555: m0->m_next = 0; ! 556: if (m && (m0->m_flags & M_EOR)) { ! 557: m0->m_flags &= ~M_EOR; ! 558: m->m_flags |= M_EOR; ! 559: } ! 560: sbcompress(sb, m, m0); ! 561: } ! 562: ! 563: /* ! 564: * Append address and data, and optionally, control (ancillary) data ! 565: * to the receive queue of a socket. If present, ! 566: * m0 must include a packet header with total length. ! 567: * Returns 0 if no space in sockbuf or insufficient mbufs. ! 568: */ ! 569: sbappendaddr(sb, asa, m0, control) ! 570: register struct sockbuf *sb; ! 571: struct sockaddr *asa; ! 572: struct mbuf *m0, *control; ! 573: { ! 574: register struct mbuf *m, *n; ! 575: int space = asa->sa_len; ! 576: ! 577: if (m0 && (m0->m_flags & M_PKTHDR) == 0) ! 578: panic("sbappendaddr"); ! 579: if (m0) ! 580: space += m0->m_pkthdr.len; ! 581: for (n = control; n; n = n->m_next) { ! 582: space += n->m_len; ! 583: if (n->m_next == 0) /* keep pointer to last control buf */ ! 584: break; ! 585: } ! 586: if (space > sbspace(sb)) ! 587: return (0); ! 588: if (asa->sa_len > MLEN) ! 589: return (0); ! 590: MGET(m, M_DONTWAIT, MT_SONAME); ! 591: if (m == 0) ! 592: return (0); ! 593: m->m_len = asa->sa_len; ! 594: bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len); ! 595: if (n) ! 596: n->m_next = m0; /* concatenate data to control */ ! 597: else ! 598: control = m0; ! 599: m->m_next = control; ! 600: for (n = m; n; n = n->m_next) ! 601: sballoc(sb, n); ! 602: if (n = sb->sb_mb) { ! 603: while (n->m_nextpkt) ! 604: n = n->m_nextpkt; ! 605: n->m_nextpkt = m; ! 606: } else ! 607: sb->sb_mb = m; ! 608: return (1); ! 609: } ! 610: ! 611: sbappendcontrol(sb, m0, control) ! 612: struct sockbuf *sb; ! 613: struct mbuf *control, *m0; ! 614: { ! 615: register struct mbuf *m, *n; ! 616: int space = 0; ! 617: ! 618: if (control == 0) ! 619: panic("sbappendcontrol"); ! 620: for (m = control; ; m = m->m_next) { ! 621: space += m->m_len; ! 622: if (m->m_next == 0) ! 623: break; ! 624: } ! 625: n = m; /* save pointer to last control buffer */ ! 626: for (m = m0; m; m = m->m_next) ! 627: space += m->m_len; ! 628: if (space > sbspace(sb)) ! 629: return (0); ! 630: n->m_next = m0; /* concatenate data to control */ ! 631: for (m = control; m; m = m->m_next) ! 632: sballoc(sb, m); ! 633: if (n = sb->sb_mb) { ! 634: while (n->m_nextpkt) ! 635: n = n->m_nextpkt; ! 636: n->m_nextpkt = control; ! 637: } else ! 638: sb->sb_mb = control; ! 639: return (1); ! 640: } ! 641: ! 642: /* ! 643: * Compress mbuf chain m into the socket ! 644: * buffer sb following mbuf n. If n ! 645: * is null, the buffer is presumed empty. ! 646: */ ! 647: sbcompress(sb, m, n) ! 648: register struct sockbuf *sb; ! 649: register struct mbuf *m, *n; ! 650: { ! 651: register int eor = 0; ! 652: ! 653: while (m) { ! 654: eor |= m->m_flags & M_EOR; ! 655: if (m->m_len == 0) { ! 656: m = m_free(m); ! 657: continue; ! 658: } ! 659: if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 && ! 660: (n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] && ! 661: n->m_type == m->m_type) { ! 662: bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len, ! 663: (unsigned)m->m_len); ! 664: n->m_len += m->m_len; ! 665: sb->sb_cc += m->m_len; ! 666: m = m_free(m); ! 667: continue; ! 668: } ! 669: if (n) ! 670: n->m_next = m; ! 671: else ! 672: sb->sb_mb = m; ! 673: sballoc(sb, m); ! 674: n = m; ! 675: m->m_flags &= ~M_EOR; ! 676: m = m->m_next; ! 677: n->m_next = 0; ! 678: } ! 679: if (n) ! 680: n->m_flags |= eor; ! 681: } ! 682: ! 683: /* ! 684: * Free all mbufs in a sockbuf. ! 685: * Check that all resources are reclaimed. ! 686: */ ! 687: sbflush(sb) ! 688: register struct sockbuf *sb; ! 689: { ! 690: ! 691: if (sb->sb_flags & SB_LOCK) ! 692: panic("sbflush"); ! 693: while (sb->sb_mbcnt) ! 694: sbdrop(sb, (int)sb->sb_cc); ! 695: if (sb->sb_cc || sb->sb_mb) ! 696: panic("sbflush 2"); ! 697: } ! 698: ! 699: /* ! 700: * Drop data from (the front of) a sockbuf. ! 701: */ ! 702: sbdrop(sb, len) ! 703: register struct sockbuf *sb; ! 704: register int len; ! 705: { ! 706: register struct mbuf *m, *mn; ! 707: struct mbuf *next; ! 708: ! 709: next = (m = sb->sb_mb) ? m->m_nextpkt : 0; ! 710: while (len > 0) { ! 711: if (m == 0) { ! 712: if (next == 0) ! 713: panic("sbdrop"); ! 714: m = next; ! 715: next = m->m_nextpkt; ! 716: continue; ! 717: } ! 718: if (m->m_len > len) { ! 719: m->m_len -= len; ! 720: m->m_data += len; ! 721: sb->sb_cc -= len; ! 722: break; ! 723: } ! 724: len -= m->m_len; ! 725: sbfree(sb, m); ! 726: MFREE(m, mn); ! 727: m = mn; ! 728: } ! 729: while (m && m->m_len == 0) { ! 730: sbfree(sb, m); ! 731: MFREE(m, mn); ! 732: m = mn; ! 733: } ! 734: if (m) { ! 735: sb->sb_mb = m; ! 736: m->m_nextpkt = next; ! 737: } else ! 738: sb->sb_mb = next; ! 739: } ! 740: ! 741: /* ! 742: * Drop a record off the front of a sockbuf ! 743: * and move the next record to the front. ! 744: */ ! 745: sbdroprecord(sb) ! 746: register struct sockbuf *sb; ! 747: { ! 748: register struct mbuf *m, *mn; ! 749: ! 750: m = sb->sb_mb; ! 751: if (m) { ! 752: sb->sb_mb = m->m_nextpkt; ! 753: do { ! 754: sbfree(sb, m); ! 755: MFREE(m, mn); ! 756: } while (m = mn); ! 757: } ! 758: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.