コード例 #1
0
static int
net_send_packet(struct sk_buff *skb, struct device *dev)
{
	struct net_local *lp = (struct net_local *)dev->priv;
	int ioaddr = dev->base_addr;

	if (dev->tbusy) {
		/* If we get here, some higher level has decided we are broken.
		   There should really be a "kick me" function call instead. */
		int tickssofar = jiffies - dev->trans_start;
		if (tickssofar < 5)
			return 1;
		printk("%s: transmit timed out, %s?\n", dev->name,
			   tx_done(dev) ? "IRQ conflict" : "network cable problem");
		/* Try to restart the adaptor. */
		chipset_init(dev, 1);
		dev->tbusy=0;
		dev->trans_start = jiffies;
	}

	/* If some higher layer thinks we've missed an tx-done interrupt
	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
	   itself. */
	if (skb == NULL) {
		dev_tint(dev);
		return 0;
	}

	/* For ethernet, fill in the header.  This should really be done by a
	   higher level, rather than duplicated for each ethernet adaptor. */
	if (!skb->arp  &&  dev->rebuild_header(skb->data, dev)) {
		skb->dev = dev;
		arp_queue (skb);
		return 0;
	}
	skb->arp=1;

	/* Block a timer-based transmit from overlapping.  This could better be
	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
	if (set_bit(0, (void*)&dev->tbusy) != 0)
		printk("%s: Transmitter access conflict.\n", dev->name);
	else {
		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
		unsigned char *buf = skb->data;

		hardware_send_packet(ioaddr, buf, length);
		dev->trans_start = jiffies;
	}
	if (skb->free)
		kfree_skb (skb, FREE_WRITE);

	/* You might need to clean up and record Tx statistics here. */
	if (inw(ioaddr) == /*RU*/81)
		lp->stats.tx_aborted_errors++;

	return 0;
}
コード例 #2
0
ファイル: 3c501.c プロジェクト: DreamLiMu/Linux-Kernel-Study
static int
el_start_xmit(struct sk_buff *skb, struct device *dev)
{

    if (dev->tbusy) {
	if (jiffies - dev->trans_start < 20) {
	    if (el_debug > 2)
		printk(" transmitter busy, deferred.\n");
	    return 1;
	}
	if (el_debug)
	    printk ("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
		    dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS));
	el_status.stats.tx_errors++;
#ifdef oldway
	el_reset(dev);
#else
	outb(TX_NORM, TX_CMD);
	outb(RX_NORM, RX_CMD);
	outb(AX_OFF, AX_CMD);	/* Just trigger a false interrupt. */
#endif
	outb(AX_RX, AX_CMD);	/* Aux control, irq and receive enabled */
	dev->tbusy = 0;
	dev->trans_start = jiffies;
    }

    if (skb == NULL) {
	dev_tint(dev);
	return 0;
    }

    /* Fill in the ethernet header. */
    if (!skb->arp  &&  dev->rebuild_header(skb->data, dev)) {
	skb->dev = dev;
	arp_queue (skb);
	return 0;
    }
    skb->arp=1;

    if (skb->len <= 0)
	return 0;

    /* Avoid timer-based retransmission conflicts. */
    if (set_bit(0, (void*)&dev->tbusy) != 0)
	printk("%s: Transmitter access conflict.\n", dev->name);
    else {
	int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);
	unsigned char *buf = skb->data;

	el_status.tx_pkt_start = gp_start;
    	el_status.collisions = 0;

	outb(AX_SYS, AX_CMD);
	inb(RX_STATUS);
	inb(TX_STATUS);
	outb(0x00, RX_BUF_CLR);	/* Set rx packet area to 0. */
	outw(gp_start, GP_LOW);
	outsb(DATAPORT,buf,skb->len);
	outw(gp_start, GP_LOW);
	outb(AX_XMIT, AX_CMD);		/* Trigger xmit.  */
	dev->trans_start = jiffies;
    }

    if (el_debug > 2)
	printk(" queued xmit.\n");
    if (skb->free)
	kfree_skb (skb, FREE_WRITE);
    return 0;
}
コード例 #3
0
ファイル: 3c505.c プロジェクト: Lakshmipathi/Linux-historic
static int elp_start_xmit(struct sk_buff *skb, struct device *dev)

