Exemplo n.º 1
0
STATIC streamscall int
ip2xinet_lrput(queue_t *q, mblk_t *mp)
{
	struct iocblk *iocp;
	union DL_primitives *dp;
	struct ip2xinet_priv *privptr;
	struct net_device *dev;
	int i;

	spin_lock(&ip2xinet_lock);

	/* use the first open ip device */
	for (i = 0; i < NUMIP2XINET; i++) {
		privptr = &ip2xinet_devs[i].priv;

		if (privptr->state == 1)
			break;
	}
	if (i == NUMIP2XINET)
		i = 0;		/* All devices closed, pick the 1st one */
	/* send data up to ip through the 1st open device */
	dev = &ip2xinet_devs[i].dev;

	switch (mp->b_datap->db_type) {
	case M_CTL:
		freemsg(mp);
		break;

	case M_DATA:
		/* NOTE: We don't expect any M_DATA messages from xinet */
		freemsg(mp);
		break;

	case M_PROTO:
	case M_PCPROTO:
		dp = (union DL_primitives *) mp->b_rptr;

#if 0
#ifdef DEBUG
		printk("ip2xinet_lrput: %s size=%d\n", x25dbdlpmsg(dp->dl_primitive),
		       x25dbmsgsize(mp));
#endif
#endif

		switch (dp->dl_primitive) {
		case DL_BIND_ACK:

			/* if we're in in BNDPND and receive a BIND_ACK we go to IDLE */
			ip2xinet_status.ip2x_dlstate = DL_IDLE;

			/* If we're DL_IDLE, then dev is open and the kernel can transmit */
			for (i = 0; i < NUMIP2XINET; i++) {
				privptr = &ip2xinet_devs[i].priv;

				if (privptr->state == 1)
					netif_start_queue(&(ip2xinet_devs[i].dev));
			}
			freemsg(mp);	/* Frees bind_ack no longer needed */
			break;

		case DL_INFO_ACK:

			/* NOTE: currently we don't send info_req to xinet */

			freemsg(mp);
			break;

		case DL_ERROR_ACK:
			switch (ip2xinet_status.ip2x_dlstate) {
			case DL_ATTACH_PENDING:
				/* if we receive ERROR_ACK and we're in ATTACH_PEND go into
				   UNATTACHED */
				ip2xinet_status.ip2x_dlstate = DL_UNATTACHED;
				freemsg(mp);
				break;

			case DL_BIND_PENDING:
				/* if we're in BNDPND and receive an ERR ack we go to UNBND, */
				ip2xinet_status.ip2x_dlstate = DL_UNBOUND;
				freemsg(mp);
				break;

			case DL_UNBIND_PENDING:
				/* If we're in UNBIND_PEND and we receive ERROR_ACK we go into IDLE 
				 */
				ip2xinet_status.ip2x_dlstate = DL_IDLE;
				freemsg(mp);
				break;

			case DL_DETACH_PENDING:
				/* If we're in DETACH_PEND and receive and ERROR_ACK we go into
				   UNBND */
				ip2xinet_status.ip2x_dlstate = DL_UNBOUND;
				freemsg(mp);
				break;
			default:
				freemsg(mp);
				break;

			}
			break;

		case DL_UNITDATA_IND:
			/* if we're in IDLE we can get DL_UNITDATA_IND with data and call the guy
			   who would normally receive data from interrupt handler. */

			/* Check state: can't transmit if dev is closed :-) Note: we have to check
			   both the dlpi state and dev->start because during a close the DLPI state 
			   could remain DL_IDLE if we couldn't allocate mblk for UNBIND_REQ. There
			   are many ways in which the dev->start could be 1 but dlpi state - not
			   DL_IDLE. */
			if (ip2xinet_status.ip2x_dlstate == DL_IDLE && privptr->state == 1)
			{
				mblk_t *newmp;
				unsigned char *buf;
				int len, tmplen;
				struct ethhdr *eth;
				struct sk_buff *skb;

				newmp = unlinkb(mp);

				freemsg(mp);
				mp = newmp;

				/* 1st pass through.  figure out the len */
				for (len = sizeof(struct ethhdr); newmp != NULL;
				     newmp = newmp->b_cont)
					len += (newmp->b_wptr - newmp->b_rptr);

				/* ALLOCATE skb of length len+2, COPY from mp chain to skb */

				skb = dev_alloc_skb(len + 2);
				if (!skb) {
					printk("ip2xinet rx: failed to allocate an skb\n");
					freemsg(mp);
					break;
				}
				skb_reserve(skb, 2);	/* align IP on 16B boundary */
				/* The packet has been retrieved from the transmission medium.
				   Build an skb around it, so upper layers can handle it */
				buf = skb_put(skb, len);
				for (newmp = mp, tmplen = sizeof(struct ethhdr); newmp != NULL;
				     newmp = newmp->b_cont) {
					bcopy(newmp->b_rptr, buf + tmplen,
					      newmp->b_wptr - newmp->b_rptr);
					tmplen += (newmp->b_wptr - newmp->b_rptr);
				}
				eth = (struct ethhdr *) buf;

				/* I am not sure it's necessary, but just in case... */

				memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
				memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
				eth->h_proto = 0x8;	/* ETH_P_IP in network order */
				eth->h_source[ETH_ALEN - 1] ^= 0x01;	/* say src is us xor 1 */

				/* send it to ip2xinet_rx for handling */
				ip2xinet_rx(dev, skb);
			}
			freemsg(mp);
			break;
		case DL_UDERROR_IND:
			freemsg(mp);
			break;

		case DL_OK_ACK:
			switch (dp->ok_ack.dl_correct_primitive) {

			case DL_ATTACH_REQ:
				/* if we're in ATTACH_PEND and we received OK_ACK1 change state to
				   UNBND */
				ip2xinet_status.ip2x_dlstate = DL_UNBOUND;
				freemsg(mp);
				/* We just completed building up the X.25 stack below us. If IP is
				   already above us, we need to send down the bind that we would
				   normally do when IP opens us.  This allows us to restart the
				   X.25 stack without restarting TCP/IP. */
				if (ip2xinet_num_ip_opened != 0)
					ip2xinet_send_down_bind(WR(q));
				break;

			case DL_UNBIND_REQ:
				/* If we're in UNBIND_PEND and receive OK_ACK1 we go to UNBND. */
				ip2xinet_status.ip2x_dlstate = DL_UNBOUND;
				freemsg(mp);
				break;

			case DL_DETACH_REQ:
				/* If we're in DETACH_PEND and receive OK_ACK1 we go to UNATT */
				ip2xinet_status.ip2x_dlstate = DL_UNATTACHED;
				freemsg(mp);
				break;

			default:
				freemsg(mp);
				break;
			}
			break;

		default:
			printk("ip2xinet_lrput: bad prim=0x%lx", (ulong) dp->dl_primitive);
			freemsg(mp);
			break;
		}
		break;

	case M_FLUSH:
		if (mp->b_rptr[0] & FLUSHR) {
			if (mp->b_rptr[0] & FLUSHBAND)
				flushband(q, mp->b_rptr[1], FLUSHDATA);
			else
				flushq(q, FLUSHDATA);
			qenable(q);
		}
		if (mp->b_rptr[0] & FLUSHW) {
			mp->b_rptr[0] &= ~FLUSHR;
			if (mp->b_rptr[0] & FLUSHBAND)
				flushband(WR(q), mp->b_rptr[1], FLUSHDATA);
			else
				flushq(WR(q), FLUSHDATA);
			qenable(WR(q));
			if (!putq(WR(q), mp)) {
				mp->b_band = 0;
				putq(WR(q), mp);
			}
		} else
			freemsg(mp);
		break;

	case M_HANGUP:
		/* send it to the guy that linked us up, what he does is his problem. */
		if (!putq(ip2xinet_status.readq, mp)) {
			mp->b_band = 0;
			putq(ip2xinet_status.readq, mp);
		}
		break;

	case M_IOCACK:
		iocp = (struct iocblk *) mp->b_rptr;
		if (iocp->ioc_cmd == SIOCSIFMTU) {
			/* The set MTU ioctl was a success Rejoice :-) */
			freemsg(mp);
		} else if (!putq(ip2xinet_status.readq, mp)) {
			mp->b_band = 0;
			putq(ip2xinet_status.readq, mp);
		}
		break;

	case M_IOCNAK:
		iocp = (struct iocblk *) mp->b_rptr;
		if (iocp->ioc_cmd == SIOCSIFMTU) {
			/* The set MTU ioctl was a failure From looking at xinet code this is *
			   impossible, so ignore it */

			freemsg(mp);
		} else if (!putq(ip2xinet_status.readq, mp)) {
			mp->b_band = 0;
			putq(ip2xinet_status.readq, mp);
		}
		break;

	default:
		printk("ip2xinet_lrput: bad type=%d", mp->b_datap->db_type);
		freemsg(mp);
		break;
	}

	spin_unlock(&ip2xinet_lock);
	return (0);
}
Exemplo n.º 2
0
/*
 * dm2s_wput - Streams write side put routine.
 *
 * All M_DATA messages are queued so that they are transmitted in
 * the service procedure. This is done to simplify the streams
 * synchronization. Other messages are handled appropriately.
 */
