📄 sdla_x25.c
字号:
*/static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb){ unsigned new_lcn = mb->cmd.lcn; struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn); printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " "Diagn:0x%02X\n", card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); if (dev == NULL) return 1; set_chan_state(dev, WAN_DISCONNECTED); return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1;}/*============================================================================ * Handle X.25 restart event. */ static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb){ wan_device_t* wandev = &card->wandev; struct device* dev; printk(KERN_INFO "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", card->devname, mb->cmd.cause, mb->cmd.diagn); /* down all logical channels */ for (dev = wandev->dev; dev; dev = dev->slave) set_chan_state(dev, WAN_DISCONNECTED); return (cmd == X25_WRITE) ? 0 : 1;}/*============================================================================ * Handle timeout event. */static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb){ unsigned new_lcn = mb->cmd.lcn; if (mb->cmd.pktType == 0x05) /* call request time out */ { struct device* dev = get_dev_by_lcn(&card->wandev, new_lcn); printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", card->devname, new_lcn); if (dev) set_chan_state(dev, WAN_DISCONNECTED); } else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", card->devname, mb->cmd.pktType, new_lcn); return 1;}/******* Miscellaneous ******************************************************//*============================================================================ * Establish physical connection. * o open HDLC and raise DTR * * Return: 0 connection established * 1 connection is in progress * <0 error */static int connect (sdla_t* card){ if (x25_open_hdlc(card) || x25_setup_hdlc(card)) return -EIO; wanpipe_set_state(card, WAN_CONNECTING); return 1;}/*============================================================================ * Tear down physical connection. * o close HDLC link * o drop DTR * * Return: 0 * <0 error */static int disconnect (sdla_t* card){ wanpipe_set_state(card, WAN_DISCONNECTED); x25_set_intr_mode(card, 0); /* disable interrupt generation */ x25_close_hdlc(card); /* close HDLC link */ x25_set_dtr(card, 0); /* drop DTR */ return 0;}/*============================================================================ * Find network device by its channel number. */static struct device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn){ struct device* dev; for (dev = wandev->dev; dev; dev = dev->slave) if (((x25_channel_t*)dev->priv)->lcn == lcn) break; return dev;}/*============================================================================ * Initiate connection on the logical channel. * o for PVC we just get channel configuration * o for SVCs place an X.25 call * * Return: 0 connected * >0 connection in progress * <0 failure */static int chan_connect (struct device* dev){ x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; if (chan->svc) { if (!chan->addr[0]) return -EINVAL; /* no destination address */ printk(KERN_INFO "%s: placing X.25 call to %s ...\n", card->devname, chan->addr); if (x25_place_call(card, chan) != CMD_OK) return -EIO; set_chan_state(dev, WAN_CONNECTING); return 1; } else { if (x25_get_chan_conf(card, chan) != CMD_OK) return -EIO; set_chan_state(dev, WAN_CONNECTED); } return 0;}/*============================================================================ * Disconnect logical channel. * o if SVC then clear X.25 call */static int chan_disc (struct device* dev){ x25_channel_t* chan = dev->priv; if (chan->svc) x25_clear_call(chan->card, chan->lcn, 0, 0); set_chan_state(dev, WAN_DISCONNECTED); return 0;}/*============================================================================ * Set logical channel state. */static void set_chan_state (struct device* dev, int state){ x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; unsigned long flags; save_flags(flags); cli(); if (chan->state != state) { switch (state) { case WAN_CONNECTED: printk (KERN_INFO "%s: interface %s connected!\n", card->devname, dev->name); *(unsigned short*)dev->dev_addr = htons(chan->lcn); chan->i_timeout_sofar = jiffies; break; case WAN_CONNECTING: printk (KERN_INFO "%s: interface %s connecting...\n", card->devname, dev->name); break; case WAN_DISCONNECTED: printk (KERN_INFO "%s: interface %s disconnected!\n", card->devname, dev->name); if (chan->svc) { *(unsigned short*)dev->dev_addr = 0; chan->lcn = 0; } break; } chan->state = state; } chan->state_tick = jiffies; restore_flags(flags);}/*============================================================================ * Send packet on a logical channel. * When this function is called, tx_skb field of the channel data space * points to the transmit socket buffer. When transmission is complete, * release socket buffer and reset 'tbusy' flag. * * Return: 0 - transmission complete * 1 - busy * * Notes: * 1. If packet length is greater than MTU for this channel, we'll fragment * the packet into 'complete sequence' using M-bit. * 2. When transmission is complete, an event notification should be issued * to the router. */static int chan_send (struct device* dev, struct sk_buff* skb){ x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; TX25Status* status = card->flags; unsigned len, qdm; /* Check to see if channel is ready */ if (!(status->cflags[chan->ch_idx] & 0x40)) return 1; if (skb->len > chan->tx_pkt_size) { len = chan->tx_pkt_size; qdm = 0x01; /* set M-bit (more data) */ } else /* final packet */ { len = skb->len; qdm = 0; } switch(x25_send(card, chan->lcn, qdm, len, skb->data)) { case 0x00: /* success */ chan->i_timeout_sofar = jiffies; if (qdm) { skb_pull(skb, len); return 1; } ++chan->ifstats.tx_packets; chan->ifstats.tx_bytes += skb->len; break; case 0x33: /* Tx busy */ return 1; default: /* failure */ ++chan->ifstats.tx_errors;/* return 1; */ } return 0;}/*============================================================================ * Parse X.25 call request data and fill x25_call_info_t structure. */static void parse_call_info (unsigned char* str, x25_call_info_t* info){ memset(info, 0, sizeof(x25_call_info_t)); for (; *str; ++str) { int i; unsigned ch; if (*str == '-') switch (str[1]) { case 'd': /* destination address */ for (i = 0; i < 16; ++i) { ch = str[2+i]; if (!is_digit(ch)) break; info->dest[i] = ch; } break; case 's': /* source address */ for (i = 0; i < 16; ++i) { ch = str[2+i]; if (!is_digit(ch)) break; info->src[i] = ch; } break; case 'u': /* user data */ for (i = 0; i < 127; ++i) { ch = str[2+2*i]; if (!is_hex_digit(ch)) break; info->user[i] = hex_to_uint(&str[2+2*i], 2); } info->nuser = i; break; case 'f': /* facilities */ for (i = 0; i < 64; ++i) { ch = str[2+4*i]; if (!is_hex_digit(ch)) break; info->facil[i].code = hex_to_uint(&str[2+4*i], 2); ch = str[4+4*i]; if (!is_hex_digit(ch)) break; info->facil[i].parm = hex_to_uint(&str[4+4*i], 2); } info->nfacil = i; break; } }}/*============================================================================ * Convert line speed in bps to a number used by S502 code. */static unsigned char bps_to_speed_code (unsigned long bps){ unsigned char number; if (bps <= 1200) number = 0x01 ; else if (bps <= 2400) number = 0x02; else if (bps <= 4800) number = 0x03; else if (bps <= 9600) number = 0x04; else if (bps <= 19200) number = 0x05; else if (bps <= 38400) number = 0x06; else if (bps <= 45000) number = 0x07; else if (bps <= 56000) number = 0x08; else if (bps <= 64000) number = 0x09; else if (bps <= 74000) number = 0x0A; else if (bps <= 112000) number = 0x0B; else if (bps <= 128000) number = 0x0C; else number = 0x0D; return number;}/*============================================================================ * Convert decimal string to unsigned integer. * If len != 0 then only 'len' characters of the string are converted. */static unsigned int dec_to_uint (unsigned char* str, int len){ unsigned val; if (!len) len = strlen(str); for (val = 0; len && is_digit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); return val;}/*============================================================================ * Convert hex string to unsigned integer. * If len != 0 then only 'len' characters of the string are conferted. */static unsigned int hex_to_uint (unsigned char* str, int len){ unsigned val, ch; if (!len) len = strlen(str); for (val = 0; len; ++str, --len) { ch = *str; if (is_digit(ch)) val = (val << 4) + (ch - (unsigned)'0'); else if (is_hex_digit(ch)) val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); else break; } return val;}static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto){ int i; if( proto == htons(ETH_P_IPX) ) { /* It's an IPX packet */ if(!enable_IPX) { /* Return 1 so we don't pass it up the stack. */ return 1; } } else { /* It's not IPX so pass it up the stack. */ return 0; } if( sendpacket[16] == 0x90 && sendpacket[17] == 0x04) { /* It's IPXWAN */ if( sendpacket[2] == 0x02 && sendpacket[34] == 0x00) { /* It's a timer request packet */ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); /* Go through the routing options and answer no to every * option except Unnumbered RIP/SAP */ for(i = 41; sendpacket[i] == 0x00; i += 5) { /* 0x02 is the option for Unnumbered RIP/SAP */ if( sendpacket[i + 4] != 0x02) sendpacket[i + 1] = 0; } /* Skip over the extended Node ID option */ if( sendpacket[i] == 0x04 ) i += 8; /* We also want to turn off all header compression opt. */ for(; sendpacket[i] == 0x80 ;) { sendpacket[i + 1] = 0; i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; } /* Set the packet type to timer response */ sendpacket[34] = 0x01; printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); } else if( sendpacket[34] == 0x02 ) { /* This is an information request packet */ printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); /* Set the packet type to information response */ sendpacket[34] = 0x03; /* Set the router name */ sendpacket[51] = 'X'; sendpacket[52] = 'T'; sendpacket[53] = 'P'; sendpacket[54] = 'I'; sendpacket[55] = 'P'; sendpacket[56] = 'E'; sendpacket[57] = '-'; sendpacket[58] = CVHexToAscii(network_number >> 28); sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); for(i = 66; i < 99; i+= 1) sendpacket[i] = 0; printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); } else { printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); return 0; } /* Set the WNodeID to our network address */ sendpacket[35] = (unsigned char)(network_number >> 24); sendpacket[36] = (unsigned char)((network_number & 0x00FF00
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -