Beispiel #1
0
static struct mbuf *
m_getm(struct mbuf *m, int len, int how, int type)
{
        struct mbuf *top, *tail, *mp, *mtail = NULL;

        KASSERT(len >= 0);

        mp = m_get(how, type);
        if (mp == NULL)
                return (NULL);
        else if (len > MINCLSIZE) {
                m_clget(mp, how);
                if ((mp->m_flags & M_EXT) == 0) {
                        m_free(mp);
                        return (NULL);
                }
        }
        mp->m_len = 0;
        len -= M_TRAILINGSPACE(mp);

        if (m != NULL)
                for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next);
        else
                m = mp;

        top = tail = mp;
        while (len > 0) {
                mp = m_get(how, type);
                if (mp == NULL)
                        goto failed;

                tail->m_next = mp;
                tail = mp;
                if (len > MINCLSIZE) {
                        m_clget(mp, how);
                        if ((mp->m_flags & M_EXT) == 0)
                                goto failed;
                }

                mp->m_len = 0;
                len -= M_TRAILINGSPACE(mp);
        }

        if (mtail != NULL)
                mtail->m_next = top;
        return (m);

failed:
        m_freem(top);
        return (NULL);
}
Beispiel #2
0
int
rump_netconfig_auto_ipv6(const char *ifname)
{
	struct ifnet *ifp;
	int ifindex;
	struct socket *rsso = NULL;
	int rv = 0;
	int hoplimit = 255;
	struct mbuf *m_nam = NULL,
		    *m_outbuf = NULL;
	struct sockaddr_in6 *sin6;
	char *buf;
	struct nd_router_solicit rs;
	struct nd_opt_hdr opt;

	ifp = ifunit(ifname);
	if (ifp == NULL) {
		rv = ENXIO;
		goto out;
	}
	if (ifp->if_sadl->sdl_type != IFT_ETHER) {
		rv = EINVAL;
		goto out;
	}

	rv = socreate(PF_INET6, &rsso, SOCK_RAW, IPPROTO_ICMPV6, curlwp, NULL);
	if (rv != 0)
		goto out;
	ifindex = ifp->if_index;
	rv = so_setsockopt(curlwp, rsso, IPPROTO_IPV6, IPV6_MULTICAST_IF,
			&ifindex, sizeof ifindex);
	if (rv != 0)
		goto out;
	rv = so_setsockopt(curlwp, rsso, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
			&hoplimit, sizeof hoplimit);
	if (rv != 0)
		goto out;

	m_nam = m_get(M_WAIT, MT_SONAME);
	sin6 = mtod(m_nam, struct sockaddr_in6 *);
	sin6->sin6_len = m_nam->m_len = sizeof (*sin6);
	sin6->sin6_family = AF_INET6;
	netconfig_inet_pton6("ff02::2", &sin6->sin6_addr);

#define rslen (sizeof rs + sizeof opt + ETHER_ADDR_LEN)
	CTASSERT(rslen <= MCLBYTES);
	m_outbuf = m_gethdr(M_WAIT, MT_DATA);
	m_clget(m_outbuf, M_WAIT);
	m_outbuf->m_pkthdr.len = m_outbuf->m_len = rslen;


#if __NetBSD_Prereq__(7,99,31)
	m_set_rcvif(m_outbuf, NULL);
#else
	m_outbuf->m_pkthdr.rcvif = NULL;
#endif

#undef rslen
	buf = mtod(m_outbuf, char *);
	memset(&rs, 0, sizeof rs);
	rs.nd_rs_type = ND_ROUTER_SOLICIT;
	memset(&opt, 0, sizeof opt);
	opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
	opt.nd_opt_len = 1; /* units of 8 octets */
	memcpy(buf, &rs, sizeof rs);
	buf += sizeof rs;
	memcpy(buf, &opt, sizeof opt);
	buf += sizeof opt;
	memcpy(buf, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN);

	ip6_accept_rtadv = 1;
	rv = rump_netconfig_ifup(ifname);
	if (rv != 0)
		goto out;
#if __NetBSD_Prereq__(7,99,12)
	rv = (*rsso->so_send)(rsso, (struct sockaddr *)sin6, NULL, m_outbuf,
			NULL, 0, curlwp);
#else
	rv = (*rsso->so_send)(rsso, m_nam, NULL, m_outbuf, NULL, 0, curlwp);
#endif
	if (rv == 0)
		/* *(so_send)() takes ownership of m_outbuf on success */
		m_outbuf = NULL;
	else
		goto out;

	rv = 0;
out:
	if (m_nam)
		m_freem(m_nam);
	if (m_outbuf)
		m_freem(m_outbuf);
	if (rsso)
		soclose(rsso);
	return rv;
}
Beispiel #3
0
/*
 * Slightly changed version of sosend()
 */