int
dm2s_wput(queue_t *wq, mblk_t *mp)
{
	dm2s_t	*dm2sp = (dm2s_t *)wq->q_ptr;

	DPRINTF(DBG_DRV, ("dm2s_wput: called\n"));
	if (dm2sp == NULL) {
		return (ENODEV);   /* Can't happen. */
	}

	switch (mp->b_datap->db_type) {
	case (M_DATA):
		DPRINTF(DBG_DRV, ("dm2s_wput: M_DATA message\n"));
		while (mp->b_wptr == mp->b_rptr) {
			mblk_t *mp1;

			mp1 = unlinkb(mp);
			freemsg(mp);
			mp = mp1;
			if (mp == NULL) {
				return (0);
			}
		}

		/*
		 * Simply queue the message and handle it in the service
		 * procedure.
		 */
		(void) putq(wq, mp);
		qenable(wq);
		return (0);

	case (M_PROTO):
		DPRINTF(DBG_DRV, ("dm2s_wput: M_PROTO message\n"));
		/* We don't expect this */
		mp->b_datap->db_type = M_ERROR;
		mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
		*mp->b_wptr++ = EPROTO;
		qreply(wq, mp);
		return (EINVAL);

	case (M_IOCTL):
		DPRINTF(DBG_DRV, ("dm2s_wput: M_IOCTL message\n"));
		if (MBLKL(mp) < sizeof (struct iocblk)) {
			freemsg(mp);
			return (0);
		}
		/*
		 * No ioctls required to be supported by this driver, so
		 * return EINVAL for all ioctls.
		 */
		miocnak(wq, mp, 0, EINVAL);
		break;

	case (M_CTL):
		DPRINTF(DBG_DRV, ("dm2s_wput: M_CTL message\n"));
		/*
		 * No M_CTL messages need to supported by this driver,
		 * so simply ignore them.
		 */
		freemsg(mp);
		break;

	case (M_FLUSH):
		DPRINTF(DBG_DRV, (
		    "dm2s_wput: M_FLUSH message 0x%X\n", *mp->b_rptr));
		if (*mp->b_rptr & FLUSHW) {	/* Flush write-side */
			(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key,
			    MB_FLUSH_SEND);
			flushq(wq, FLUSHDATA);
			*mp->b_rptr &= ~FLUSHW;
		}
		if (*mp->b_rptr & FLUSHR) {
			(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key,
			    MB_FLUSH_RECEIVE);
			flushq(RD(wq), FLUSHDATA);
			qreply(wq, mp);
		} else {
			freemsg(mp);
		}
		break;

	default:
		DPRINTF(DBG_DRV, ("dm2s_wput: UNKNOWN message\n"));
		freemsg(mp);

	}
	return (0);
}
Exemplo n.º 3
0
    static int
