On Sun, 10 Jun 2007 14:13:58 +0400, "Denis Kirjanov" <kirjanov@xxxxxxxxx> wrote: > On 6/10/07, Lukas Razik <linux@xxxxxxxxxx> wrote: >> Hello! >> >> I'm new to kernel programming and I try to develop a fake ethernet > driver for >> v2.6.21.3 which I really need based on netdev but I ran into the > following >> issue: >> If the kernel calls the 'dev->hard_start_xmit' function of my driver > then this >> calls another one which try to create a socket in the following "normal > way": >> >> struct socket *ssock = NULL; >> ... >> sock_create(family, SOCK_STREAM, IPPROTO_TCP, &ssock); >> >> But at this point I get an error message from the kernel as appended > below. >> So what have I done wrong? >> >> Regards and many thanks for any help! >> Lukas > Show full source code > Hi Dennis! Here it is (it's based on this one http://www.cs.fsu.edu/~baker/devices/lxr/http/source/ldd-examples/snull/snull.c ). I'll send you the full code as a file. For all others the important part is below. The error occurs in ethos_socket_tx(). Regards, Lukas ... static int timeout = ETHOS_TIMEOUT; module_param(timeout, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); static int family = AF_INET; module_param(family, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); struct ethos_addr_map { u32 ethos_addr; u32 real_addr; }; static const struct ethos_addr_map ethos_addr_maps[] = { /* ethos_addr <-> real_addr */ /* 192.168.10.1 <-> 192.168.0.1 */ {__constant_htonl(0xc0a80a01),__constant_htonl(0xc0a80001)} }; #define ETHOS_ADDR_MAPS_NUM 1 ... static void ethos_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int statusword; struct ethos_priv *priv; struct ethos_packet *pkt = NULL; /* * As usual, check the "device" pointer to be sure it is * really interrupting. * Then assign "struct device *dev" */ struct net_device *dev = (struct net_device *)dev_id; /* ... and check with hw if it's really ours */ /* paranoid */ if (!dev) return; /* Lock the device */ priv = netdev_priv(dev); spin_lock(&priv->lock); /* retrieve statusword: real netdevices use I/O instructions */ statusword = priv->status; priv->status = 0; if (statusword & ETHOS_RX_INTR) { /* send it to ethos_rx for handling */ pkt = priv->rx_queue; if (pkt) { priv->rx_queue = pkt->next; ethos_rx(dev, pkt); } } if (statusword & ETHOS_TX_INTR) { /* If packet was sent... */ if(priv->tx_packetlen) { priv->stats.tx_packets++; priv->stats.tx_bytes += priv->tx_packetlen; } else PNOTICE("packet dropped\n"); // TODO: else info about rejected packet /* a transmission is over: free the skb */ dev_kfree_skb(priv->skb); } /* Unlock the device and we are done */ spin_unlock(&priv->lock); // TODO: maybe if(pkt) kfree(pkt); // if (pkt) ethos_release_buffer(pkt); /* Do this outside the lock! */ return; } static void ethos_socket_tx(char *buf, int len, struct net_device *dev) struct iphdr *ih; struct ethos_priv *priv; struct ethos_packet pkt; struct sockaddr_in saddr; struct socket *ssock = NULL; int ret = -1, i; /* I am paranoid. Ain't I? */ if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { printk("ethos: Hmm... packet too short (%i octets)\n", len); // TODO: buf won't be freed by ethos_interrupt() return; } /* * Ethhdr is 14 bytes, but the kernel arranges for iphdr * to be aligned (i.e., ethhdr is unaligned) */ ih = (struct iphdr *)(buf+sizeof(struct ethhdr)); //TODO: // set pkt /* Trying to map ethos address to real address */ for(i = 0; i < ETHOS_ADDR_MAPS_NUM; i++) if(ethos_addr_maps[i].ethos_addr == ih->daddr) break; /* Didn't find ethos address in the map table */ if(ETHOS_ADDR_MAPS_NUM == i) { PNOTICE("ethos: couldn't map ethos addr %08x\n", ntohl(ih->daddr)); len = 0; goto err_map; } PDEBUG("mapped %08x to %08x\n", ntohl(ih->daddr), ntohl(ethos_addr_maps[i].real_addr)); /* Create send socket */ ret = sock_create(family, SOCK_STREAM, IPPROTO_TCP, &ssock); if(ret < 0) { PERR("couldn't create send socket (ret=%d)\n", ret); len = 0; goto err_sock; } PDEBUG("created send socket (ssock=%0x, family=%d, ret=%d)\n", (unsigned int)ssock, family, ret); len = 0; goto err_connect; /* Connect through send socket */ memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = family; saddr.sin_port = htons(ETHOS_SOCKET_PORT); saddr.sin_addr.s_addr = ethos_addr_maps[i].real_addr; ret = kernel_connect(ssock, (struct sockaddr *) &saddr, sizeof(saddr), O_RDWR); if(ret && (ret != -EINPROGRESS)) { PERR("couldn't connect to %08x:%05d (ret=%d)\n", saddr.sin_addr.s_addr, saddr.sin_port, ret); len = 0; goto err_connect; } /* Receive an answere from pong program */ char *recv_msg = kmalloc(ETHOS_RCVBUF, GFP_KERNEL); read_msg(ssock, recv_msg); printk(KERN_INFO "ethos: server said: %s\n", recv_msg); err_connect: sock_release(ssock); PDEBUG("released send socket (ssock=%0x)\n", (unsigned int)ssock); err_sock: err_map: priv = netdev_priv(dev); priv->tx_packetlen = len; priv->tx_packetdata = buf; priv->status |= ETHOS_TX_INTR; ethos_interrupt(0, dev, NULL); } ... /* * Transmit a packet (called by the kernel) */ int ethos_tx(struct sk_buff *skb, struct net_device *dev) { int len; char *data, shortpkt[ETH_ZLEN]; struct ethos_priv *priv = netdev_priv(dev); data = skb->data; len = skb->len; if (len < ETH_ZLEN) { memset(shortpkt, 0, ETH_ZLEN); memcpy(shortpkt, skb->data, skb->len); len = ETH_ZLEN; data = shortpkt; } dev->trans_start = jiffies; /* save the timestamp */ /* Remember the skb, so we can free it at interrupt time */ priv->skb = skb; /* actual deliver of data is device-specific, and not shown here */ ethos_socket_tx(data, len, dev); return 0; /* Our simple device can not fail */ } ... void ethos_init(struct net_device *dev) { struct ethos_priv *priv; /* * Then, assign other fields in dev, using ether_setup() and some * hand assignments */ ether_setup(dev); /* assign some of the fields */ dev->open = ethos_open; dev->stop = ethos_release; dev->set_config = ethos_config; dev->hard_start_xmit = ethos_tx; dev->do_ioctl = ethos_ioctl; dev->get_stats = ethos_stats; dev->change_mtu = ethos_change_mtu; dev->rebuild_header = ethos_rebuild_header; dev->hard_header = ethos_header; dev->tx_timeout = ethos_tx_timeout; dev->watchdog_timeo = timeout; /* keep the default flags, just add NOARP */ dev->flags |= IFF_NOARP; dev->features |= NETIF_F_NO_CSUM; dev->hard_header_cache = NULL; /* Disable caching */ /* * Then, initialize the priv field. This encloses the statistics * and a few private fields. */ priv = netdev_priv(dev); memset(priv, 0, sizeof(struct ethos_priv)); spin_lock_init(&priv->lock); ethos_rx_ints(dev, 1); /* enable receive interrupts */ } ... int ethos_init_module(void) { int result, i, ret = -ENOMEM; /* Allocate the devices */ ethos_devs[0] = alloc_netdev(sizeof(struct ethos_priv), "eth%d", ethos_init); if (ethos_devs[0] == NULL) goto out; ret = -ENODEV; for (i = 0; i < ETHOS_NUM; i++) if ((result = register_netdev(ethos_devs[i]))) PERR("ethos: error %i registering device \"%s\"\n", result, ethos_devs[i]->name); else ret = 0; out: if (ret) ethos_cleanup_module(); return ret; } -- To unsubscribe from this list: send an email with "unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx Please read the FAQ at http://kernelnewbies.org/FAQ