{
    elp_device * adapter = (elp_device *) dev->priv;

    CHECK_NULL(dev);

    /*
     * not sure what this does, but the 3c509 driver does it, so...
     */
    if (skb == NULL) {
        dev_tint(dev);
        return 0;
    }

    /*
     * Fill in the ethernet header
     * (for kernels prior to 1.1.4 only)
     */
#if (ELP_KERNEL_TYPE < 2)
    IS_SKB(skb);
    if (!skb->arp && dev->rebuild_header(SKB_DATA, dev)) {
        skb->dev = dev;
        IS_SKB(skb);
        arp_queue (skb);
        return 0;
    }
#endif

    /*
     * if we ended up with a munged length, don't send it
     */
    if (skb->len <= 0)
        return 0;

    if (elp_debug >= 3)
        printk("%s: request to send packet of length %d\n", dev->name, (int)skb->len);

    /*
     * if the transmitter is still busy, we have a transmit timeout...
     */
    if (dev->tbusy) {
        int tickssofar = jiffies - dev->trans_start;
        if (tickssofar < 200) /* was 500, AJT */
            return 1;
        printk("%s: transmit timed out, resetting adapter\n", dev->name);
        if ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0)
            printk("%s: hmmm...seemed to have missed an interrupt!\n", dev->name);
        adapter_reset(adapter);
        dev->trans_start = jiffies;
        dev->tbusy = 0;
    }

    /*
     * send the packet at skb->data for skb->len
     */
    if (!send_packet(adapter, (unsigned char *)SKB_DATA, skb->len)) {
        printk("%s: send packet PCB failed\n", dev->name);
        return 1;
    }

    if (elp_debug >= 3)
        printk("%s: packet of length %d sent\n", dev->name, (int)skb->len);


    /*
     * start the transmit timeout
     */
    dev->trans_start = jiffies;

    /*
     * the transmitter is now busy
     */
    dev->tbusy = 1;

    /*
     * if we have been asked to free the buffer, do so
     */
#if (ELP_KERNEL_TYPE < 4)
    if (skb->free)
    {
        IS_SKB(skb);
        kfree_skb(skb, FREE_WRITE);
    }
#else
    dev_kfree_skb(skb, FREE_WRITE);
#endif

    return 0;
}
コード例 #4
0
ファイル: ether.c プロジェクト: HarryR/sanos
err_t ether_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) {
  struct pbuf *q;
  struct eth_hdr *ethhdr;
  struct eth_addr *dest, mcastaddr;
  struct ip_addr *queryaddr;
  err_t err;
  int i;
  int loopback = 0;

  //kprintf("ether: xmit %d bytes, %d bufs\n", p->tot_len, pbuf_clen(p));

  if ((netif->flags & NETIF_UP) == 0) return -ENETDOWN;

  if (pbuf_header(p, ETHER_HLEN)) {
    kprintf(KERN_ERR "ether_output: not enough room for Ethernet header in pbuf\n");
    stats.link.err++;
    return -EBUF;
  }

  // Construct Ethernet header. Start with looking up deciding which
  // MAC address to use as a destination address. Broadcasts and
  // multicasts are special, all other addresses are looked up in the
  // ARP table.

  queryaddr = ipaddr;
  if (ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, &netif->netmask)) {
    dest = (struct eth_addr *) &ethbroadcast;
  } else if (ip_addr_ismulticast(ipaddr)) {
    // Hash IP multicast address to MAC address.
    mcastaddr.addr[0] = 0x01;
    mcastaddr.addr[1] = 0x0;
    mcastaddr.addr[2] = 0x5e;
    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
    mcastaddr.addr[4] = ip4_addr3(ipaddr);
    mcastaddr.addr[5] = ip4_addr4(ipaddr);
    dest = &mcastaddr;
  } else if (ip_addr_cmp(ipaddr, &netif->ipaddr)) {
    dest = &netif->hwaddr;
    loopback = 1;
  } else {
    if (ip_addr_maskcmp(ipaddr, &netif->ipaddr, &netif->netmask)) {
      // Use destination IP address if the destination is on the same subnet as we are.
      queryaddr = ipaddr;
    } else {
      // Otherwise we use the default router as the address to send the Ethernet frame to.
      queryaddr = &netif->gw;
    }

    dest = arp_lookup(queryaddr);
  }

  // If the arp_lookup() didn't find an address, we send out an ARP query for the IP address.
  if (dest == NULL) {
    q = arp_query(netif, &netif->hwaddr, queryaddr);
    if (q != NULL) {
      err = dev_transmit((dev_t) netif->state, q);
      if (err < 0) {
        kprintf(KERN_ERR "ether: error %d sending arp packet\n", err);
        pbuf_free(q);
        stats.link.drop++;
        return err;
      }
    }

    // Queue packet for transmission, when the ARP reply returns
    err = arp_queue(netif, p, queryaddr);
    if (err < 0) {
      kprintf(KERN_ERR "ether: error %d queueing packet\n", err);
      stats.link.drop++;
      stats.link.memerr++;
      return err;
    }

    return 0;
  }

  ethhdr = p->payload;

  for (i = 0; i < 6; i++) {
    ethhdr->dest.addr[i] = dest->addr[i];
    ethhdr->src.addr[i] = netif->hwaddr.addr[i];
  }
  ethhdr->type = htons(ETHTYPE_IP);
  
  if (loopback) {
    struct pbuf *q;

    q = pbuf_dup(PBUF_RAW, p);
    if (!q) return -ENOMEM;

    err = ether_input(netif, q);
    if (err < 0) {
      pbuf_free(q);
      return err;
    }
  } else {
    err = dev_transmit((dev_t) netif->state, p);
    if (err < 0) {
      kprintf(KERN_ERR "ether: error %d sending packet\n", err);
      return err;
    }
  }

  return 0;
}
コード例 #5
0
ファイル: d_link.c プロジェクト: DreamLiMu/Linux-Kernel-Study
/*
 * Copy a buffer to the adapter transmit page memory.
 * Start sending.
 */