dlpi_rput( queue_t *q, mblk_t *m )
{
    struct atif_data	*aid = (struct atif_data *)q->q_ptr;
    union DL_primitives	*dl;
    mblk_t		*m0;
    struct llc		*llc;

    switch ( m->b_datap->db_type ) {
    case M_IOCNAK :
	putnext( q, m );
	return( 0 );

    case M_PCPROTO :
    case M_PROTO :
	if ( m->b_wptr - m->b_rptr < sizeof( dl->dl_primitive )) {
	    break;
	}
	dl = (union DL_primitives *)m->b_rptr;
	switch ( dl->dl_primitive ) {
	case DL_UNITDATA_IND :
	    if ( m->b_wptr - m->b_rptr < sizeof( DL_UNITDATA_IND_SIZE )) {
		break;
	    }
	    if (( m0 = unlinkb( m )) == NULL ) {
		break;
	    }
	    if ( m0->b_wptr - m0->b_rptr < sizeof( struct llc )) {
		freemsg( m0 );
		break;
	    }
	    llc = (struct llc *)m0->b_rptr;
	    if ( llc->llc_dsap != LLC_SNAP_LSAP ||
		    llc->llc_ssap != LLC_SNAP_LSAP ||
		    llc->llc_control != LLC_UI ) {
		freemsg( m0 );
		break;
	    }

	    if ( bcmp( llc->llc_org_code, at_org_code,
		    sizeof( at_org_code )) == 0 &&
		    ntohs( llc->llc_ether_type ) == ETHERTYPE_AT ) {
		adjmsg( m0, sizeof( struct llc ));
		ddp_rput( aid, m0 );
	    } else if ( bcmp( llc->llc_org_code, aarp_org_code,
		    sizeof( aarp_org_code )) == 0 &&
		    ntohs( llc->llc_ether_type ) == ETHERTYPE_AARP ) {
		adjmsg( m0, sizeof( struct llc ));
		aarp_rput( q, m0 );
	    } else {
		freemsg( m0 );
	    }
	    break;

	case DL_OK_ACK :
	    if ( m->b_wptr - m->b_rptr < sizeof( DL_OK_ACK_SIZE )) {
		break;
	    }
	    switch ( dl->ok_ack.dl_correct_primitive ) {
	    case DL_ATTACH_REQ :
		if ( aid->aid_state != DL_ATTACH_PENDING ) {
		    cmn_err( CE_NOTE, "dlpi_rput DL_OK_ACK attach state %d\n",
			    aid->aid_state );
		    break;
		}
		if ( aid->aid_c.c_type != IF_UNITSEL ) {
		    cmn_err( CE_NOTE, "dlpi_rput DL_OK_ACK attach context %x\n",
			    aid->aid_c.c_type );
		    break;
		}

		if ( WR(q)->q_next == NULL || WR(q)->q_next->q_qinfo == NULL ||
			WR(q)->q_next->q_qinfo->qi_minfo == NULL ||
			WR(q)->q_next->q_qinfo->qi_minfo->mi_idname == NULL ) {
		    cmn_err( CE_NOTE, "dlpi_rput can't get interface name\n" );
		    break;
		}

		if_name( aid, WR(q)->q_next->q_qinfo->qi_minfo->mi_idname,
			aid->aid_c.c_u.u_unit.uu_ppa );

		aid->aid_state = DL_BIND_PENDING;

#ifdef i386
		/*
		 * As of Solaris 7 (nice name), the i386 arch needs to be
		 * bound as 0 to receive 802 frames.  However, in the same
		 * OS, Sparcs must be bound as ETHERMTU (or at least not 0)
		 * to receive the same frames.  A bug?  In the Solaris 7
		 * (nice name) kernel?
		 */
		dl_bind_req( WR( q ), 0 );
#else /* i386 */
		dl_bind_req( WR( q ), ETHERMTU );
#endif /* i386 */
		break;

	    case DL_ENABMULTI_REQ :
		if ( aid->aid_c.c_type != SIOCADDMULTI ) {
		    cmn_err( CE_NOTE,
			    "dlpi_rput DL_OK_ACK enabmulti context %x\n",
			    aid->aid_c.c_type );
		    break;
		}

		ioc_ok_ack( aid->aid_c.c_u.u_multi.um_q,
			aid->aid_c.c_u.u_multi.um_m, 0 );
		aid->aid_c.c_type = 0;
		aid->aid_c.c_u.u_multi.um_q = NULL;
		aid->aid_c.c_u.u_multi.um_m = 0;
		break;

	    default :
		cmn_err( CE_CONT, "!dlpi_rput DL_OK_ACK unhandled %d\n",
			dl->ok_ack.dl_correct_primitive );
		break;
	    }
	    break;

	case DL_BIND_ACK :
	    if ( m->b_wptr - m->b_rptr < sizeof( DL_BIND_ACK_SIZE )) {
		break;
	    }
	    if ( aid->aid_state != DL_BIND_PENDING ) {
		break;
	    }
	    if ( aid->aid_c.c_type != IF_UNITSEL ) {
		break;
	    }
	    bcopy( m->b_rptr + dl->bind_ack.dl_addr_offset, aid->aid_hwaddr, 
		    dl->bind_ack.dl_addr_length );
	    aid->aid_state = DL_IDLE;
	    ioc_ok_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m, 0 );
	    aid->aid_c.c_type = 0;
	    aid->aid_c.c_u.u_unit.uu_m = NULL;
	    aid->aid_c.c_u.u_unit.uu_ppa = 0;
	    break;

	case DL_ERROR_ACK :
	    if ( m->b_wptr - m->b_rptr < sizeof( DL_ERROR_ACK_SIZE )) {
		break;
	    }

	    switch ( aid->aid_c.c_type ) {
	    case IF_UNITSEL :
		if ( dl->error_ack.dl_errno == DL_SYSERR ) {
		    ioc_error_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m,
			    dl->error_ack.dl_unix_errno );
		} else {
		    cmn_err( CE_CONT, "dlpi_rput DL_ERROR_ACK 0x%x\n",
			    dl->error_ack.dl_errno );
		    ioc_error_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m, EINVAL );
		}
		aid->aid_c.c_type = 0;
		aid->aid_c.c_u.u_unit.uu_m = NULL;
		aid->aid_c.c_u.u_unit.uu_ppa = 0;
		break;

	    default :
		cmn_err( CE_NOTE, "dlpi_rput DL_ERROR_ACK unhandled %d %d %d\n",
			dl->error_ack.dl_error_primitive,
			dl->error_ack.dl_errno, dl->error_ack.dl_unix_errno );
		break;
	    }
	    break;

	default :
	    cmn_err( CE_NOTE, "dlpi_rput M_PCPROTO 0x%x\n", dl->dl_primitive );
	    break;
	}
	break;

    default :
	cmn_err( CE_NOTE, "dlpi_rput 0x%X\n", m->b_datap->db_type );
	break;
    }

    freemsg( m );
    return( 0 );
}
Exemplo n.º 4
0
/*
 * start data transmit
 */
