|
|
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.