static int
d_link_start_xmit(struct sk_buff *skb, struct device *dev)
{
	int		transmit_from;
	int		len;
	int		tickssofar;
	unsigned char	*buffer = skb->data;

	/*
	 * If some higher layer thinks we've missed a
	 * tx-done interrupt we are passed NULL.
	 * Caution: dev_tint() handles the cli()/sti() itself.
	 */

	if (skb == NULL) {
		dev_tint(dev);
		return 0;
	}

	/* For ethernet, fill in the header (hardware addresses) with an arp. */
	if (!skb->arp)
		if(dev->rebuild_header(skb->data, dev)) {
			skb->dev = dev;
			arp_queue (skb);
			return 0;
		}
	skb->arp = 1;

	if (free_tx_pages <= 0) {	/* Do timeouts, to avoid hangs. */
		tickssofar = jiffies - dev->trans_start;

		if (tickssofar < 5)
			return 1;

		/* else */
		printk("%s: transmit timed out (%d), %s?\n",
			dev->name,
			tickssofar,
			"network cable problem"
			);
		/* Restart the adapter. */
		adapter_init(dev);
	}

	/* Start real output */
	PRINTK(("d_link_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages));

	if ((len = skb->len) < RUNT)
		len = RUNT;

	cli();
	select_nic();

	tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
	tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */

	d_link_setup_address(transmit_from, RW_ADDR);
	for ( ; len > 0; --len, ++buffer)
		d_link_put_byte(*buffer);

	if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
		dev->trans_start = jiffies;
		dev->tbusy = 0;	/* allow more packets into adapter */
		/* Send page and generate an interrupt */
		d_link_setup_address(transmit_from, TX_ADDR);
		d_link_put_command(TX_ENABLE);
	}
	else {
		dev->tbusy = !free_tx_pages;
		select_prn();
	}
	
	sti(); /* interrupts back on */
	
	if (skb->free)
		kfree_skb (skb, FREE_WRITE);

	return 0;
}
コード例 #6
0
ファイル: we.c プロジェクト: LambdaCalculus379/SLS-1.02
int
wd8003_start_xmit(struct sk_buff *skb, struct device *dev)
{
  unsigned char cmd;
  int len;

  cli();
  if (dev->tbusy)
    {
       /* put in a time out. */
       if (jiffies - dev->trans_start < 30)
	 {
	   sti();
	   return (1);
	 }

       printk ("wd8003 transmit timed out. \n");
    }
  dev->tbusy = 1;

  if (skb == NULL)
    {
      sti();
      wd_trs(dev);
      return (0);
    }

  /* this should check to see if it's been killed. */
  if (skb->dev != dev)
    {
      sti();
      return (0);
    }


  if (!skb->arp)
    {
      if ( dev->rebuild_header (skb+1, dev)) 
	{
	  cli();
	  if (skb->dev == dev)
	    {
	      arp_queue (skb);
	    }
	   cli (); /* arp_queue turns them back on. */
 	  dev->tbusy = 0;
	   sti();
	   return (0);
	}
    }

  memcpy ((unsigned char *)dev->mem_start, skb+1, skb->len);

  len = skb->len;

  /* now we need to set up the card info. */
  dev->trans_start = jiffies;
  len=max(len, ETHER_MIN_LEN); /* actually we should zero out
				  the extra memory. */
/*  printk ("start_xmit len - %d\n", len);*/

  cmd=inb_p(WD_COMM);
  cmd &= ~CPAGE;
  outb_p(cmd, WD_COMM);

  interrupt_mask |= TRANS_MASK;
  if (!(dev->interrupt))
    outb (interrupt_mask, WD_IMR);

  outb_p(len&0xff,WD_TB0);
  outb_p(len>>8,WD_TB1);
  cmd |= CTRANS;
  outb_p(cmd,WD_COMM);
  sti();
  
  if (skb->free)
    {
	    kfree_skb (skb, FREE_WRITE);
    }

  return (0);
}