📄 wanmain.c
字号:
/****************************************************************************** wanmain.c WAN Multiprotocol Router Module. Main code.** This module is completely hardware-independent and provides* the following common services for the WAN Link Drivers:* o WAN device managenment (registering, unregistering)* o Network interface management* o Physical connection management (dial-up, incoming calls)* o Logical connection management (switched virtual circuits)* o Protocol encapsulation/decapsulation** Author: Gideon Hack ** Copyright: (c) 1995-1999 Sangoma Technologies Inc.** 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.* ============================================================================* Nov 24, 2000 Nenad Corbic Updated for 2.4.X kernels * Nov 07, 2000 Nenad Corbic Fixed the Mulit-Port PPP for kernels 2.2.16 and* greater.* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on* kernels 2.2.16 or greater. The SyncPPP * has changed.* Jul 13, 2000 Nenad Corbic Added SyncPPP support* Added extra debugging in device_setup().* Oct 01, 1999 Gideon Hack Update for s514 PCI card* Dec 27, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE)* Jan 16, 1997 Gene Kozin router_devlist made public* Jan 31, 1997 Alan Cox Hacked it about a bit for 2.1* Jun 27, 1997 Alan Cox realigned with vendor code* Oct 15, 1997 Farhan Thawar changed wan_encapsulate to add a pad byte of 0* Apr 20, 1998 Alan Cox Fixed 2.1 symbols* May 17, 1998 K. Baranowski Fixed SNAP encapsulation in wan_encapsulate* Dec 15, 1998 Arnaldo Melo support for firmwares of up to 128000 bytes* check wandev->setup return value* Dec 22, 1998 Arnaldo Melo vmalloc/vfree used in device_setup to allocate* kernel memory and copy configuration data to* kernel space (for big firmwares)* Jun 02, 1999 Gideon Hack Updates for Linux 2.0.X and 2.2.X kernels. *****************************************************************************/#include <linux/version.h>#include <linux/config.h>#include <linux/stddef.h> /* offsetof(), etc. */#include <linux/errno.h> /* return codes */#include <linux/kernel.h>#include <linux/module.h> /* support for loadable modules */#include <linux/slab.h> /* kmalloc(), kfree() */#include <linux/mm.h> /* verify_area(), etc. */#include <linux/string.h> /* inline mem*, str* functions */#include <asm/byteorder.h> /* htons(), etc. */#include <linux/wanrouter.h> /* WAN router API definitions */#if defined(LINUX_2_4) #include <linux/vmalloc.h> /* vmalloc, vfree */ #include <asm/uaccess.h> /* copy_to/from_user */ #include <linux/init.h> /* __initfunc et al. */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) #include <net/syncppp.h>#else #include <../drivers/net/wan/syncppp.h>#endif#elif defined(LINUX_2_1) #define LINUX_2_1 #include <linux/vmalloc.h> /* vmalloc, vfree */ #include <asm/uaccess.h> /* copy_to/from_user */ #include <linux/init.h> /* __initfunc et al. */ #include <../drivers/net/syncppp.h>#else #include <asm/segment.h> /* kernel <-> user copy */#endif#define KMEM_SAFETYZONE 8/***********FOR DEBUGGING PURPOSES*********************************************static void * dbg_kmalloc(unsigned int size, int prio, int line) { int i = 0; void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); char * c1 = v; c1 += sizeof(unsigned int); *((unsigned int *)v) = size; for (i = 0; i < KMEM_SAFETYZONE; i++) { c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; c1 += 8; } c1 += size; for (i = 0; i < KMEM_SAFETYZONE; i++) { c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; c1 += 8; } v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); return v;}static void dbg_kfree(void * v, int line) { unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); unsigned int size = *sp; char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; int i = 0; for (i = 0; i < KMEM_SAFETYZONE; i++) { if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); } c1 += 8; } c1 += size; for (i = 0; i < KMEM_SAFETYZONE; i++) { if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' ) { printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); } c1 += 8; } printk(KERN_INFO "line %d kfree(%p)\n",line,v); v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); kfree(v);}#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)#define kfree(x) dbg_kfree(x,__LINE__)*****************************************************************************//* * Function Prototypes *//* * Kernel loadable module interface. */#ifdef MODULEint init_module (void);void cleanup_module (void);#endif/* * WAN device IOCTL handlers */static int device_setup(wan_device_t *wandev, wandev_conf_t *u_conf);static int device_stat(wan_device_t *wandev, wandev_stat_t *u_stat);static int device_shutdown(wan_device_t *wandev);static int device_new_if(wan_device_t *wandev, wanif_conf_t *u_conf);static int device_del_if(wan_device_t *wandev, char *u_name); /* * Miscellaneous */static wan_device_t *find_device (char *name);static int delete_interface (wan_device_t *wandev, char *name);void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);/* * Global Data */static char fullname[] = "Sangoma WANPIPE Router";static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc.";static char modname[] = ROUTER_NAME; /* short module name */wan_device_t* router_devlist = NULL; /* list of registered devices */static int devcnt = 0;/* * Organize Unique Identifiers for encapsulation/decapsulation */static unsigned char oui_ether[] = { 0x00, 0x00, 0x00 };#if 0static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 };#endif#ifndef MODULEint wanrouter_init(void){ int err; extern int wanpipe_init(void); extern int sdladrv_init(void); printk(KERN_INFO "%s v%u.%u %s\n", fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright); err = wanrouter_proc_init(); if (err){ printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", modname); } /* * Initialise compiled in boards */#ifdef CONFIG_VENDOR_SANGOMA sdladrv_init(); wanpipe_init();#endif return err;}#ifdef LINUX_2_4static void __exit wanrouter_cleanup (void){ wanrouter_proc_cleanup();}#endif#else/* * Kernel Loadable Module Entry Points *//* * Module 'insert' entry point. * o print announcement * o initialize static data * o create /proc/net/router directory and static entries * * Return: 0 Ok * < 0 error. * Context: process */int init_module (void){ int err; printk(KERN_INFO "%s v%u.%u %s\n", fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright); err = wanrouter_proc_init(); if (err){ printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", modname); } return err;}/* * Module 'remove' entry point. * o delete /proc/net/router directory and static entries. */void cleanup_module (void){ wanrouter_proc_cleanup();}#endif/* * Kernel APIs *//* * Register WAN device. * o verify device credentials * o create an entry for the device in the /proc/net/router directory * o initialize internally maintained fields of the wan_device structure * o link device data space to a singly-linked list * o if it's the first device, then start kernel 'thread' * o increment module use count * * Return: * 0 Ok * < 0 error. * * Context: process */int register_wan_device(wan_device_t *wandev){ int err, namelen; if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) || (wandev->name == NULL)) return -EINVAL; namelen = strlen(wandev->name); if (!namelen || (namelen > WAN_DRVNAME_SZ)) return -EINVAL; if (find_device(wandev->name) != NULL) return -EEXIST;#ifdef WANDEBUG printk(KERN_INFO "%s: registering WAN device %s\n", modname, wandev->name);#endif /* * Register /proc directory entry */ err = wanrouter_proc_add(wandev); if (err) { printk(KERN_INFO "%s: can't create /proc/net/router/%s entry!\n", modname, wandev->name); return err; } /* * Initialize fields of the wan_device structure maintained by the * router and update local data. */ wandev->ndev = 0; wandev->dev = NULL; wandev->next = router_devlist; router_devlist = wandev; ++devcnt; MOD_INC_USE_COUNT; /* prevent module from unloading */ return 0;}/* * Unregister WAN device. * o shut down device * o unlink device data space from the linked list * o delete device entry in the /proc/net/router directory * o decrement module use count * * Return: 0 Ok * <0 error. * Context: process */int unregister_wan_device(char *name){ wan_device_t *wandev, *prev; if (name == NULL) return -EINVAL; for (wandev = router_devlist, prev = NULL; wandev && strcmp(wandev->name, name); prev = wandev, wandev = wandev->next) ; if (wandev == NULL) return -ENODEV;#ifdef WANDEBUG printk(KERN_INFO "%s: unregistering WAN device %s\n", modname, name);#endif if (wandev->state != WAN_UNCONFIGURED) { device_shutdown(wandev); } if (prev){ prev->next = wandev->next; }else{ router_devlist = wandev->next; } --devcnt; wanrouter_proc_delete(wandev); MOD_DEC_USE_COUNT; return 0;}/* * Encapsulate packet. * * Return: encapsulation header size * < 0 - unsupported Ethertype * * Notes: * 1. This function may be called on interrupt context. */int wanrouter_encapsulate (struct sk_buff *skb, netdevice_t *dev, unsigned short type){ int hdr_len = 0; switch (type) { case ETH_P_IP: /* IP datagram encapsulation */ hdr_len += 1; skb_push(skb, 1); skb->data[0] = NLPID_IP; break; case ETH_P_IPX: /* SNAP encapsulation */ case ETH_P_ARP: hdr_len += 7; skb_push(skb, 7); skb->data[0] = 0; skb->data[1] = NLPID_SNAP; memcpy(&skb->data[2], oui_ether, sizeof(oui_ether)); *((unsigned short*)&skb->data[5]) = htons(type); break; default: /* Unknown packet type */ printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", modname, type, dev->name); hdr_len = -EINVAL; } return hdr_len;}/* * Decapsulate packet. * * Return: Ethertype (in network order) * 0 unknown encapsulation * * Notes: * 1. This function may be called on interrupt context. */unsigned short wanrouter_type_trans (struct sk_buff *skb, netdevice_t *dev){ int cnt = skb->data[0] ? 0 : 1; /* there may be a pad present */ unsigned short ethertype; switch (skb->data[cnt]) { case NLPID_IP: /* IP datagramm */ ethertype = htons(ETH_P_IP); cnt += 1; break; case NLPID_SNAP: /* SNAP encapsulation */ if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether))){ printk(KERN_INFO "%s: unsupported SNAP OUI %02X-%02X-%02X " "on interface %s!\n", modname, skb->data[cnt+1], skb->data[cnt+2], skb->data[cnt+3], dev->name); return 0; } ethertype = *((unsigned short*)&skb->data[cnt+4]); cnt += 6; break; /* add other protocols, e.g. CLNP, ESIS, ISIS, if needed */ default: printk(KERN_INFO "%s: unsupported NLPID 0x%02X on interface %s!\n", modname, skb->data[cnt], dev->name); return 0; } skb->protocol = ethertype; skb->pkt_type = PACKET_HOST; /* Physically point to point */ skb_pull(skb, cnt); skb->mac.raw = skb->data; return ethertype;}/* * WAN device IOCTL. * o find WAN device associated with this node * o execute requested action or pass command to the device driver */int wanrouter_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int err = 0; struct proc_dir_entry *dent; wan_device_t *wandev; #if defined (LINUX_2_1) || defined (LINUX_2_4) if (!capable(CAP_NET_ADMIN)){ return -EPERM; } #endif if ((cmd >> 8) != ROUTER_IOCTL) return -EINVAL; dent = inode->u.generic_ip; if ((dent == NULL) || (dent->data == NULL)) return -EINVAL; wandev = dent->data; if (wandev->magic != ROUTER_MAGIC) return -EINVAL; switch (cmd) { case ROUTER_SETUP: err = device_setup(wandev, (void*)arg); break; case ROUTER_DOWN: err = device_shutdown(wandev); break; case ROUTER_STAT: err = device_stat(wandev, (void*)arg); break; case ROUTER_IFNEW: err = device_new_if(wandev, (void*)arg); break; case ROUTER_IFDEL: err = device_del_if(wandev, (void*)arg); break; case ROUTER_IFSTAT: break; default: if ((cmd >= ROUTER_USER) && (cmd <= ROUTER_USER_MAX) && wandev->ioctl) err = wandev->ioctl(wandev, cmd, arg); else err = -EINVAL; } return err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -