示例#1
0
/*
 * Create and transmit a management frame using "operation" and "oid",
 * with arguments data/length.
 * We either return an error and free the frame, or we return 0 and
 * islpci_mgt_cleanup_transmit() frees the frame in the tx-done
 * interrupt.
 */
static int
islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid,
		    void *data, int length)
{
	islpci_private *priv = netdev_priv(ndev);
	isl38xx_control_block *cb =
	    (isl38xx_control_block *) priv->control_block;
	void *p;
	int err = -EINVAL;
	unsigned long flags;
	isl38xx_fragment *frag;
	struct islpci_membuf buf;
	u32 curr_frag;
	int index;
	int frag_len = length + PIMFOR_HEADER_SIZE;

#if VERBOSE > SHOW_ERROR_MESSAGES
	DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n");
#endif

	if (frag_len > MGMT_FRAME_SIZE) {
//		printk(KERN_DEBUG "%s: mgmt frame too large %d\n",
;
		goto error;
	}

	err = -ENOMEM;
	p = buf.mem = kmalloc(frag_len, GFP_KERNEL);
	if (!buf.mem) {
//		printk(KERN_DEBUG "%s: cannot allocate mgmt frame\n",
;
		goto error;
	}
	buf.size = frag_len;

	/* create the header directly in the fragment data area */
	pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p);
	p += PIMFOR_HEADER_SIZE;

	if (data)
		memcpy(p, data, length);
	else
		memset(p, 0, length);

#if VERBOSE > SHOW_ERROR_MESSAGES
	{
		pimfor_header_t *h = buf.mem;
		DEBUG(SHOW_PIMFOR_FRAMES,
		      "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x\n",
		      h->operation, oid, h->device_id, h->flags, length);

		/* display the buffer contents for debugging */
		display_buffer((char *) h, sizeof (pimfor_header_t));
		display_buffer(p, length);
	}
#endif

	err = -ENOMEM;
	buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len,
				      PCI_DMA_TODEVICE);
	if (!buf.pci_addr) {
//		printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n",
;
		goto error_free;
	}

	/* Protect the control block modifications against interrupts. */
	spin_lock_irqsave(&priv->slock, flags);
	curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]);
	if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) {
//		printk(KERN_WARNING "%s: mgmt tx queue is still full\n",
;
		goto error_unlock;
	}

	/* commit the frame to the tx device queue */
	index = curr_frag % ISL38XX_CB_MGMT_QSIZE;
	priv->mgmt_tx[index] = buf;
	frag = &cb->tx_data_mgmt[index];
	frag->size = cpu_to_le16(frag_len);
	frag->flags = 0;	/* for any other than the last fragment, set to 1 */
	frag->address = cpu_to_le32(buf.pci_addr);

	/* The fragment address in the control block must have
	 * been written before announcing the frame buffer to
	 * device */
	wmb();
	cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag + 1);
	spin_unlock_irqrestore(&priv->slock, flags);

	/* trigger the device */
	islpci_trigger(priv);
	return 0;

      error_unlock:
	spin_unlock_irqrestore(&priv->slock, flags);
      error_free:
	kfree(buf.mem);
      error:
	return err;
}
static int ntl_transmit(pid_t pid, int seq, int operation, int oid, long *data, unsigned long data_len,
                        int dev_type, int dev_id )
{
    unsigned char *old_tail;
    struct sk_buff *skb;
    struct nlmsghdr *nlh;
    struct pimfor_hdr *pimfor_hdr;
    size_t size;

    int err = 0;
    /* Trap group is mapped to dev_type. */
    unsigned int trapgrp = dev_type;

#ifdef DRIVER_DEBUG
    printk(KERN_INFO "ntl_transmit: pid %d, seq %d, oper %d, oid %d, data ptr %p, data_len %lu, dev_id %d \n",
                       pid, seq, operation, oid, data, data_len, dev_id);
#endif

    if ( nl_sock == NULL ) {
        printk(KERN_ERR "ntl_transmit: no nl_sock\n");
        return -EPFNOSUPPORT;
    }

    size = NLMSG_LENGTH(data_len + sizeof(struct pimfor_hdr));
    skb = alloc_skb(size, GFP_ATOMIC);

    if ( skb ) {

        old_tail = skb->tail;
        nlh = NLMSG_PUT(skb, pid, seq, NETLINK_TYPE_PIMFOR, size - NLMSG_ALIGN(sizeof(struct nlmsghdr)));
        pimfor_hdr = (struct pimfor_hdr *)NLMSG_DATA(nlh);

        pimfor_encode_header(operation, oid, dev_id, 0 /*flags*/, data_len, pimfor_hdr);
        /* Add data after the PIMFOR header */
        memcpy(PIMFOR_DATA(pimfor_hdr), data, data_len);

        nlh->nlmsg_len = skb->tail - old_tail;
        NETLINK_CB(skb).dst_groups = 0;
    } else {

        printk(KERN_ERR "ntl_transmit: alloc_skb failed\n");
        return -EPFNOSUPPORT;
    }

    if (pid != 0 ) {
        err = netlink_unicast(nl_sock, skb, pid, MSG_DONTWAIT);
    } else {
        if (trapgrp) {
            netlink_broadcast(nl_sock, skb, pid, trapgrp ,GFP_ATOMIC );
        }
        else {
            printk(KERN_WARNING "No trap group defined, drop packet.\n");
            kfree_skb(skb);
        }
    }

    return err;

nlmsg_failure:
    if ( skb )
            kfree_skb(skb);
    printk(KERN_ERR "ntl_transmit: NLMSG_PUT failed\n");
    return -EPFNOSUPPORT;
}