/* * 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; }