📄 cycx_x25.c
字号:
memset (&x25_cmd_conf, 0, sizeof(x25_cmd_conf)); x25_cmd_conf.nlinks = 2; x25_cmd_conf.conf[0] = *conf; /* FIXME: we need to find a way in the wanrouter framework to configure the second link, for now lets use it with the same config from the first link, fixing the interface type to RS232, the speed in 38400 and the clock to external */ x25_cmd_conf.conf[1] = *conf; x25_cmd_conf.conf[1].link = 1; x25_cmd_conf.conf[1].speed = 5; /* 38400 */ x25_cmd_conf.conf[1].clock = 8; x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */ x25_dump_config(&x25_cmd_conf.conf[0]); x25_dump_config(&x25_cmd_conf.conf[1]); return x25_exec(card, X25_CONFIG, 0, &x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0);}/* Get protocol statistics. */static int x25_get_stats (cycx_t *card){ /* the firmware expects 20 in the size field!!! thanks to Daniela */ int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0); if (err) return err; interruptible_sleep_on(&card->wait_stats); if (signal_pending(current)) return -EINTR; card->wandev.stats.rx_packets = card->u.x.stats.n2_rx_frames; card->wandev.stats.rx_over_errors = card->u.x.stats.rx_over_errors; card->wandev.stats.rx_crc_errors = card->u.x.stats.rx_crc_errors; card->wandev.stats.rx_length_errors = 0; /* not available from fw */ card->wandev.stats.rx_frame_errors = 0; /* not available from fw */ card->wandev.stats.rx_missed_errors = card->u.x.stats.rx_aborts; card->wandev.stats.rx_dropped = 0; /* not available from fw */ card->wandev.stats.rx_errors = 0; /* not available from fw */ card->wandev.stats.tx_packets = card->u.x.stats.n2_tx_frames; card->wandev.stats.tx_aborted_errors = card->u.x.stats.tx_aborts; card->wandev.stats.tx_dropped = 0; /* not available from fw */ card->wandev.stats.collisions = 0; /* not available from fw */ card->wandev.stats.tx_errors = 0; /* not available from fw */ x25_dump_devs(&card->wandev); return 0;}/* return the number of nibbles */static int byte_to_nibble(u8 *s, u8 *d, char *nibble){ int i = 0; if (*nibble && *s) { d[i] |= *s++ - '0'; *nibble = 0; ++i; } while (*s) { d[i] = (*s - '0') << 4; if (*(s + 1)) d[i] |= *(s + 1) - '0'; else { *nibble = 1; break; } ++i; s += 2; } return i;}static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble){ if (nibble) { *d++ = '0' + (*s++ & 0x0F); --len; } while (len) { *d++ = '0' + (*s >> 4); if (--len) { *d++ = '0' + (*s & 0x0F); --len; } else break; ++s; } *d = '\0';}/* Place X.25 call. */static int x25_place_call (cycx_t *card, x25_channel_t *chan){ int err = 0, len; char d[64], nibble = 0, mylen = chan->local_addr ? strlen(chan->local_addr) : 0, remotelen = strlen(chan->addr); u8 key; if (card->u.x.connection_keys == ~0UL) { printk(KERN_INFO "%s: too many simultaneous connection " "requests!\n", card->devname); return -EAGAIN; } key = ffz(card->u.x.connection_keys); set_bit(key, (void*)&card->u.x.connection_keys); ++key; dprintk(1, KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key); memset(d, 0, sizeof(d)); d[1] = key; /* user key */ d[2] = 0x10; d[4] = 0x0B; len = byte_to_nibble(chan->addr, d + 6, &nibble); if (chan->local_addr) len += byte_to_nibble(chan->local_addr, d + 6 + len, &nibble); if (nibble) ++len; d[5] = mylen << 4 | remotelen; d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanks to Daniela :) */ if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link, &d, 7 + len + 1, NULL, 0)) != 0) clear_bit(--key, (void*)&card->u.x.connection_keys); else chan->lcn = -key; return err;}/* Place X.25 CONNECT RESPONSE. */static int x25_connect_response (cycx_t *card, x25_channel_t *chan){ u8 d[8]; memset(d, 0, sizeof(d)); d[0] = d[3] = chan->lcn; d[2] = 0x10; d[4] = 0x0F; d[7] = 0xCC; /* TCP/IP over X.25, thanks Daniela */ return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0);}/* Place X.25 DISCONNECT RESPONSE. */static int x25_disconnect_response (cycx_t *card, u8 link, u8 lcn){ char d[5]; memset(d, 0, sizeof(d)); d[0] = d[3] = lcn; d[2] = 0x10; d[4] = 0x17; return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0);}/* Clear X.25 call. */static int x25_clear_call (cycx_t *card, u8 link, u8 lcn, u8 cause, u8 diagn){ u8 d[7]; memset(d, 0, sizeof(d)); d[0] = d[3] = lcn; d[2] = 0x10; d[4] = 0x13; d[5] = cause; d[6] = diagn; return x25_exec(card, X25_DISCONNECT_REQUEST, link, d, 7, NULL, 0);}/* Send X.25 data packet. */static int x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len, void *buf){ u8 d[] = "?\xFF\x10??"; d[0] = d[3] = lcn; d[4] = bitm; return x25_exec(card, X25_DATA_REQUEST, link, &d, 5, buf, len);}/* Miscellaneous *//* Find network device by its channel number. */static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn){ struct net_device *dev = wandev->dev; x25_channel_t *chan; while (dev) { chan = (x25_channel_t*)dev->priv; if (chan->lcn == lcn) break; dev = chan->slave; } return dev;}/* Find network device by its remote dte address. */static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte){ struct net_device *dev = wandev->dev; x25_channel_t *chan; while (dev) { chan = (x25_channel_t*)dev->priv; if (!strcmp(chan->addr, dte)) break; dev = chan->slave; } 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 net_device *dev){ x25_channel_t *chan = dev->priv; cycx_t *card = chan->card; if (chan->svc) { if (!chan->addr[0]) return -EINVAL; /* no destination address */ dprintk(1, KERN_INFO "%s: placing X.25 call to %s...\n", card->devname, chan->addr); if (x25_place_call(card, chan)) return -EIO; set_chan_state(dev, WAN_CONNECTING); return 1; } else set_chan_state(dev, WAN_CONNECTED); return 0;}/* Disconnect logical channel. * o if SVC then clear X.25 call */static void chan_disconnect (struct net_device *dev){ x25_channel_t *chan = dev->priv; if (chan->svc) { x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0); set_chan_state(dev, WAN_DISCONNECTING); } else set_chan_state(dev, WAN_DISCONNECTED);}/* Called by kernel timer */static void chan_timer (unsigned long d){ struct net_device *dev = (struct net_device *)d; x25_channel_t *chan = dev->priv; if (chan->state == WAN_CONNECTED) chan_disconnect(dev); else printk(KERN_ERR "%s: chan_timer for svc (%s) not connected!\n", chan->card->devname, dev->name);}/* Set logical channel state. */static void set_chan_state (struct net_device *dev, u8 state){ x25_channel_t *chan = dev->priv; cycx_t *card = chan->card; long flags; char *string_state = NULL; spin_lock_irqsave(&card->lock, flags); if (chan->state != state) { if (chan->svc && chan->state == WAN_CONNECTED) del_timer(&chan->timer); switch (state) { case WAN_CONNECTED: string_state = "connected!"; *(u16*)dev->dev_addr = htons(chan->lcn); netif_wake_queue(dev); reset_timer(dev); if (chan->protocol == ETH_P_X25) chan_x25_send_event(dev, 1); break; case WAN_CONNECTING: string_state = "connecting..."; break; case WAN_DISCONNECTING: string_state = "disconnecting..."; break; case WAN_DISCONNECTED: string_state = "disconnected!"; if (chan->svc) { *(unsigned short*)dev->dev_addr = 0; chan->lcn = 0; } if (chan->protocol == ETH_P_X25) chan_x25_send_event(dev, 2); netif_wake_queue(dev); break; } printk (KERN_INFO "%s: interface %s %s\n", card->devname, dev->name, string_state); chan->state = state; } spin_unlock_irqrestore(&card->lock, 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 net_device *dev, struct sk_buff *skb){ x25_channel_t *chan = dev->priv; cycx_t *card = chan->card; int bitm = 0; /* final packet */ unsigned len = skb->len; if (skb->len > card->wandev.mtu) { len = card->wandev.mtu; bitm = 0x10; /* set M-bit (more data) */ } if (x25_send(card, chan->link, chan->lcn, bitm, len, skb->data)) return 1; if (bitm) { skb_pull(skb, len); return 1; } ++chan->ifstats.tx_packets; chan->ifstats.tx_bytes += len; return 0;}/* Send event (connection, disconnection, etc) to X.25 socket layer */static void chan_x25_send_event(struct net_device *dev, u8 event){ struct sk_buff *skb; unsigned char *ptr; if ((skb = dev_alloc_skb(1)) == NULL) { printk(KERN_ERR __FUNCTION__ ": out of memory\n"); return; } ptr = skb_put(skb, 1); *ptr = event; skb->dev = dev; skb->protocol = htons(ETH_P_X25); skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; netif_rx(skb); dev->last_rx = jiffies; /* timestamp */}/* Convert line speed in bps to a number used by cyclom 2x code. */static u8 bps_to_speed_code (u32 bps){ u8 number = 0; /* defaults to the lowest (1200) speed ;> */ if (bps >= 512000) number = 8; else if (bps >= 256000) number = 7; else if (bps >= 64000) number = 6; else if (bps >= 38400) number = 5; else if (bps >= 19200) number = 4; else if (bps >= 9600) number = 3; else if (bps >= 4800) number = 2; else if (bps >= 2400) number = 1; return number;}/* log base 2 */static u8 log2 (u32 n){ u8 log = 0; if (!n) return 0; while (n > 1) { n >>= 1; ++log; } return log;}/* Convert decimal string to unsigned integer. * If len != 0 then only 'len' characters of the string are converted. */static unsigned dec_to_uint (u8 *str, int len){ unsigned val = 0; if (!len) len = strlen(str); for (; len && is_digit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned) '0'); return val;}static void reset_timer(struct net_device *dev){ x25_channel_t *chan = dev->priv; if (chan->svc) mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ);}#ifdef CYCLOMX_X25_DEBUGstatic void x25_dump_config(TX25Config *conf){ printk(KERN_INFO "X.25 configuration\n"); printk(KERN_INFO "-----------------\n"); printk(KERN_INFO "link number=%d\n", conf->link); printk(KERN_INFO "line speed=%d\n", conf->speed); printk(KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In"); printk(KERN_INFO "# level 2 retransm.=%d\n", conf->n2); printk(KERN_INFO "level 2 window=%d\n", conf->n2win); printk(KERN_INFO "level 3 window=%d\n", conf->n3win); printk(KERN_INFO "# logical channels=%d\n", conf->nvc); printk(KERN_INFO "level 3 pkt len=%d\n", conf->pktlen); printk(KERN_INFO "my address=%d\n", conf->locaddr); printk(KERN_INFO "remote address=%d\n", conf->remaddr); printk(KERN_INFO "t1=%d seconds\n", conf->t1); printk(KERN_INFO "t2=%d seconds\n", conf->t2); printk(KERN_INFO "t21=%d seconds\n", conf->t21); printk(KERN_INFO "# PVCs=%d\n", conf->npvc); printk(KERN_INFO "t23=%d seconds\n", conf->t23); printk(KERN_INFO "flags=0x%x\n", conf->flags);}static void x25_dump_stats(TX25Stats *stats){ printk(KERN_INFO "X.25 statistics\n"); printk(KERN_INFO "--------------\n"); printk(KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors); printk(KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors); printk(KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames); printk(KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames); printk(KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts); printk(KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts); printk(KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets); printk(KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets); printk(KERN_INFO "tx_aborts=%d\n", stats->tx_aborts); printk(KERN_INFO "rx_aborts=%d\n", stats->rx_aborts);}static void x25_dump_devs(wan_device_t *wandev){ struct net_device *dev = wandev->dev; printk(KERN_INFO "X.25 dev states\n"); printk(KERN_INFO "name: addr: txoff: protocol:\n"); printk(KERN_INFO "---------------------------------------\n"); while(dev) { x25_channel_t *chan = dev->priv; printk(KERN_INFO "%-5.5s %-15.15s %d ETH_P_%s\n", chan->name, chan->addr, netif_queue_stopped(dev), chan->protocol == ETH_P_IP ? "IP" : "X25"); dev = chan->slave; }}#endif /* CYCLOMX_X25_DEBUG *//* End */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -