Beispiel #1
0
static void
l2cap_complete(void *arg, int count)
{
	struct socket *so = arg;

	while (count-- > 0)
		sbdroprecord(&so->so_snd);

	sowwakeup(so);
}
Beispiel #2
0
static void
sco_complete(void *arg, int num)
{
	struct socket *so = arg;

	while (num-- > 0)
		sbdroprecord(&so->so_snd);

	sowwakeup(so);
}
Beispiel #3
0
static void
sco_input(void *arg, struct mbuf *m)
{
	struct socket *so = arg;

	/*
	 * since this data is time sensitive, if the buffer
	 * is full we just dump data until the latest one
	 * will fit.
	 */

	while (m->m_pkthdr.len > sbspace(&so->so_rcv))
		sbdroprecord(&so->so_rcv);

	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);

	sbappendrecord(&so->so_rcv, m);
	sorwakeup(so);
}
Beispiel #4
0
int
soreceive(struct socket * so, 
   struct mbuf **aname,
   char * data,
   int * datalen,
   int   flags)
{
   struct mbuf *  m;
   int   len;
   int   error =  0;
   int   offset;
   struct protosw *  pr =  so->so_proto;
   struct mbuf *  nextrecord;
   int   moff;
   int   lflags;

   if (aname)
      *aname = 0;
   if (flags & MSG_OOB) 
   {
      m = m_get (M_WAIT, MT_RXDATA);
      if (m == NULL)
         return ENOBUFS;
      lflags = flags & MSG_PEEK;

      so->so_req = PRU_RCVOOB;
      error = (*pr->pr_usrreq)(so, m, LONG2MBUF((long)lflags));
      if (error == 0)
      {
         do 
         {
            len = *datalen;
            if (len > (int)m->m_len)
               len = m->m_len;

            MEMCPY(data, mtod(m, char*), len);
            data += len;
            *datalen = len;
            m = m_free(m);
         } while (*datalen && (error == 0) && m);
      }

      if (m)
         m_freem(m);
      return (error);
   }

restart:
   sblock (&so->so_rcv);
   INET_TRACE (INETM_IO,
    ("INET:soreceive sbcc %d soerror %d so_state %d *datalen %d\n",
    so->so_rcv.sb_cc, so->so_error, so->so_state, *datalen));

   /* If no data is ready, see if we should wait or return */
   if (so->so_rcv.sb_cc == 0) 
   {
      if (so->so_error) 
      {
         error = so->so_error;
         so->so_error = 0;
         goto release;
      }
      if (so->so_state & SS_CANTRCVMORE)
         goto release;
      if ((so->so_state & SS_ISCONNECTED) == 0 &&
          (so->so_proto->pr_flags & PR_CONNREQUIRED)) 
      {
         error = ENOTCONN;
         goto release;
      }
      if (*datalen == 0)
         goto release;
      if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) 
      {
         error = EWOULDBLOCK;
         goto release;
      }
      sbunlock(&so->so_rcv);
      sbwait(&so->so_rcv);
      goto restart;
   }
   m = so->so_rcv.sb_mb;
   if (m == 0)
      panic("sorecv 1");
   nextrecord = m->m_act;
   if (pr->pr_flags & PR_ADDR) 
   {
      if (m->m_type != MT_SONAME) 
      {
         dprintf ("sorecv:type %d not nam", m->m_type);
         panic("sorecv 2");
      }
      if (flags & MSG_PEEK) 
      {
         if (aname)
            *aname = m_copy (m, 0, m->m_len);
         m = m->m_next;
      } else 
      {
         sbfree (&so->so_rcv, m);
         if (aname) 
         {
            *aname = m;
            m = m->m_next;
            (*aname)->m_next = 0;
            so->so_rcv.sb_mb = m;
         } else 
         {
            MFREE(m, so->so_rcv.sb_mb);
            m = so->so_rcv.sb_mb;
         }
         if (m)
            m->m_act = nextrecord;
      }
   }
   moff = 0;
   offset = 0;
   while (m && (*datalen > 0) && (error == 0))
   {
      if (m->m_type != MT_RXDATA && m->m_type != MT_HEADER)
         panic("sorecv 3");
      len = *datalen;
      so->so_state &= ~SS_RCVATMARK;
      if (so->so_oobmark && (len > (int)(so->so_oobmark - offset)))
         len = (int)(so->so_oobmark - offset);
      if (len > (int)(m->m_len - moff))
         len = m->m_len - moff;

      INET_TRACE (INETM_IO, ("INET: soreceive, so %lx %d bytes, flags %x\n",
                  so, len, flags));

      /*
       * Copy mbufs info user buffer, then free them.
       * Sockbuf must be consistent here (points to current mbuf,
       * it points to next record) when we drop priority;
       * we must note any additions to the sockbuf when we
       * block interrupts again.
       */

      MEMCPY(data, (mtod(m, char *) + moff), len);
      data += len;
      *datalen -= len;

      if (len == (int)(m->m_len - moff))
      {
         if (flags & MSG_PEEK) 
         {
            m = m->m_next;
            moff = 0;
         } else 
         {
            nextrecord = m->m_act;
            sbfree(&so->so_rcv, m);
            {
               MFREE(m, so->so_rcv.sb_mb);
               m = so->so_rcv.sb_mb;
            }
            if (m)
               m->m_act = nextrecord;
         }
      } else 
      {
         if (flags & MSG_PEEK)
            moff += len;
         else 
         {
            m->m_data += len;
            m->m_len -= len;
            so->so_rcv.sb_cc -= len;
         }
      }
      if (so->so_oobmark) 
      {
         if ((flags & MSG_PEEK) == 0) 
         {
            so->so_oobmark -= len;
            if (so->so_oobmark == 0) 
            {
               so->so_state |= SS_RCVATMARK;
               break;
            }
         } else
            offset += len;
      }
   }

   if ((flags & MSG_PEEK) == 0) 
   {
      if (m == 0)
         so->so_rcv.sb_mb = nextrecord;
      else if (pr->pr_flags & PR_ATOMIC)
         (void) sbdroprecord(&so->so_rcv);
      if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
      {
         so->so_req = PRU_RCVD;
         (*pr->pr_usrreq)(so, (struct mbuf *)0,
          (struct mbuf *)0);
      }
   }
release:
   sbunlock(&so->so_rcv);
   return (error);
}
Beispiel #5
0
static int
kttcp_soreceive(struct socket *so, unsigned long long slen,
    unsigned long long *done, struct lwp *l, int *flagsp)
{
	struct mbuf *m, **mp;
	int flags, len, error, offset, moff, type;
	long long orig_resid, resid;
	const struct protosw *pr;
	struct mbuf *nextrecord;

	pr = so->so_proto;
	mp = NULL;
	type = 0;
	resid = orig_resid = slen;
	if (flagsp)
		flags = *flagsp &~ MSG_EOR;
	else
 		flags = 0;
	if (flags & MSG_OOB) {
		m = m_get(M_WAIT, MT_DATA);
		solock(so);
		error = (*pr->pr_usrreqs->pr_recvoob)(so, m, flags & MSG_PEEK);
		sounlock(so);
		if (error)
			goto bad;
		do {
			resid -= min(resid, m->m_len);
			m = m_free(m);
		} while (resid && error == 0 && m);
 bad:
		if (m)
			m_freem(m);
		return (error);
	}
	if (mp)
		*mp = NULL;
	solock(so);
 restart:
	if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0)
		return (error);
	m = so->so_rcv.sb_mb;
	/*
	 * If we have less data than requested, block awaiting more
	 * (subject to any timeout) if:
	 *   1. the current count is less than the low water mark,
	 *   2. MSG_WAITALL is set, and it is possible to do the entire
	 *	receive operation at once if we block (resid <= hiwat), or
	 *   3. MSG_DONTWAIT is not set.
	 * If MSG_WAITALL is set but resid is larger than the receive buffer,
	 * we have to do the receive in sections, and thus risk returning
	 * a short count if a timeout or signal occurs after we start.
	 */
	if (m == NULL || (((flags & MSG_DONTWAIT) == 0 &&
	    so->so_rcv.sb_cc < resid) &&
	    (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
	    ((flags & MSG_WAITALL) && resid <= so->so_rcv.sb_hiwat)) &&
	    m->m_nextpkt == NULL && (pr->pr_flags & PR_ATOMIC) == 0)) {
#ifdef DIAGNOSTIC
		if (m == NULL && so->so_rcv.sb_cc)
			panic("receive 1");
#endif
		if (so->so_error) {
			if (m)
				goto dontblock;
			error = so->so_error;
			if ((flags & MSG_PEEK) == 0)
				so->so_error = 0;
			goto release;
		}
		if (so->so_state & SS_CANTRCVMORE) {
			if (m)
				goto dontblock;
			else
				goto release;
		}
		for (; m; m = m->m_next)
			if (m->m_type == MT_OOBDATA  || (m->m_flags & M_EOR)) {
				m = so->so_rcv.sb_mb;
				goto dontblock;
			}
		if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
		    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
			error = ENOTCONN;
			goto release;
		}
		if (resid == 0)
			goto release;
		if ((so->so_state & SS_NBIO) ||
		    (flags & (MSG_DONTWAIT|MSG_NBIO))) {
			error = EWOULDBLOCK;
			goto release;
		}
		sbunlock(&so->so_rcv);
		error = sbwait(&so->so_rcv);
		if (error) {
			sounlock(so);
			return (error);
		}
		goto restart;
	}
 dontblock:
	/*
	 * On entry here, m points to the first record of the socket buffer.
	 * While we process the initial mbufs containing address and control
	 * info, we save a copy of m->m_nextpkt into nextrecord.
	 */
#ifdef notyet /* XXXX */
	if (uio->uio_lwp)
		uio->uio_lwp->l_ru.ru_msgrcv++;
#endif
	KASSERT(m == so->so_rcv.sb_mb);
	SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 1");
	SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 1");
	nextrecord = m->m_nextpkt;
	if (pr->pr_flags & PR_ADDR) {
#ifdef DIAGNOSTIC
		if (m->m_type != MT_SONAME)
			panic("receive 1a");
#endif
		orig_resid = 0;
		if (flags & MSG_PEEK) {
			m = m->m_next;
		} else {
			sbfree(&so->so_rcv, m);
			MFREE(m, so->so_rcv.sb_mb);
			m = so->so_rcv.sb_mb;
		}
	}
	while (m && m->m_type == MT_CONTROL && error == 0) {
		if (flags & MSG_PEEK) {
			m = m->m_next;
		} else {
			sbfree(&so->so_rcv, m);
			MFREE(m, so->so_rcv.sb_mb);
			m = so->so_rcv.sb_mb;
		}
	}

	/*
	 * If m is non-NULL, we have some data to read.  From now on,
	 * make sure to keep sb_lastrecord consistent when working on
	 * the last packet on the chain (nextrecord == NULL) and we
	 * change m->m_nextpkt.
	 */
	if (m) {
		if ((flags & MSG_PEEK) == 0) {
			m->m_nextpkt = nextrecord;
			/*
			 * If nextrecord == NULL (this is a single chain),
			 * then sb_lastrecord may not be valid here if m
			 * was changed earlier.
			 */
			if (nextrecord == NULL) {
				KASSERT(so->so_rcv.sb_mb == m);
				so->so_rcv.sb_lastrecord = m;
			}
		}
		type = m->m_type;
		if (type == MT_OOBDATA)
			flags |= MSG_OOB;
	} else {
		if ((flags & MSG_PEEK) == 0) {
			KASSERT(so->so_rcv.sb_mb == m);
			so->so_rcv.sb_mb = nextrecord;
			SB_EMPTY_FIXUP(&so->so_rcv);
		}
	}
	SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 2");
	SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 2");

	moff = 0;
	offset = 0;
	while (m && resid > 0 && error == 0) {
		if (m->m_type == MT_OOBDATA) {
			if (type != MT_OOBDATA)
				break;
		} else if (type == MT_OOBDATA)
			break;
#ifdef DIAGNOSTIC
		else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
			panic("receive 3");
#endif
		so->so_state &= ~SS_RCVATMARK;
		len = resid;
		if (so->so_oobmark && len > so->so_oobmark - offset)
			len = so->so_oobmark - offset;
		if (len > m->m_len - moff)
			len = m->m_len - moff;
		/*
		 * If mp is set, just pass back the mbufs.
		 * Otherwise copy them out via the uio, then free.
		 * Sockbuf must be consistent here (points to current mbuf,
		 * it points to next record) when we drop priority;
		 * we must note any additions to the sockbuf when we
		 * block interrupts again.
		 */
		resid -= len;
		if (len == m->m_len - moff) {
			if (m->m_flags & M_EOR)
				flags |= MSG_EOR;
			if (flags & MSG_PEEK) {
				m = m->m_next;
				moff = 0;
			} else {
				nextrecord = m->m_nextpkt;
				sbfree(&so->so_rcv, m);
				if (mp) {
					*mp = m;
					mp = &m->m_next;
					so->so_rcv.sb_mb = m = m->m_next;
					*mp = NULL;
				} else {
					MFREE(m, so->so_rcv.sb_mb);
					m = so->so_rcv.sb_mb;
				}
				/*
				 * If m != NULL, we also know that
				 * so->so_rcv.sb_mb != NULL.
				 */
				KASSERT(so->so_rcv.sb_mb == m);
				if (m) {
					m->m_nextpkt = nextrecord;
					if (nextrecord == NULL)
						so->so_rcv.sb_lastrecord = m;
				} else {
					so->so_rcv.sb_mb = nextrecord;
					SB_EMPTY_FIXUP(&so->so_rcv);
				}
				SBLASTRECORDCHK(&so->so_rcv,
				    "kttcp_soreceive 3");
				SBLASTMBUFCHK(&so->so_rcv,
				    "kttcp_soreceive 3");
			}
		} else {
			if (flags & MSG_PEEK)
				moff += len;
			else {
				if (mp) {
					sounlock(so);
					*mp = m_copym(m, 0, len, M_WAIT);
					solock(so);
				}
				m->m_data += len;
				m->m_len -= len;
				so->so_rcv.sb_cc -= len;
			}
		}
		if (so->so_oobmark) {
			if ((flags & MSG_PEEK) == 0) {
				so->so_oobmark -= len;
				if (so->so_oobmark == 0) {
					so->so_state |= SS_RCVATMARK;
					break;
				}
			} else {
				offset += len;
				if (offset == so->so_oobmark)
					break;
			}
		}
		if (flags & MSG_EOR)
			break;
		/*
		 * If the MSG_WAITALL flag is set (for non-atomic socket),
		 * we must not quit until "uio->uio_resid == 0" or an error
		 * termination.  If a signal/timeout occurs, return
		 * with a short count but without error.
		 * Keep sockbuf locked against other readers.
		 */
		while (flags & MSG_WAITALL && m == NULL && resid > 0 &&
		    !sosendallatonce(so) && !nextrecord) {
			if (so->so_error || so->so_state & SS_CANTRCVMORE)
				break;
			/*
			 * If we are peeking and the socket receive buffer is
			 * full, stop since we can't get more data to peek at.
			 */
			if ((flags & MSG_PEEK) && sbspace(&so->so_rcv) <= 0)
				break;
			/*
			 * If we've drained the socket buffer, tell the
			 * protocol in case it needs to do something to
			 * get it filled again.
			 */
			if ((pr->pr_flags & PR_WANTRCVD) && so->so_pcb) {
				(*pr->pr_usrreqs->pr_rcvd)(so, flags, l);
			}
			SBLASTRECORDCHK(&so->so_rcv,
			    "kttcp_soreceive sbwait 2");
			SBLASTMBUFCHK(&so->so_rcv,
			    "kttcp_soreceive sbwait 2");
			error = sbwait(&so->so_rcv);
			if (error) {
				sbunlock(&so->so_rcv);
				sounlock(so);
				return (0);
			}
			if ((m = so->so_rcv.sb_mb) != NULL)
				nextrecord = m->m_nextpkt;
		}
	}

	if (m && pr->pr_flags & PR_ATOMIC) {
		flags |= MSG_TRUNC;
		if ((flags & MSG_PEEK) == 0)
			(void) sbdroprecord(&so->so_rcv);
	}
	if ((flags & MSG_PEEK) == 0) {
		if (m == NULL) {
			/*
			 * First part is an SB_EMPTY_FIXUP().  Second part
			 * makes sure sb_lastrecord is up-to-date if
			 * there is still data in the socket buffer.
			 */
			so->so_rcv.sb_mb = nextrecord;
			if (so->so_rcv.sb_mb == NULL) {
				so->so_rcv.sb_mbtail = NULL;
				so->so_rcv.sb_lastrecord = NULL;
			} else if (nextrecord->m_nextpkt == NULL)
				so->so_rcv.sb_lastrecord = nextrecord;
		}
		SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 4");
		SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 4");
		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) {
			(*pr->pr_usrreqs->pr_rcvd)(so, flags, l);
		}
	}
	if (orig_resid == resid && orig_resid &&
	    (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
		sbunlock(&so->so_rcv);
		goto restart;
	}

	if (flagsp)
		*flagsp |= flags;
 release:
	sbunlock(&so->so_rcv);
	sounlock(so);
	*done = slen - resid;
#if 0
	printf("soreceive: error %d slen %llu resid %lld\n", error, slen, resid);
#endif
	return (error);
}