static int
kttcp_sosend(struct socket *so, unsigned long long slen,
	     unsigned long long *done, struct lwp *l, int flags)
{
	struct mbuf **mp, *m, *top;
	long space, len, mlen;
	int error, dontroute, atomic;
	long long resid;

	atomic = sosendallatonce(so);
	resid = slen;
	top = NULL;
	/*
	 * In theory resid should be unsigned.
	 * However, space must be signed, as it might be less than 0
	 * if we over-committed, and we must use a signed comparison
	 * of space and resid.  On the other hand, a negative resid
	 * causes us to loop sending 0-length segments to the protocol.
	 */
	if (resid < 0) {
		error = EINVAL;
		goto out;
	}
	dontroute =
	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
	    (so->so_proto->pr_flags & PR_ATOMIC);
	l->l_ru.ru_msgsnd++;
#define	snderr(errno)	{ error = errno; goto release; }
	solock(so);
 restart:
	if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0)
		goto out;
	do {
		if (so->so_state & SS_CANTSENDMORE)
			snderr(EPIPE);
		if (so->so_error) {
			error = so->so_error;
			so->so_error = 0;
			goto release;
		}
		if ((so->so_state & SS_ISCONNECTED) == 0) {
			if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
				snderr(ENOTCONN);
			} else {
				snderr(EDESTADDRREQ);
			}
		}
		space = sbspace(&so->so_snd);
		if (flags & MSG_OOB)
			space += 1024;
		if ((atomic && resid > so->so_snd.sb_hiwat))
			snderr(EMSGSIZE);
		if (space < resid && (atomic || space < so->so_snd.sb_lowat)) {
			if (so->so_state & SS_NBIO)
				snderr(EWOULDBLOCK);
			SBLASTRECORDCHK(&so->so_rcv,
			    "kttcp_soreceive sbwait 1");
			SBLASTMBUFCHK(&so->so_rcv,
			    "kttcp_soreceive sbwait 1");
			sbunlock(&so->so_snd);
			error = sbwait(&so->so_snd);
			if (error)
				goto out;
			goto restart;
		}
		mp = &top;
		do {
			sounlock(so);
			do {
				if (top == 0) {
					m = m_gethdr(M_WAIT, MT_DATA);
					mlen = MHLEN;
					m->m_pkthdr.len = 0;
					m->m_pkthdr.rcvif = NULL;
				} else {
					m = m_get(M_WAIT, MT_DATA);
					mlen = MLEN;
				}
				if (resid >= MINCLSIZE && space >= MCLBYTES) {
					m_clget(m, M_WAIT);
					if ((m->m_flags & M_EXT) == 0)
						goto nopages;
					mlen = MCLBYTES;
#ifdef	MAPPED_MBUFS
					len = lmin(MCLBYTES, resid);
#else
					if (atomic && top == 0) {
						len = lmin(MCLBYTES - max_hdr,
						    resid);
						m->m_data += max_hdr;
					} else
						len = lmin(MCLBYTES, resid);
#endif
					space -= len;
				} else {
nopages:
					len = lmin(lmin(mlen, resid), space);
					space -= len;
					/*
					 * For datagram protocols, leave room
					 * for protocol headers in first mbuf.
					 */
					if (atomic && top == 0 && len < mlen)
						MH_ALIGN(m, len);
				}
				resid -= len;
				m->m_len = len;
				*mp = m;
				top->m_pkthdr.len += len;
				if (error)
					goto release;
				mp = &m->m_next;
				if (resid <= 0) {
					if (flags & MSG_EOR)
						top->m_flags |= M_EOR;
					break;
				}
			} while (space > 0 && atomic);
			solock(so);

			if (so->so_state & SS_CANTSENDMORE)
				snderr(EPIPE);
			if (dontroute)
				so->so_options |= SO_DONTROUTE;
			if (resid > 0)
				so->so_state |= SS_MORETOCOME;
			if (flags & MSG_OOB)
				error = (*so->so_proto->pr_usrreqs->pr_sendoob)(so,
				    top, NULL);
			else
				error = (*so->so_proto->pr_usrreqs->pr_send)(so,
				    top, NULL, NULL, l);
			if (dontroute)
				so->so_options &= ~SO_DONTROUTE;
			if (resid > 0)
				so->so_state &= ~SS_MORETOCOME;
			top = 0;
			mp = &top;
			if (error)
				goto release;
		} while (resid && space > 0);
	} while (resid);

 release:
	sbunlock(&so->so_snd);
 out:
 	sounlock(so);
	if (top)
		m_freem(top);
	*done = slen - resid;
