📄 sdla_x25.c
字号:
/****************************************************************************** sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module.** Author: Gene Kozin <genek@compuserve.com>** Copyright: (c) 1995-1997 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.* ============================================================================* Mar 15, 1998 Alan Cox o 2.1.x porting* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs* when they are disabled.* Nov 17, 1997 Farhan Thawar o Added IPX support* o Changed if_send() to now buffer packets when* the board is busy* o Removed queueing of packets via the polling* routing* o Changed if_send() critical flags to properly* handle race conditions* Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts* o Changed PVC encapsulation to ETH_P_IP* Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree()* when packets are received.* Mar 11, 1997 Farhan Thawar Version 3.1.1* o added support for V35* o changed if_send() to return 0 if* wandev.critical() is true* o free socket buffer in if_send() if* returning 0* o added support for single '@' address to* accept all incoming calls* o fixed bug in set_chan_state() to disconnect* Jan 15, 1997 Gene Kozin Version 3.1.0* o implemented exec() entry point* Jan 07, 1997 Gene Kozin Initial version.*****************************************************************************/#include <linux/kernel.h> /* printk(), and other useful stuff */#include <linux/stddef.h> /* offsetof(), etc. */#include <linux/errno.h> /* return codes */#include <linux/string.h> /* inline memset(), etc. */#include <linux/malloc.h> /* kmalloc(), kfree() */#include <linux/wanrouter.h> /* WAN router definitions */#include <linux/wanpipe.h> /* WANPIPE common user API definitions */#include <asm/byteorder.h> /* htons(), etc. */#include <asm/uaccess.h>#define _GNUC_#include <linux/sdla_x25.h> /* X.25 firmware API definitions *//****** Defines & Macros ****************************************************/#define CMD_OK 0 /* normal firmware return code */#define CMD_TIMEOUT 0xFF /* firmware command timed out */#define MAX_CMD_RETRY 10 /* max number of firmware retries */#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */#define X25_HRDHDR_SZ 7 /* max encapsulation header size */#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */#define HOLD_DOWN_TIME (30*HZ) /* link hold down time *//* For IPXWAN */#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))/****** Data Structures *****************************************************//* This is an extention of the 'struct device' we create for each network * interface to keep the rest of X.25 channel-specific data. */typedef struct x25_channel{ char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ unsigned lcn; /* logical channel number */ unsigned tx_pkt_size; unsigned short protocol; /* ethertype, 0 - multiplexed */ char svc; /* 0 - permanent, 1 - switched */ char state; /* channel state */ char drop_sequence; /* mark sequence for dropping */ unsigned long state_tick; /* time of the last state change */ unsigned idle_timeout; /* sec, before disconnecting */ unsigned long i_timeout_sofar; /* # of sec's we've been idle */ unsigned hold_timeout; /* sec, before re-connecting */ unsigned long tick_counter; /* counter for transmit time out */ char devtint; /* Weather we should dev_tint() */ struct sk_buff* rx_skb; /* receive socket buffer */ struct sk_buff* tx_skb; /* transmit socket buffer */ sdla_t* card; /* -> owner */ int ch_idx; struct net_device_stats ifstats; /* interface statistics */} x25_channel_t;typedef struct x25_call_info{ char dest[17]; /* ASCIIZ destination address */ char src[17]; /* ASCIIZ source address */ char nuser; /* number of user data bytes */ unsigned char user[127]; /* user data */ char nfacil; /* number of facilities */ struct { unsigned char code; unsigned char parm; } facil[64]; /* facilities */} x25_call_info_t;/****** Function Prototypes *************************************************//* WAN link driver entry points. These are called by the WAN router module. */static int update (wan_device_t* wandev);static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf);static int del_if (wan_device_t* wandev, struct device* dev);/* WANPIPE-specific entry points */static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data);/* Network device interface */static int if_init (struct device* dev);static int if_open (struct device* dev);static int if_close (struct device* dev);static int if_header (struct sk_buff* skb, struct device* dev, unsigned short type, void* daddr, void* saddr, unsigned len);static int if_rebuild_hdr (struct sk_buff* skb);static int if_send (struct sk_buff* skb, struct device* dev);static struct net_device_stats * if_stats (struct device* dev);/* Interrupt handlers */static void wpx_isr (sdla_t* card);static void rx_intr (sdla_t* card);static void tx_intr (sdla_t* card);static void status_intr (sdla_t* card);static void event_intr (sdla_t* card);static void spur_intr (sdla_t* card);/* Background polling routines */static void wpx_poll (sdla_t* card);static void poll_disconnected (sdla_t* card);static void poll_connecting (sdla_t* card);static void poll_active (sdla_t* card);/* X.25 firmware interface functions */static int x25_get_version (sdla_t* card, char* str);static int x25_configure (sdla_t* card, TX25Config* conf);static int x25_get_err_stats (sdla_t* card);static int x25_get_stats (sdla_t* card);static int x25_set_intr_mode (sdla_t* card, int mode);static int x25_close_hdlc (sdla_t* card);static int x25_open_hdlc (sdla_t* card);static int x25_setup_hdlc (sdla_t* card);static int x25_set_dtr (sdla_t* card, int dtr);static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan);static int x25_place_call (sdla_t* card, x25_channel_t* chan);static int x25_accept_call (sdla_t* card, int lcn, int qdm);static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn);static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf);static int x25_fetch_events (sdla_t* card);static int x25_error (sdla_t* card, int err, int cmd, int lcn);/* X.25 asynchronous event handlers */static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);/* Miscellaneous functions */static int connect (sdla_t* card);static int disconnect (sdla_t* card);static struct device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn);static int chan_connect (struct device* dev);static int chan_disc (struct device* dev);static void set_chan_state (struct device* dev, int state);static int chan_send (struct device* dev, struct sk_buff* skb);static unsigned char bps_to_speed_code (unsigned long bps);static unsigned int dec_to_uint (unsigned char* str, int len);static unsigned int hex_to_uint (unsigned char* str, int len);static void parse_call_info (unsigned char* str, x25_call_info_t* info);/* IPX functions */static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto);extern void disable_irq(unsigned int);extern void enable_irq(unsigned int);/****** Global Data ********************************************************** * Note: All data must be explicitly initialized!!! *//****** Public Functions ****************************************************//*============================================================================ * X.25 Protocol Initialization routine. * * This routine is called by the main WANPIPE module during setup. At this * point adapter is completely initialized and X.25 firmware is running. * o read firmware version (to make sure it's alive) * o configure adapter * o initialize protocol-specific fields of the adapter data space. * * Return: 0 o.k. * < 0 failure. */int wpx_init (sdla_t* card, wandev_conf_t* conf){ union { char str[80]; TX25Config cfg; } u; /* Verify configuration ID */ if (conf->config_id != WANCONFIG_X25) { printk(KERN_INFO "%s: invalid configuration ID %u!\n", card->devname, conf->config_id) ; return -EINVAL; } /* Initialize protocol-specific fields */ card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS); card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work * around this, we execute the first command twice. */ if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) return -EIO ; printk(KERN_INFO "%s: running X.25 firmware v%s\n", card->devname, u.str) ; /* Configure adapter. Here we set resonable defaults, then parse * device configuration structure and set configuration options. * Most configuration options are verified and corrected (if * necessary) since we can't rely on the adapter to do so and don't * want it to fail either. */ memset(&u.cfg, 0, sizeof(u.cfg)); u.cfg.t1 = 3; u.cfg.n2 = 10; u.cfg.autoHdlc = 1; /* automatic HDLC connection */ u.cfg.hdlcWindow = 7; u.cfg.pktWindow = 2; u.cfg.station = 1; /* DTE */ u.cfg.options = 0x00B0; /* disable D-bit pragmatics */ u.cfg.ccittCompat = 1988; u.cfg.t10t20 = 30; u.cfg.t11t21 = 30; u.cfg.t12t22 = 30; u.cfg.t13t23 = 30; u.cfg.t16t26 = 30; u.cfg.t28 = 30; u.cfg.r10r20 = 5; u.cfg.r12r22 = 5; u.cfg.r13r23 = 5; u.cfg.responseOpt = 1; /* RR's after every packet */ if (conf->clocking != WANOPT_EXTERNAL) u.cfg.baudRate = bps_to_speed_code(conf->bps) ; if (conf->station != WANOPT_DTE) { u.cfg.station = 0; /* DCE mode */ } if (conf->interface != WANOPT_RS232 ) { u.cfg.hdlcOptions |= 0x80; /* V35 mode */ } /* adjust MTU */ if (!conf->mtu || (conf->mtu >= 1024)) card->wandev.mtu = 1024 ; else if (conf->mtu >= 512) card->wandev.mtu = 512 ; else if (conf->mtu >= 256) card->wandev.mtu = 256 ; else if (conf->mtu >= 128) card->wandev.mtu = 128 ; else card->wandev.mtu = 64; u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; if (conf->u.x25.hi_pvc) { card->u.x.hi_pvc = min(conf->u.x25.hi_pvc, 4095); card->u.x.lo_pvc = min(conf->u.x25.lo_pvc, card->u.x.hi_pvc); } if (conf->u.x25.hi_svc) { card->u.x.hi_svc = min(conf->u.x25.hi_svc, 4095); card->u.x.lo_svc = min(conf->u.x25.lo_svc, card->u.x.hi_svc); } u.cfg.loPVC = card->u.x.lo_pvc; u.cfg.hiPVC = card->u.x.hi_pvc; u.cfg.loTwoWaySVC = card->u.x.lo_svc; u.cfg.hiTwoWaySVC = card->u.x.hi_svc; if (conf->u.x25.hdlc_window) u.cfg.hdlcWindow = min(conf->u.x25.hdlc_window, 7) ; if (conf->u.x25.pkt_window) u.cfg.pktWindow = min(conf->u.x25.pkt_window, 7) ; if (conf->u.x25.t1) u.cfg.t1 = min(conf->u.x25.t1, 30) ; u.cfg.t2 = min(conf->u.x25.t2, 29); u.cfg.t4 = min(conf->u.x25.t4, 240); if (conf->u.x25.n2) u.cfg.n2 = min(conf->u.x25.n2, 30) ; if (conf->u.x25.ccitt_compat) u.cfg.ccittCompat = conf->u.x25.ccitt_compat ; /* initialize adapter */ if ((x25_configure(card, &u.cfg) != CMD_OK) || (x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ return -EIO ; /* Initialize protocol-specific fields of adapter data space */ card->wandev.bps = conf->bps; card->wandev.interface = conf->interface; card->wandev.clocking = conf->clocking; card->wandev.station = conf->station; card->isr = &wpx_isr; card->poll = &wpx_poll; card->exec = &wpx_exec; card->wandev.update = &update; card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; card->wandev.state = WAN_DISCONNECTED; card->wandev.enable_tx_int = 0; card->irq_dis_if_send_count = 0; card->irq_dis_poll_count = 0; card->wandev.enable_IPX = conf->enable_IPX; if (conf->network_number) card->wandev.network_number = conf->network_number; else card->wandev.network_number = 0xDEADBEEF; return 0;}/******* WAN Device Driver Entry Points *************************************//*============================================================================ * Update device status & statistics. */static int update (wan_device_t* wandev){ sdla_t* card; /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN; card = wandev->private; x25_get_err_stats(card); x25_get_stats(card); wandev->critical = 0; return 0;}/*============================================================================ * Create new logical channel. * This routine is called by the router when ROUTER_IFNEW IOCTL is being * handled. * o parse media- and hardware-specific configuration * o make sure that a new channel can be created * o allocate resources, if necessary * o prepare network device structure for registaration. * * Return: 0 o.k. * < 0 failure (channel will not be created) */static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf){ sdla_t* card = wandev->private; x25_channel_t* chan; int err = 0; if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { printk(KERN_INFO "%s: invalid interface name!\n", card->devname) ; return -EINVAL; } /* allocate and initialize private data */ chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL); if (chan == NULL) return -ENOMEM ; memset(chan, 0, sizeof(x25_channel_t)); strcpy(chan->name, conf->name); chan->card = card; chan->protocol = ETH_P_IP; chan->tx_skb = chan->rx_skb = NULL; /* verify media address */ if (conf->addr[0] == '@') /* SVC */ { chan->svc = 1; strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); /* Set channel timeouts (default if not specified) */ chan->idle_timeout = (conf->idle_timeout) ? conf->idle_timeout : 90; chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout : 10; } else if (is_digit(conf->addr[0])) /* PVC */ { int lcn = dec_to_uint(conf->addr, 0); if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)) { chan->lcn = lcn; } else { printk(KERN_ERR "%s: PVC %u is out of range on interface %s!\n", wandev->name, lcn, chan->name) ; err = -EINVAL; } } else { printk(KERN_ERR "%s: invalid media address on interface %s!\n", wandev->name, chan->name) ; err = -EINVAL; } if (err) { kfree(chan); return err; } /* prepare network device data space for registration */ dev->name = chan->name; dev->init = &if_init; dev->priv = chan; return 0;}/*============================================================================ * Delete logical channel.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -