📄 net.c
字号:
/*************************************************************************** * function_name.c - Software Radio template module * ------------------- * begin : 2003 * authors : Linus Gasser * emails : linus.gasser@epfl.ch ***************************************************************************//*************************************************************************** * Changes * ------- * date - name - description * 03/05/02 - ineiti - make new sending-algorithm * 03/05/19 - ineiti - start over with snull * **************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************//* ------------------------------------------------------------------------ * -----------------------------------------------------------------------*/#ifndef USER_SPACE#include <linux/netdevice.h> /* struct device, and other headers */#include <linux/etherdevice.h>#include <linux/ip.h> /* struct iphdr */#include <linux/tcp.h> /* struct tcphdr */#include <linux/in6.h>#include <asm/uaccess.h>#include <asm/checksum.h>#endif#include "spc.h"#include "tcpip.h"#include "net.h"#include "buf.h"#include "std.h"#define DBG_LVL 4/** * Some network-related functions for the tcpip-device */#ifndef USER_SPACEint net_k_eth;extern struct net_device net_k_devs[];/* * Open and close */int net_k_open(struct net_device *dev) { char str[16]; MOD_INC_USE_COUNT; /* * Assign the hardware address of the board: use "\0SNULx", where * x is 0 or 1. The first byte is '\0' to avoid being a multicast * address (the first byte of multicast addrs is odd). */ memcpy(dev->dev_addr, "\0SNUL0", ETH_ALEN); dev->dev_addr[ETH_ALEN-1] += (dev == net_k_devs); /* the number */ memcpy( str, dev->dev_addr, ETH_ALEN ); str[ ETH_ALEN ] = 0; PR_DBG( 4, "Mac-adress is: %s\n", str + 1 ); netif_start_queue(dev); return 0;}int net_k_release(struct net_device *dev) { /* release ports, irq and such -- like fops->close */ netif_stop_queue(dev); /* can't transmit any more */ MOD_DEC_USE_COUNT; /* if irq2dev_map was used (2.0 kernel), zero the entry here */ return 0;}/* * Configuration changes (passed on by ifconfig) */int net_k_config(struct net_device *dev, struct ifmap *map) { if (dev->flags & IFF_UP) /* can't act on a running interface */ return -EBUSY; /* Don't allow changing the I/O address */ if (map->base_addr != dev->base_addr) { PR_DBG( 0, "snull: Can't change I/O address\n"); return -EOPNOTSUPP; } /* Allow changing the IRQ */ if (map->irq != dev->irq) { dev->irq = map->irq; /* request_irq() is delayed to open-time */ } /* ignore other fields */ return 0;}/* * Receive a packet: retrieve, encapsulate and pass over to upper levels */void net_k_rx(struct net_device *dev, int len, unsigned char *buf) { struct sk_buff *skb; struct net_priv *priv = (struct net_priv *) dev->priv; /* * The packet has been retrieved from the transmission * medium. Build an skb around it, so upper layers can handle it */ skb = dev_alloc_skb(len+2); if (!skb) { PR_DBG( 0,"snull rx: low on mem - packet dropped\n"); priv->stats.rx_dropped++; return; } skb_reserve(skb, 2); /* align IP on 16B boundary */ memcpy(skb_put(skb, len), buf, len); /* Write metadata, and then pass to the receive level */ skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ priv->stats.rx_packets++; priv->stats.rx_bytes += len; netif_rx(skb); return;}/* * Transmit a packet (low level interface) */void net_k_hw_tx(char *buf, int len, struct net_device *dev) { /* * This function deals with hw details. This interface loops * back the packet to the other snull interface (if any). * In other words, this function implements the snull behaviour, * while all other procedures are rather device-independent */ struct iphdr *ih; struct net_device *dest; struct net_priv *priv; u32 *saddr, *daddr; /* I am paranoid. Ain't I? */ if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { PR_DBG( 0,"snull: Hmm... packet too short (%i octets)\n", len); return; } if (0) { /* enable this conditional to look at the data */ int i; PR_DBG( 0, "len is %i\ndata:",len); for (i=14 ; i<len; i++) PR_DBG( 0," %02x",buf[i]&0xff); PR_DBG( 0, "\n"); } /* * 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)); saddr = &ih->saddr; daddr = &ih->daddr; ((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */ ((u8 *)daddr)[2] ^= 1; ih->check = 0; /* and rebuild the checksum (ip needs it) */ ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl); if (dev == net_k_devs) { PR_DBG( 0, "%08x:%05i --> %08x:%05i\n", ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source), ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest)); } else { PR_DBG( 0, "%08x:%05i <-- %08x:%05i\n", ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest), ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source)); } /* * Ok, now the packet is ready for transmission: first simulate a * receive interrupt on the twin device, then a * transmission-done on the transmitting device */ dest = net_k_devs + ( dev==net_k_devs ? 1 : 0 ); priv = (struct net_priv *) dest->priv; priv->status = NET_RX_INTR; priv->rx_packetlen = len; priv->rx_packetdata = buf; spin_lock(&priv->lock) ; net_k_rx(dest, priv->rx_packetlen, priv->rx_packetdata); spin_unlock(&priv->lock) ; priv = (struct net_priv *) dev->priv; priv->status = NET_TX_INTR; priv->tx_packetlen = len; priv->tx_packetdata = buf; spin_lock(&priv->lock) ; priv->stats.tx_packets++; priv->stats.tx_bytes += priv->tx_packetlen; dev_kfree_skb(priv->skb); spin_unlock(&priv->lock) ;}/* * Transmit a packet (called by the kernel) */int net_k_tx(struct sk_buff *skb, struct net_device *dev) { int len; char *data; struct net_priv *priv = (struct net_priv *) dev->priv; len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; data = skb->data; 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 */ net_k_hw_tx(data, len, dev); return 0; /* Our simple device can not fail */}/* * Return statistics to the caller */struct net_device_stats *net_k_stats(struct net_device *dev) { struct net_priv *priv = (struct net_priv *) dev->priv; return &priv->stats;}/* * This function is called to fill up an eth header, since arp is not * available on the interface */int net_k_rebuild_header(struct sk_buff *skb) { struct ethhdr *eth = (struct ethhdr *) skb->data; struct net_device *dev = skb->dev; PR_DBG( 0, "Rebuild\n" ); memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memcpy(eth->h_dest, dev->dev_addr, dev->addr_len); eth->h_dest[ETH_ALEN-1] ^= 0x01; /* dest is us xor 1 */ return 0;}int net_k_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned int len) { struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN); PR_DBG( 0, "hard header\n" ); eth->h_proto = htons(type); memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len); memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len); eth->h_dest[ETH_ALEN-1] ^= 0x01; /* dest is us xor 1 */ return (dev->hard_header_len);}/* * The init function (sometimes called probe). * It is invoked by register_netdev() */int net_k_init(struct net_device *dev) { /* * Then, assign other fields in dev, using ether_setup() and some * hand assignments */ ether_setup(dev); /* assign some of the fields */ dev->open = net_k_open; dev->stop = net_k_release; dev->set_config = net_k_config; dev->hard_start_xmit = net_k_tx; dev->get_stats = net_k_stats; dev->rebuild_header = net_k_rebuild_header; dev->hard_header = net_k_header; /* keep the default flags, just add NOARP */ dev->flags |= IFF_NOARP; dev->hard_header_cache = NULL; /* Disable caching */ SET_MODULE_OWNER(dev); return 0;}/* * The devices */struct net_device net_k_devs[MAX_RF_PORTS];/* * Finally, the module stuff */int net_k_init_module( void ) { int result, device_present = 0, d; struct net_device *dev; for ( d = 0; d < MAX_RF_PORTS; d++ ) { dev = net_k_devs + d; dev->init = net_k_init; /* * Then, allocate the priv field. This encloses the statistics * and a few private fields. */ dev->priv = swr_malloc(sizeof(struct net_priv)); if (dev->priv == NULL) { return -ENOMEM; } memset(dev->priv, 0, sizeof(struct net_priv)); spin_lock_init(& ((struct net_priv *) dev->priv)->lock) ; strcpy( dev->name, "msr%d" ); if ( (result = register_netdev(dev)) ) { PR_DBG( 0,"snull: error %i registering device \"%s\"\n", result, dev->name); } else { device_present++; } } return ( device_present == MAX_RF_PORTS ) ? 0 : -ENODEV;}void net_k_cleanup( void ) { int d; for ( d=0; d<MAX_RF_PORTS; d++ ) { swr_free( net_k_devs[d].priv); unregister_netdev( net_k_devs + d ); } return;}#endif/* * Generate a packet */int net_tx( struct buffer_t *buf ) { char *data;#define USER_LEN 2048 data = swr_malloc( USER_LEN + 2 ); *((u16*)data) = USER_LEN; *((U32*)(data + 2)) = swr_crc32_struct( data + 2, USER_LEN ); PR_DBG( 4, "Crc calculated: %x\n", *((U32*)(data + 2) ) ); buf_net_to_rf( buf, data, USER_LEN + 2 ); swr_free( data ); return 0;}/** * @short sends a packet to the kernel * * Takes a packet, makes a nice envelope and sends it to * the kernel. * * @param block the packet * @param len the length in bytes */void net_send_to_kernel( struct net_device *dev, char *buf, int len ) { U32 crc, crc_rcvd; crc_rcvd = *((U32*)buf); crc = swr_crc32_struct( buf, len ); PR_DBG( 4, "Crc rcvd: %x, calculated: %x\n", crc_rcvd, crc ); if ( crc != crc_rcvd ) { PR_DBG( 0, "Fatal: wrongly received packet!\n" ); } else {#ifndef USER_SPACE net_k_rx( dev, len, buf + 4 );#endif }}/** * The initialisation function called by an insmod tcpip */int net_init( ) {#ifndef USER_SPACE return net_k_init_module( );#else // dev->priv = swr_malloc( sizeof( struct net_priv ) ); return 0;#endif}/** * The cleanup function called when rmmod tcpip */void net_cleanup( ) {#ifndef USER_SPACE net_k_cleanup( );#else // swr_free( dev->priv );#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -