static int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0) { struct ipx *ipx; struct socket *so; int len = 0; struct route *ro; struct mbuf *m; struct mbuf *mprev = NULL; IPX_LOCK_ASSERT(ipxp); /* * Calculate data length. */ for (m = m0; m != NULL; m = m->m_next) { mprev = m; len += m->m_len; } /* * Make sure packet is actually of even length. */ if (len & 1) { m = mprev; if ((m->m_flags & M_EXT) == 0 && (m->m_len + m->m_data < &m->m_dat[MLEN])) { mtod(m, char*)[m->m_len++] = 0; } else { struct mbuf *m1 = m_get(M_NOWAIT, MT_DATA); if (m1 == NULL) { m_freem(m0); return (ENOBUFS); } m1->m_len = 1; * mtod(m1, char *) = 0; m->m_next = m1; } m0->m_pkthdr.len++; } /* * Fill in mbuf with extended IPX header * and addresses and length put into network format. */ m = m0; if (ipxp->ipxp_flags & IPXP_RAWOUT) { ipx = mtod(m, struct ipx *); } else {
/* * 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); }
/* * Drop connection, reporting * the specified error. */ void ipx_drop(struct ipxpcb *ipxp, int errno) { struct socket *so = ipxp->ipxp_socket; IPX_LIST_LOCK_ASSERT(); IPX_LOCK_ASSERT(ipxp); /* * someday, in the IPX world * we will generate error protocol packets * announcing that the socket has gone away. * * XXX Probably never. IPX does not have error packets. */ /*if (TCPS_HAVERCVDSYN(tp->t_state)) { tp->t_state = TCPS_CLOSED; tcp_output(tp); }*/ so->so_error = errno; ipx_pcbdisconnect(ipxp); soisdisconnected(so); }
void spx_input(struct mbuf *m, struct ipxpcb *ipxp) { struct spxpcb *cb; struct spx *si = mtod(m, struct spx *); struct socket *so; struct spx spx_savesi; int dropsocket = 0; short ostate = 0; spxstat.spxs_rcvtotal++; KASSERT(ipxp != NULL, ("spx_input: ipxpcb == NULL")); /* * spx_input() assumes that the caller will hold both the pcb list * lock and also the ipxp lock. spx_input() will release both before * returning, and may in fact trade in the ipxp lock for another pcb * lock following sonewconn(). */ IPX_LIST_LOCK_ASSERT(); IPX_LOCK_ASSERT(ipxp); cb = ipxtospxpcb(ipxp); KASSERT(cb != NULL, ("spx_input: cb == NULL")); if (ipxp->ipxp_flags & IPXP_DROPPED) goto drop; if (m->m_len < sizeof(*si)) { if ((m = m_pullup(m, sizeof(*si))) == NULL) { IPX_UNLOCK(ipxp); IPX_LIST_UNLOCK(); spxstat.spxs_rcvshort++; return; } si = mtod(m, struct spx *); } si->si_seq = ntohs(si->si_seq); si->si_ack = ntohs(si->si_ack); si->si_alo = ntohs(si->si_alo); so = ipxp->ipxp_socket; KASSERT(so != NULL, ("spx_input: so == NULL")); #ifdef MAC if (mac_socket_check_deliver(so, m) != 0) goto drop; #endif if (so->so_options & SO_DEBUG || traceallspxs) { ostate = cb->s_state; spx_savesi = *si; } if (so->so_options & SO_ACCEPTCONN) { struct spxpcb *ocb = cb; so = sonewconn(so, 0); if (so == NULL) goto drop; /* * This is ugly, but .... * * Mark socket as temporary until we're committed to keeping * it. The code at ``drop'' and ``dropwithreset'' check the * flag dropsocket to see if the temporary socket created * here should be discarded. We mark the socket as * discardable until we're committed to it below in * TCPS_LISTEN. * * XXXRW: In the new world order of real kernel parallelism, * temporarily allocating the socket when we're "not sure" * seems like a bad idea, as we might race to remove it if * the listen socket is closed...? * * We drop the lock of the listen socket ipxp, and acquire * the lock of the new socket ippx. */ dropsocket++; IPX_UNLOCK(ipxp); ipxp = (struct ipxpcb *)so->so_pcb; IPX_LOCK(ipxp); ipxp->ipxp_laddr = si->si_dna; cb = ipxtospxpcb(ipxp); cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ cb->s_flags = ocb->s_flags; /* preserve sockopts */ cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ cb->s_state = TCPS_LISTEN; } IPX_LOCK_ASSERT(ipxp); /* * Packet received on connection. Reset idle time and keep-alive * timer. */ cb->s_idle = 0; cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; switch (cb->s_state) { case TCPS_LISTEN:{ struct sockaddr_ipx *sipx, ssipx; struct ipx_addr laddr; /* * If somebody here was carying on a conversation and went * away, and his pen pal thinks he can still talk, we get the * misdirected packet. */ if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { spx_istat.gonawy++; goto dropwithreset; } sipx = &ssipx; bzero(sipx, sizeof *sipx); sipx->sipx_len = sizeof(*sipx); sipx->sipx_family = AF_IPX; sipx->sipx_addr = si->si_sna; laddr = ipxp->ipxp_laddr; if (ipx_nullhost(laddr)) ipxp->ipxp_laddr = si->si_dna; if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &thread0)) { ipxp->ipxp_laddr = laddr; spx_istat.noconn++; goto drop; } spx_template(cb); dropsocket = 0; /* committed to socket */ cb->s_did = si->si_sid; cb->s_rack = si->si_ack; cb->s_ralo = si->si_alo; #define THREEWAYSHAKE #ifdef THREEWAYSHAKE cb->s_state = TCPS_SYN_RECEIVED; cb->s_force = 1 + SPXT_KEEP; spxstat.spxs_accepts++; cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; } break; case TCPS_SYN_RECEIVED: { /* * This state means that we have heard a response to our * acceptance of their connection. It is probably logically * unnecessary in this implementation. */ if (si->si_did != cb->s_sid) { spx_istat.wrncon++; goto drop; } #endif ipxp->ipxp_fport = si->si_sport; cb->s_timer[SPXT_REXMT] = 0; cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; soisconnected(so); cb->s_state = TCPS_ESTABLISHED; spxstat.spxs_accepts++; } break; case TCPS_SYN_SENT: /* * This state means that we have gotten a response to our * attempt to establish a connection. We fill in the data * from the other side, telling us which port to respond to, * instead of the well-known one we might have sent to in the * first place. We also require that this is a response to * our connection id. */ if (si->si_did != cb->s_sid) { spx_istat.notme++; goto drop; } spxstat.spxs_connects++; cb->s_did = si->si_sid; cb->s_rack = si->si_ack; cb->s_ralo = si->si_alo; cb->s_dport = ipxp->ipxp_fport = si->si_sport; cb->s_timer[SPXT_REXMT] = 0; cb->s_flags |= SF_ACKNOW; soisconnected(so); cb->s_state = TCPS_ESTABLISHED; /* * Use roundtrip time of connection request for initial rtt. */ if (cb->s_rtt) { cb->s_srtt = cb->s_rtt << 3; cb->s_rttvar = cb->s_rtt << 1; SPXT_RANGESET(cb->s_rxtcur, ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, SPXTV_MIN, SPXTV_REXMTMAX); cb->s_rtt = 0; } }