static void
uftdi_tx_start(uftdi_state_t *uf, int *xferd)
{
	int		len;		/* bytes we can transmit */
	mblk_t		*data;		/* data to be transmitted */
	int		data_len;	/* bytes in 'data' */
	mblk_t		*mp;		/* current msgblk */
	int		copylen;	/* bytes copy from 'mp' to 'data' */
	int		rval;

	USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_tx_start");
	ASSERT(mutex_owned(&uf->uf_lock));
	ASSERT(uf->uf_port_state != UFTDI_PORT_CLOSED);

	if (xferd)
		*xferd = 0;
	if ((uf->uf_port_flags & UFTDI_PORT_TX_STOPPED) ||
	    uf->uf_tx_mp == NULL) {
		return;
	}
	if (uf->uf_bulkout_state != UFTDI_PIPE_IDLE) {
		USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh,
		    "uftdi_tx_start: pipe busy");
		return;
	}
	ASSERT(MBLKL(uf->uf_tx_mp) > 0);

	/* send as much data as port can receive */
	len = min(msgdsize(uf->uf_tx_mp), uf->uf_xfer_sz);

	if (len <= 0)
		return;
	if ((data = allocb(len, BPRI_LO)) == NULL)
		return;

	/*
	 * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'
	 */
	data_len = 0;
	while (data_len < len && uf->uf_tx_mp) {
		mp = uf->uf_tx_mp;
		copylen = min(MBLKL(mp), len - data_len);
		bcopy(mp->b_rptr, data->b_wptr, copylen);
		mp->b_rptr += copylen;
		data->b_wptr += copylen;
		data_len += copylen;

		if (MBLKL(mp) < 1) {
			uf->uf_tx_mp = unlinkb(mp);
			freeb(mp);
		} else {
			ASSERT(data_len == len);
		}
	}

	ASSERT(data_len > 0);

	uf->uf_bulkout_state = UFTDI_PIPE_BUSY;
	mutex_exit(&uf->uf_lock);

	rval = uftdi_send_data(uf, data);
	mutex_enter(&uf->uf_lock);

	if (rval != USB_SUCCESS) {
		uf->uf_bulkout_state = UFTDI_PIPE_IDLE;
		uftdi_put_head(&uf->uf_tx_mp, data);
	} else {
		if (xferd)
			*xferd = data_len;
	}
}