#if 0
	printf("sosend: error %d slen %llu resid %lld\n", error, slen, resid);
#endif
	return (error);
}
Beispiel #4
0
static int
bpf_movein(struct uio *uio, int linktype, uint64_t mtu, struct mbuf **mp,
	   struct sockaddr *sockp)
{
	struct mbuf *m;
	int error;
	size_t len;
	size_t hlen;
	size_t align;

	/*
	 * Build a sockaddr based on the data link layer type.
	 * We do this at this level because the ethernet header
	 * is copied directly into the data field of the sockaddr.
	 * In the case of SLIP, there is no header and the packet
	 * is forwarded as is.
	 * Also, we are careful to leave room at the front of the mbuf
	 * for the link level header.
	 */
	switch (linktype) {

	case DLT_SLIP:
		sockp->sa_family = AF_INET;
		hlen = 0;
		align = 0;
		break;

	case DLT_PPP:
		sockp->sa_family = AF_UNSPEC;
		hlen = 0;
		align = 0;
		break;

	case DLT_EN10MB:
		sockp->sa_family = AF_UNSPEC;
		/* XXX Would MAXLINKHDR be better? */
 		/* 6(dst)+6(src)+2(type) */
		hlen = sizeof(struct ether_header);
		align = 2;
		break;

	case DLT_ARCNET:
		sockp->sa_family = AF_UNSPEC;
		hlen = ARC_HDRLEN;
		align = 5;
		break;

	case DLT_FDDI:
		sockp->sa_family = AF_LINK;
		/* XXX 4(FORMAC)+6(dst)+6(src) */
		hlen = 16;
		align = 0;
		break;

	case DLT_ECONET:
		sockp->sa_family = AF_UNSPEC;
		hlen = 6;
		align = 2;
		break;

	case DLT_NULL:
		sockp->sa_family = AF_UNSPEC;
		hlen = 0;
		align = 0;
		break;

	default:
		return (EIO);
	}

	len = uio->uio_resid;
	/*
	 * If there aren't enough bytes for a link level header or the
	 * packet length exceeds the interface mtu, return an error.
	 */
	if (len - hlen > mtu)
		return (EMSGSIZE);

	/*
	 * XXX Avoid complicated buffer chaining ---
	 * bail if it won't fit in a single mbuf.
	 * (Take into account possible alignment bytes)
	 */
	if (len + align > MCLBYTES)
		return (EIO);

	m = m_gethdr(M_WAIT, MT_DATA);
	m_reset_rcvif(m);
	m->m_pkthdr.len = (int)(len - hlen);
	if (len + align > MHLEN) {
		m_clget(m, M_WAIT);
		if ((m->m_flags & M_EXT) == 0) {
			error = ENOBUFS;
			goto bad;
		}
	}

	/* Insure the data is properly aligned */
	if (align > 0) {
		m->m_data += align;
		m->m_len -= (int)align;
	}

	error = uiomove(mtod(m, void *), len, uio);
	if (error)
		goto bad;
	if (hlen != 0) {
		memcpy(sockp->sa_data, mtod(m, void *), hlen);
		m->m_data += hlen; /* XXX */
		len -= hlen;
	}