void soisconnected(struct socket *so) { struct socket *head; head = so->so_head; KASSERT(solocked(so)); KASSERT(head == NULL || solocked2(so, head)); so->so_state &= ~(SS_ISCONNECTING | SS_ISDISCONNECTING); so->so_state |= SS_ISCONNECTED; if (head && so->so_onq == &head->so_q0) { if ((so->so_options & SO_ACCEPTFILTER) == 0) { soqremque(so, 0); soqinsque(head, so, 1); sorwakeup(head); cv_broadcast(&head->so_cv); } else { so->so_upcall = head->so_accf->so_accept_filter->accf_callback; so->so_upcallarg = head->so_accf->so_accept_filter_arg; so->so_rcv.sb_flags |= SB_UPCALL; so->so_options &= ~SO_ACCEPTFILTER; (*so->so_upcall)(so, so->so_upcallarg, POLLIN|POLLRDNORM, M_DONTWAIT); } } else { cv_broadcast(&so->so_cv); sorwakeup(so); sowwakeup(so); } }
int STKARGFUN raw_input(struct mbuf *m0, struct sockproto *proto, struct sockaddr *src, struct sockaddr *dst) { register struct rawcb *rp; register struct mbuf *m = m0; register int sockets = 0; struct socket *last; last = 0; for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { if (rp->rcb_proto.sp_family != proto->sp_family) continue; if (rp->rcb_proto.sp_protocol && rp->rcb_proto.sp_protocol != proto->sp_protocol) continue; /* * We assume the lower level routines have * placed the address in a canonical format * suitable for a structure comparison. * * Note that if the lengths are not the same * the comparison will fail at the first byte. */ #define equal(a1, a2) \ (bcmp((caddr_t)(a1), (caddr_t)(a2), a1->sa_len) == 0) if (rp->rcb_laddr && !equal(rp->rcb_laddr, dst)) continue; if (rp->rcb_faddr && !equal(rp->rcb_faddr, src)) continue; if (last) { struct mbuf *n; if (n = m_copy(m, 0, (int)M_COPYALL)) { if (sbappendaddr(&last->so_rcv, src, n, (struct mbuf *)0) == 0) /* should notify about lost packet */ m_freem(n); else { sorwakeup(last); sockets++; } } } last = rp->rcb_socket; } if (last) { if (sbappendaddr(&last->so_rcv, src, m, (struct mbuf *)0) == 0) m_freem(m); else { sorwakeup(last); sockets++; } } else m_freem(m); return (sockets); }
/* * Setup generic address and protocol structures * for raw_input routine, then pass them along with * mbuf chain. */ void rip_input(struct mbuf *m, int iphlen) { struct ip *ip = mtod(m, struct ip *); register struct inpcb *inp; struct inpcb *last = 0; struct mbuf *opts = 0; ripsrc.sin_addr = ip->ip_src; for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { if (inp->inp_ip_p && inp->inp_ip_p != ip->ip_p) continue; if (inp->inp_laddr.s_addr && inp->inp_laddr.s_addr != ip->ip_dst.s_addr) continue; if (inp->inp_faddr.s_addr && inp->inp_faddr.s_addr != ip->ip_src.s_addr) continue; if (last) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); if (n) { if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) ip_savecontrol(last, &opts, ip, n); if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&ripsrc, n, opts) == 0) { /* should notify about lost packet */ m_freem(n); if (opts) m_freem(opts); } else sorwakeup(last->inp_socket); opts = 0; } } last = inp; } if (last) { if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) ip_savecontrol(last, &opts, ip, m); if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&ripsrc, m, opts) == 0) { m_freem(m); if (opts) m_freem(opts); } else sorwakeup(last->inp_socket); } else { m_freem(m); ipstat.ips_noproto++; ipstat.ips_delivered--; } }
void socantrcvmore(struct socket *so) { so->so_state |= SS_CANTRCVMORE; sorwakeup(so); }
/* ----------------------------------------------------------------------------- called from l2tp_rfc when data are present ----------------------------------------------------------------------------- */ int l2tp_input(void *data, mbuf_t m, struct sockaddr *from, int more) { struct socket *so = (struct socket *)data; int err; lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); if (so->so_tpcb) { // we are hooked to ppp return l2tp_wan_input(ALIGNED_CAST(struct ppp_link *)so->so_tpcb, m); // Wcast-align fix - we malloc so->so_tpcb } if (m) { if (from == 0) { // no from address, just free the buffer mbuf_freem(m); return 1; } if (sbappendaddr(&so->so_rcv, from, (struct mbuf *)m, 0, &err) == 0) { //IOLog("l2tp_input no space, so = %p\n", so); return 1; } } if (!more) sorwakeup(so); return 0; }
/* * Notify a udp user of an asynchronous error; * just wake up so that he can collect error status. */ void udp_notify(struct inpcb *inp, int error) { inp->inp_socket->so_error = error; sorwakeup(inp->inp_socket); sowwakeup(inp->inp_socket); }
/* * subroutine of udp_input(), mainly for source code readability. * caller must properly init udp_ip6 and udp_in6 beforehand. */ static void udp_append(struct inpcb *last, struct ip *ip, struct mbuf *n, int off, struct sockaddr_in *udp_in) { struct mbuf *opts = NULL; int ret; KASSERT(INP_ISIPV4(last), ("not inet inpcb")); if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) ip_savecontrol(last, &opts, ip, n); m_adj(n, off); lwkt_gettoken(&last->inp_socket->so_rcv.ssb_token); ret = ssb_appendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)udp_in, n, opts); lwkt_reltoken(&last->inp_socket->so_rcv.ssb_token); if (ret == 0) { m_freem(n); if (opts) m_freem(opts); udp_stat.udps_fullsock++; } else { sorwakeup(last->inp_socket); } }
/* * socantrcvmore(): indicates that no more data will be received and * will normally be applied to the socket by a protocol when it detects * that the peer will send no more data. Data queued for reading in * the socket may yet be read. */ void socantrcvmore(struct socket *so) { KASSERT(solocked(so)); so->so_state |= SS_CANTRCVMORE; sorwakeup(so); }
void soisconnected(struct socket *so) { struct socket *head = so->so_head; so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING); so->so_state |= SS_ISCONNECTED; if (head && soqremque(so, 0)) { soqinsque(head, so, 1); sorwakeup(head); wakeup_one(&head->so_timeo); } else { wakeup(&so->so_timeo); sorwakeup(so); sowwakeup(so); } }
/* * When an attempt at a new connection is noted on a socket * which accepts connections, sonewconn is called. If the * connection is possible (subject to space constraints, etc.) * then we allocate a new structure, properly linked into the * data structure of the original socket, and return this. * Connstatus may be 0 or SS_ISCONNECTED. * * Must be called at splsoftnet() */ struct socket * sonewconn(struct socket *head, int connstatus) { struct socket *so; int soqueue = connstatus ? 1 : 0; splsoftassert(IPL_SOFTNET); if (mclpools[0].pr_nout > mclpools[0].pr_hardlimit * 95 / 100) return (NULL); if (head->so_qlen + head->so_q0len > head->so_qlimit * 3) return (NULL); so = pool_get(&socket_pool, PR_NOWAIT|PR_ZERO); if (so == NULL) return (NULL); so->so_type = head->so_type; so->so_options = head->so_options &~ SO_ACCEPTCONN; so->so_linger = head->so_linger; so->so_state = head->so_state | SS_NOFDREF; so->so_proto = head->so_proto; so->so_timeo = head->so_timeo; so->so_pgid = head->so_pgid; so->so_euid = head->so_euid; so->so_ruid = head->so_ruid; so->so_egid = head->so_egid; so->so_rgid = head->so_rgid; so->so_cpid = head->so_cpid; so->so_siguid = head->so_siguid; so->so_sigeuid = head->so_sigeuid; /* * Inherit watermarks but those may get clamped in low mem situations. */ if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat)) { pool_put(&socket_pool, so); return (NULL); } so->so_snd.sb_wat = head->so_snd.sb_wat; so->so_snd.sb_lowat = head->so_snd.sb_lowat; so->so_snd.sb_timeo = head->so_snd.sb_timeo; so->so_rcv.sb_wat = head->so_rcv.sb_wat; so->so_rcv.sb_lowat = head->so_rcv.sb_lowat; so->so_rcv.sb_timeo = head->so_rcv.sb_timeo; soqinsque(head, so, soqueue); if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH, NULL, NULL, NULL, curproc)) { (void) soqremque(so, soqueue); pool_put(&socket_pool, so); return (NULL); } if (connstatus) { sorwakeup(head); wakeup(&head->so_timeo); so->so_state |= connstatus; } return (so); }
void soisdisconnected(struct socket *so) { so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); soconnwakeup(so); sowwakeup(so); sorwakeup(so); }
void soisdisconnecting(struct socket *so) { so->so_state &= ~SS_ISCONNECTING; so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); wakeup(&so->so_timeo); sowwakeup(so); sorwakeup(so); }
/* * natmintr: interrupt * * Note: we expect a socket pointer in rcvif rather than an interface * pointer. We can get the interface pointer from the so's PCB if we really * need it. */ void natmintr(struct mbuf *m) { struct socket *so; struct natmpcb *npcb; #ifdef DIAGNOSTIC M_ASSERTPKTHDR(m); #endif NATM_LOCK(); npcb = (struct natmpcb *)m->m_pkthdr.rcvif; /* XXX: overloaded */ so = npcb->npcb_socket; npcb->npcb_inq--; if (npcb->npcb_flags & NPCB_DRAIN) { if (npcb->npcb_inq == 0) free(npcb, M_PCB); /* done! */ NATM_UNLOCK(); m_freem(m); return; } if (npcb->npcb_flags & NPCB_FREE) { NATM_UNLOCK(); m_freem(m); /* drop */ return; } #ifdef NEED_TO_RESTORE_IFP m->m_pkthdr.rcvif = npcb->npcb_ifp; #else #ifdef DIAGNOSTIC m->m_pkthdr.rcvif = NULL; /* null it out to be safe */ #endif #endif if (sbspace(&so->so_rcv) > m->m_pkthdr.len) { #ifdef NATM_STAT natm_sookcnt++; natm_sookbytes += m->m_pkthdr.len; #endif sbappendrecord(&so->so_rcv, m); sorwakeup(so); NATM_UNLOCK(); } else { #ifdef NATM_STAT natm_sodropcnt++; natm_sodropbytes += m->m_pkthdr.len; #endif NATM_UNLOCK(); m_freem(m); } }
void soisconnected(struct socket *so) { register struct socket *head = so->so_head; so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); so->so_state |= SS_ISCONNECTED; if (head && (so->so_state & SS_INCOMP)) { TAILQ_REMOVE(&head->so_incomp, so, so_list); head->so_incqlen--; so->so_state &= ~SS_INCOMP; TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); so->so_state |= SS_COMP; sorwakeup(head); soconnwakeup(head); } else { soconnwakeup(so); sorwakeup(so); sowwakeup(so); } }
void soisdisconnected(struct socket *so) { KASSERT(solocked(so)); so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED); cv_broadcast(&so->so_cv); sowwakeup(so); sorwakeup(so); }
int socket6_send(struct socket *s, struct mbuf *mm, struct sockaddr_in6 *src) { if (s) { if (sbappendaddr(&s->so_rcv, sin6tosa(src), mm, NULL) != 0) { sorwakeup(s); return 0; } } m_freem(mm); return -1; }
void soisdisconnecting(struct socket *so) { KASSERT(solocked(so)); so->so_state &= ~SS_ISCONNECTING; so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); #if 0 cv_broadcast(&so->so_cv); #endif sowwakeup(so); sorwakeup(so); }
/* * This may also be called for raw listeners. */ void idp_input(struct mbuf *m, ...) { struct nspcb *nsp; struct idp *idp = mtod(m, struct idp *); struct ifnet *ifp = m->m_pkthdr.rcvif; struct sockaddr_ns idp_ns; va_list ap; va_start(ap, m); nsp = va_arg(ap, struct nspcb *); va_end(ap); if (nsp == NULL) panic("No nspcb"); /* * Construct sockaddr format source address. * Stuff source address and datagram in user buffer. */ bzero(&idp_ns, sizeof(idp_ns)); idp_ns.sns_len = sizeof(idp_ns); idp_ns.sns_family = AF_NS; idp_ns.sns_addr = idp->idp_sna; if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) { struct ifaddr *ifa; for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) { if (ifa->ifa_addr->sa_family == AF_NS) { idp_ns.sns_addr.x_net = IA_SNS(ifa)->sns_addr.x_net; break; } } } nsp->nsp_rpt = idp->idp_pt; if ( ! (nsp->nsp_flags & NSP_RAWIN) ) { m->m_len -= sizeof (struct idp); m->m_pkthdr.len -= sizeof (struct idp); m->m_data += sizeof (struct idp); } if (sbappendaddr(&nsp->nsp_socket->so_rcv, snstosa(&idp_ns), m, (struct mbuf *)0) == 0) goto bad; sorwakeup(nsp->nsp_socket); return; bad: m_freem(m); }
/* * This may also be called for raw listeners. */ void ipx_input(struct mbuf *m, struct ipxpcb *ipxp) { struct ipx *ipx = mtod(m, struct ipx *); struct ifnet *ifp = m->m_pkthdr.rcvif; struct sockaddr_ipx ipx_ipx; KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb")); IPX_LOCK_ASSERT(ipxp); /* * Construct sockaddr format source address. * Stuff source address and datagram in user buffer. */ ipx_ipx.sipx_len = sizeof(ipx_ipx); ipx_ipx.sipx_family = AF_IPX; ipx_ipx.sipx_addr = ipx->ipx_sna; ipx_ipx.sipx_zero[0] = '\0'; ipx_ipx.sipx_zero[1] = '\0'; if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) { struct ifaddr *ifa; for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_link)) { if (ifa->ifa_addr->sa_family == AF_IPX) { ipx_ipx.sipx_addr.x_net = IA_SIPX(ifa)->sipx_addr.x_net; break; } } } ipxp->ipxp_rpt = ipx->ipx_pt; if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) { m->m_len -= sizeof(struct ipx); m->m_pkthdr.len -= sizeof(struct ipx); m->m_data += sizeof(struct ipx); } #ifdef MAC if (mac_socket_check_deliver(ipxp->ipxp_socket, m) != 0) { m_freem(m); return; } #endif if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, m, NULL) == 0) m_freem(m); else sorwakeup(ipxp->ipxp_socket); }
/* FUNCTION: sorflush() * * PARAM1: struct socket * socket structure * * RETURNS: none * * Closes the "read" half of the socket connection. No more data * can be received on the socket, and any data currently in the * socket receive buffer is discarded. Wakeup any processes waiting * on the socket. */ void sorflush(struct socket * so) { struct sockbuf *sb = &so->so_rcv; int s; sblock(sb); socantrcvmore(so); sbunlock(sb); sbrelease(sb); MEMSET((char *)sb, 0, sizeof (*sb)); s = so->so_error; so->so_error = ESHUTDOWN; sorwakeup(so); so->so_error = s; }
/* * Notify a udp user of an asynchronous error; just wake up so that they can * collect error status. */ struct inpcb * udp_notify(struct inpcb *inp, int errno) { /* * While udp_ctlinput() always calls udp_notify() with a read lock * when invoking it directly, in_pcbnotifyall() currently uses write * locks due to sharing code with TCP. For now, accept either a read * or a write lock, but a read lock is sufficient. */ INP_LOCK_ASSERT(inp); inp->inp_socket->so_error = errno; sorwakeup(inp->inp_socket); sowwakeup(inp->inp_socket); return (inp); }
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); }
key_receive(struct socket *so, struct mbuf **paddr, struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, int *flagsp) #endif { struct rawcb *rp = sotorawcb(so); struct keycb *kp = (struct keycb *)rp; int error; #ifndef __FreeBSD__ error = (*kp->kp_receive)(so, paddr, uio, mp0, controlp, flagsp); #else error = soreceive(so, paddr, uio, mp0, controlp, flagsp); #endif if (kp->kp_queue && sbspace(&rp->rcb_socket->so_rcv) > kp->kp_queue->m_pkthdr.len) sorwakeup(so); return error; }
static int soo_drain(struct fileproc *fp, __unused vfs_context_t ctx) { int error = 0; struct socket *so = (struct socket *)fp->f_fglob->fg_data; if (so) { socket_lock(so, 1); so->so_state |= SS_DRAINING; wakeup((caddr_t)&so->so_timeo); sorwakeup(so); sowwakeup(so); socket_unlock(so, 1); } return (error); }
int userfw_domain_send_to_socket(struct socket *so, unsigned char *buf, size_t len) { struct mbchain m; int err; mb_init(&m); err = mb_put_mem(&m, buf, len, MB_MSYSTEM); if (err != 0) { mb_done(&m); return err; } sbappendstream(&(so->so_rcv), mb_detach(&m)); sorwakeup(so); return 0; }
/* * Receive data on a hook */ static int ngs_rcvdata(hook_p hook, item_p item) { struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct ngpcb *const pcbp = priv->datasock; struct socket *so; struct sockaddr_ng *addr; char *addrbuf[NG_HOOKSIZ + 4]; int addrlen; struct mbuf *m; NGI_GET_M(item, m); NG_FREE_ITEM(item); /* If there is no data socket, black-hole it. */ if (pcbp == NULL) { NG_FREE_M(m); return (0); } so = pcbp->ng_socket; /* Get the return address into a sockaddr. */ addrlen = strlen(NG_HOOK_NAME(hook)); /* <= NG_HOOKSIZ - 1 */ addr = (struct sockaddr_ng *) addrbuf; addr->sg_len = addrlen + 3; addr->sg_family = AF_NETGRAPH; bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen); addr->sg_data[addrlen] = '\0'; /* Try to tell the socket which hook it came in on. */ if (sbappendaddr((struct sockbuf *)&so->so_rcv, (struct sockaddr *)addr, m, NULL) == 0) { m_freem(m); TRAP_ERROR; return (ENOBUFS); } sorwakeup(so); return (0); }
/* * send message to the socket. */ static int key_sendup0(struct rawcb *rp, struct mbuf *m, int promisc, int canwait) { struct keycb *kp = (struct keycb *)rp; struct mbuf *n; int error = 0; if (canwait) { if (kp->kp_queue) { for (n = kp->kp_queue; n && n->m_nextpkt; n = n->m_nextpkt) ; n->m_nextpkt = m; m = kp->kp_queue; kp->kp_queue = NULL; } else m->m_nextpkt = NULL; /* just for safety */ } else m->m_nextpkt = NULL; for (; m && error == 0; m = n) { n = m->m_nextpkt; if (promisc) { struct sadb_msg *pmsg; M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT); if (m && m->m_len < sizeof(struct sadb_msg)) m = m_pullup(m, sizeof(struct sadb_msg)); if (!m) { pfkeystat.in_nomem++; error = ENOBUFS; goto recovery; } m->m_pkthdr.len += sizeof(*pmsg); pmsg = mtod(m, struct sadb_msg *); bzero(pmsg, sizeof(*pmsg)); pmsg->sadb_msg_version = PF_KEY_V2; pmsg->sadb_msg_type = SADB_X_PROMISC; pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); /* pid and seq? */ pfkeystat.in_msgtype[pmsg->sadb_msg_type]++; } if (canwait && sbspace(&rp->rcb_socket->so_rcv) < m->m_pkthdr.len) { error = EAGAIN; goto recovery; } m->m_nextpkt = NULL; if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src, m, NULL)) { pfkeystat.in_nomem++; error = ENOBUFS; goto recovery; } else { sorwakeup(rp->rcb_socket); error = 0; } } return (error); recovery: if (kp->kp_queue) { /* * insert m to the head of queue, as normally mbuf on the queue * is less important than others. */ if (m) { m->m_nextpkt = kp->kp_queue; kp->kp_queue = m; } } else { /* recover the queue */ if (!m) { /* first ENOBUFS case */ kp->kp_queue = n; } else { kp->kp_queue = m; m->m_nextpkt = n; } } return (error); }
/* * When an attempt at a new connection is noted on a socket * which accepts connections, sonewconn is called. If the * connection is possible (subject to space constraints, etc.) * then we allocate a new structure, propoerly linked into the * data structure of the original socket, and return this. * Connstatus may be 0, SS_ISCONFIRMING, or SS_ISCONNECTED. */ struct socket * sonewconn(struct socket *head, int connstatus) { struct socket *so; int soqueue, error; KASSERT(connstatus == 0 || connstatus == SS_ISCONFIRMING || connstatus == SS_ISCONNECTED); KASSERT(solocked(head)); if ((head->so_options & SO_ACCEPTFILTER) != 0) connstatus = 0; soqueue = connstatus ? 1 : 0; if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2) return NULL; so = soget(false); if (so == NULL) return NULL; mutex_obj_hold(head->so_lock); // so->so_lock = head->so_lock; so->so_type = head->so_type; so->so_options = head->so_options &~ SO_ACCEPTCONN; so->so_linger = head->so_linger; so->so_state = head->so_state | SS_NOFDREF; so->so_proto = head->so_proto; so->so_timeo = head->so_timeo; #if 0 /* VADIM */ so->so_pgid = head->so_pgid; so->so_send = head->so_send; so->so_receive = head->so_receive; so->so_uidinfo = head->so_uidinfo; so->so_cpid = head->so_cpid; #else so->glueing_block = NULL; #endif #ifdef MBUFTRACE so->so_mowner = head->so_mowner; so->so_rcv.sb_mowner = head->so_rcv.sb_mowner; so->so_snd.sb_mowner = head->so_snd.sb_mowner; #endif if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) != 0) goto out; so->so_snd.sb_lowat = head->so_snd.sb_lowat; so->so_rcv.sb_lowat = head->so_rcv.sb_lowat; so->so_rcv.sb_timeo = head->so_rcv.sb_timeo; so->so_snd.sb_timeo = head->so_snd.sb_timeo; so->so_rcv.sb_flags |= head->so_rcv.sb_flags & (SB_AUTOSIZE | SB_ASYNC); so->so_snd.sb_flags |= head->so_snd.sb_flags & (SB_AUTOSIZE | SB_ASYNC); soqinsque(head, so, soqueue); error = (*so->so_proto->pr_usrreq)(so, PRU_ATTACH, NULL, NULL, NULL); KASSERT(solocked(so)); if (error != 0) { (void) soqremque(so, soqueue); out: /* * Remove acccept filter if one is present. * XXX Is this really needed? */ #if 0 /*VADIM*/ if (so->so_accf != NULL) (void)accept_filt_clear(so); #endif soput(so); return NULL; } if (connstatus) { sorwakeup(head); #if 0 cv_broadcast(&head->so_cv); #endif so->so_state |= connstatus; } return so; }
int udp_input(struct mbuf **mp, int *offp, int proto) { struct sockaddr_in udp_in = { sizeof udp_in, AF_INET }; int iphlen; struct ip *ip; struct udphdr *uh; struct inpcb *inp; struct mbuf *m; struct mbuf *opts = NULL; int len, off; struct ip save_ip; struct inpcbinfo *pcbinfo = &udbinfo[mycpuid]; off = *offp; m = *mp; *mp = NULL; iphlen = off; udp_stat.udps_ipackets++; /* * Strip IP options, if any; should skip this, * make available to user, and use on returned packets, * but we don't yet have a way to check the checksum * with options still present. */ if (iphlen > sizeof(struct ip)) { ip_stripoptions(m); iphlen = sizeof(struct ip); } /* * IP and UDP headers are together in first mbuf. * Already checked and pulled up in ip_demux(). */ KASSERT(m->m_len >= iphlen + sizeof(struct udphdr), ("UDP header not in one mbuf")); ip = mtod(m, struct ip *); uh = (struct udphdr *)((caddr_t)ip + iphlen); /* destination port of 0 is illegal, based on RFC768. */ if (uh->uh_dport == 0) goto bad; /* * Make mbuf data length reflect UDP length. * If not enough data to reflect UDP length, drop. */ len = ntohs((u_short)uh->uh_ulen); if (ip->ip_len != len) { if (len > ip->ip_len || len < sizeof(struct udphdr)) { udp_stat.udps_badlen++; goto bad; } m_adj(m, len - ip->ip_len); /* ip->ip_len = len; */ } /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. */ save_ip = *ip; /* * Checksum extended UDP header and data. */ if (uh->uh_sum) { if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) uh->uh_sum = m->m_pkthdr.csum_data; else uh->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, htonl((u_short)len + m->m_pkthdr.csum_data + IPPROTO_UDP)); uh->uh_sum ^= 0xffff; } else { char b[9]; bcopy(((struct ipovly *)ip)->ih_x1, b, 9); bzero(((struct ipovly *)ip)->ih_x1, 9); ((struct ipovly *)ip)->ih_len = uh->uh_ulen; uh->uh_sum = in_cksum(m, len + sizeof(struct ip)); bcopy(b, ((struct ipovly *)ip)->ih_x1, 9); } if (uh->uh_sum) { udp_stat.udps_badsum++; m_freem(m); return(IPPROTO_DONE); } } else udp_stat.udps_nosum++; if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { struct inpcbhead *connhead; struct inpcontainer *ic, *ic_marker; struct inpcontainerhead *ichead; struct udp_mcast_arg arg; struct inpcb *last; int error; /* * Deliver a multicast or broadcast datagram to *all* sockets * for which the local and remote addresses and ports match * those of the incoming datagram. This allows more than * one process to receive multi/broadcasts on the same port. * (This really ought to be done for unicast datagrams as * well, but that would cause problems with existing * applications that open both address-specific sockets and * a wildcard socket listening to the same port -- they would * end up receiving duplicates of every unicast datagram. * Those applications open the multiple sockets to overcome an * inadequacy of the UDP socket interface, but for backwards * compatibility we avoid the problem here rather than * fixing the interface. Maybe 4.5BSD will remedy this?) */ /* * Construct sockaddr format source address. */ udp_in.sin_port = uh->uh_sport; udp_in.sin_addr = ip->ip_src; arg.udp_in = &udp_in; /* * Locate pcb(s) for datagram. * (Algorithm copied from raw_intr().) */ last = NULL; arg.iphlen = iphlen; connhead = &pcbinfo->hashbase[ INP_PCBCONNHASH(ip->ip_src.s_addr, uh->uh_sport, ip->ip_dst.s_addr, uh->uh_dport, pcbinfo->hashmask)]; LIST_FOREACH(inp, connhead, inp_hash) { #ifdef INET6 if (!INP_ISIPV4(inp)) continue; #endif if (!in_hosteq(inp->inp_faddr, ip->ip_src) || !in_hosteq(inp->inp_laddr, ip->ip_dst) || inp->inp_fport != uh->uh_sport || inp->inp_lport != uh->uh_dport) continue; arg.inp = inp; arg.last = last; arg.ip = ip; arg.m = m; error = udp_mcast_input(&arg); if (error == ERESTART) continue; last = arg.last; if (error == EJUSTRETURN) goto done; } ichead = &pcbinfo->wildcardhashbase[ INP_PCBWILDCARDHASH(uh->uh_dport, pcbinfo->wildcardhashmask)]; ic_marker = in_pcbcontainer_marker(mycpuid); GET_PCBINFO_TOKEN(pcbinfo); LIST_INSERT_HEAD(ichead, ic_marker, ic_list); while ((ic = LIST_NEXT(ic_marker, ic_list)) != NULL) { LIST_REMOVE(ic_marker, ic_list); LIST_INSERT_AFTER(ic, ic_marker, ic_list); inp = ic->ic_inp; if (inp->inp_flags & INP_PLACEMARKER) continue; #ifdef INET6 if (!INP_ISIPV4(inp)) continue; #endif if (inp->inp_lport != uh->uh_dport) continue; if (inp->inp_laddr.s_addr != INADDR_ANY && inp->inp_laddr.s_addr != ip->ip_dst.s_addr) continue; arg.inp = inp; arg.last = last; arg.ip = ip; arg.m = m; error = udp_mcast_input(&arg); if (error == ERESTART) continue; last = arg.last; if (error == EJUSTRETURN) break; } LIST_REMOVE(ic_marker, ic_list); REL_PCBINFO_TOKEN(pcbinfo); done: if (last == NULL) { /* * No matching pcb found; discard datagram. * (No need to send an ICMP Port Unreachable * for a broadcast or multicast datgram.) */ udp_stat.udps_noportbcast++; goto bad; } #ifdef IPSEC /* check AH/ESP integrity. */ if (ipsec4_in_reject_so(m, last->inp_socket)) { ipsecstat.in_polvio++; goto bad; } #endif /*IPSEC*/ #ifdef FAST_IPSEC /* check AH/ESP integrity. */ if (ipsec4_in_reject(m, last)) goto bad; #endif /*FAST_IPSEC*/ udp_append(last, ip, m, iphlen + sizeof(struct udphdr), &udp_in); return(IPPROTO_DONE); } /* * Locate pcb for datagram. */ inp = in_pcblookup_pkthash(pcbinfo, ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport, TRUE, m->m_pkthdr.rcvif, udp_reuseport_ext ? m : NULL); if (inp == NULL) { if (log_in_vain) { char buf[sizeof "aaa.bbb.ccc.ddd"]; strcpy(buf, inet_ntoa(ip->ip_dst)); log(LOG_INFO, "Connection attempt to UDP %s:%d from %s:%d\n", buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src), ntohs(uh->uh_sport)); } udp_stat.udps_noport++; if (m->m_flags & (M_BCAST | M_MCAST)) { udp_stat.udps_noportbcast++; goto bad; } if (blackhole) goto bad; #ifdef ICMP_BANDLIM if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0) goto bad; #endif *ip = save_ip; ip->ip_len += iphlen; icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); return(IPPROTO_DONE); } KASSERT(INP_ISIPV4(inp), ("not inet inpcb")); #ifdef IPSEC if (ipsec4_in_reject_so(m, inp->inp_socket)) { ipsecstat.in_polvio++; goto bad; } #endif /*IPSEC*/ #ifdef FAST_IPSEC if (ipsec4_in_reject(m, inp)) goto bad; #endif /*FAST_IPSEC*/ /* * Check the minimum TTL for socket. */ if (ip->ip_ttl < inp->inp_ip_minttl) goto bad; /* * Construct sockaddr format source address. * Stuff source address and datagram in user buffer. */ udp_in.sin_port = uh->uh_sport; udp_in.sin_addr = ip->ip_src; if ((inp->inp_flags & INP_CONTROLOPTS) || (inp->inp_socket->so_options & SO_TIMESTAMP)) ip_savecontrol(inp, &opts, ip, m); m_adj(m, iphlen + sizeof(struct udphdr)); lwkt_gettoken(&inp->inp_socket->so_rcv.ssb_token); if (ssb_appendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m, opts) == 0) { lwkt_reltoken(&inp->inp_socket->so_rcv.ssb_token); udp_stat.udps_fullsock++; goto bad; } lwkt_reltoken(&inp->inp_socket->so_rcv.ssb_token); sorwakeup(inp->inp_socket); return(IPPROTO_DONE); bad: m_freem(m); if (opts) m_freem(opts); return(IPPROTO_DONE); }
void natmintr() { int s; struct mbuf *m; struct socket *so; struct natmpcb *npcb; next: s = splnet(); IF_DEQUEUE(&natmintrq, m); splx(s); if (m == NULL) return; #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("natmintr no HDR"); #endif npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */ so = npcb->npcb_socket; s = splnet(); /* could have atm devs @ different levels */ npcb->npcb_inq--; splx(s); if (npcb->npcb_flags & NPCB_DRAIN) { m_freem(m); if (npcb->npcb_inq == 0) free(npcb, M_PCB); /* done! */ goto next; } if (npcb->npcb_flags & NPCB_FREE) { m_freem(m); /* drop */ goto next; } #ifdef NEED_TO_RESTORE_IFP m->m_pkthdr.rcvif = npcb->npcb_ifp; #else #ifdef DIAGNOSTIC m->m_pkthdr.rcvif = NULL; /* null it out to be safe */ #endif #endif if (sbspace(&so->so_rcv) > m->m_pkthdr.len || ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) { #ifdef NATM_STAT natm_sookcnt++; natm_sookbytes += m->m_pkthdr.len; #endif sbappendrecord(&so->so_rcv, m); sorwakeup(so); } else { #ifdef NATM_STAT natm_sodropcnt++; natm_sodropbytes += m->m_pkthdr.len; #endif m_freem(m); } goto next; }