📄 sdla_x25.c
字号:
} else mbox->cmd.length = 1; mbox->cmd.command = X25_SET_INTERRUPT_MODE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ; return err;}/*============================================================================ * Read X.25 channel configuration. */static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int lcn = chan->lcn; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.lcn = lcn; mbox->cmd.command = X25_READ_CHANNEL_CONFIG; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn)); if (!err) { TX25Status* status = card->flags; /* calculate an offset into the array of status bytes */ if (card->u.x.hi_svc <= 255) chan->ch_idx = lcn - 1; else { int offset; switch (mbox->data[0] && 0x1F) { case 0x01: offset = status->pvc_map; break; case 0x03: offset = status->icc_map; break; case 0x07: offset = status->twc_map; break; case 0x0B: offset = status->ogc_map; break; default: offset = 0; } chan->ch_idx = lcn - 1 - offset; } /* get actual transmit packet size on this channel */ switch(mbox->data[1] & 0x38) { case 0x00: chan->tx_pkt_size = 16; break; case 0x08: chan->tx_pkt_size = 32; break; case 0x10: chan->tx_pkt_size = 64; break; case 0x18: chan->tx_pkt_size = 128; break; case 0x20: chan->tx_pkt_size = 256; break; case 0x28: chan->tx_pkt_size = 512; break; case 0x30: chan->tx_pkt_size = 1024; break; } printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", card->devname, lcn, chan->tx_pkt_size); } return err;}/*============================================================================ * Place X.25 call. */static int x25_place_call (sdla_t* card, x25_channel_t* chan){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; char str[64]; sprintf(str, "-d%s -uCC", chan->addr); do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); strcpy(mbox->data, str); mbox->cmd.length = strlen(str); mbox->cmd.command = X25_PLACE_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0)); if (!err) { chan->lcn = mbox->cmd.lcn; chan->protocol = ETH_P_IP; } return err;}/*============================================================================ * Accept X.25 call. */static int x25_accept_call (sdla_t* card, int lcn, int qdm){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.lcn = lcn; mbox->cmd.qdm = qdm; mbox->cmd.command = X25_ACCEPT_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); return err;}/*============================================================================ * Clear X.25 call. */static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.lcn = lcn; mbox->cmd.cause = cause; mbox->cmd.diagn = diagn; mbox->cmd.command = X25_CLEAR_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); return err;}/*============================================================================ * Send X.25 data packet. */static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf){ TX25Mbox* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); memcpy(mbox->data, buf, len); mbox->cmd.length = len; mbox->cmd.lcn = lcn; mbox->cmd.qdm = qdm; mbox->cmd.command = X25_WRITE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_WRITE, lcn)); return err;}/*============================================================================ * Fetch X.25 asynchronous events. */static int x25_fetch_events (sdla_t* card){ TX25Status* status = card->flags; TX25Mbox* mbox = card->mbox; int err = 0; if (status->gflags & 0x20) { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_IS_DATA_AVAILABLE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); } return err;}/*============================================================================ * X.25 asynchronous event/error handler. * This routine is called each time interface command returns non-zero * return code to handle X.25 asynchronous events and common errors. * Return non-zero to repeat command or zero to cancel it. * * Notes: * 1. This function may be called recursively, as handling some of the * asynchronous events (e.g. call request) requires execution of the * interface command(s) that, in turn, may also return asynchronous * events. To avoid re-entrancy problems we copy mailbox to dynamically * allocated memory before processing events. */static int x25_error (sdla_t* card, int err, int cmd, int lcn){ int retry = 1; unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length; TX25Mbox* mb; mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC); if (mb == NULL) { printk(KERN_ERR "%s: x25_error() out of memory!\n", card->devname); return 0; } memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); switch (err) { case 0x40: /* X.25 asynchronous packet was received */ mb->data[dlen] = '\0'; switch (mb->cmd.pktType & 0x7F) { case 0x30: /* incoming call */ retry = incoming_call(card, cmd, lcn, mb); break; case 0x31: /* connected */ retry = call_accepted(card, cmd, lcn, mb); break; case 0x02: /* call clear request */ retry = call_cleared(card, cmd, lcn, mb); break; case 0x04: /* reset request */ printk(KERN_INFO "%s: X.25 reset request on LCN %d! " "Cause:0x%02X Diagn:0x%02X\n", card->devname, mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); break; case 0x08: /* restart request */ retry = restart_event(card, cmd, lcn, mb); break; default: printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " "Cause:0x%02X Diagn:0x%02X\n", card->devname, mb->cmd.pktType, mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); } break; case 0x41: /* X.25 protocol violation indication */ printk(KERN_INFO "%s: X.25 protocol violation on LCN %d! " "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", card->devname, mb->cmd.lcn, mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); break; case 0x42: /* X.25 timeout */ retry = timeout_event(card, cmd, lcn, mb); break; case 0x43: /* X.25 retry limit exceeded */ printk(KERN_INFO "%s: exceeded X.25 retry limit on LCN %d! " "Packet:0x%02X Diagn:0x%02X\n", card->devname, mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn); break; case 0x08: /* modem failure */ printk(KERN_INFO "%s: modem failure!\n", card->devname); break; case 0x09: /* N2 retry limit */ printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", card->devname); break; case 0x06: /* unnumbered frame was received while in ABM */ printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", card->devname, mb->data[0]); break; case CMD_TIMEOUT: printk(KERN_ERR "%s: command 0x%02X timed out!\n", card->devname, cmd); retry = 0; /* abort command */ break; default: printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", card->devname, cmd, err); retry = 0; /* abort command */ } kfree(mb); return retry;}/****** X.25 Asynchronous Event Handlers ************************************* * These functions are called by the x25_error() and should return 0, if * the command resulting in the asynchronous event must be aborted. *//*============================================================================ * Handle X.25 incoming call request. * RFC 1356 establishes the following rules: * 1. The first octet in the Call User Data (CUD) field of the call * request packet contains NLPID identifying protocol encapsulation. * 2. Calls MUST NOT be accepted unless router supports requested * protocol encapsulation. * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when * clearing a call because protocol encapsulation is not supported. * 4. If an incoming call is received while a call request is pending * (i.e. call collision has occurred), the incoming call shall be * rejected and call request shall be retried. */static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb){ wan_device_t* wandev = &card->wandev; int new_lcn = mb->cmd.lcn; struct device* dev = get_dev_by_lcn(wandev, new_lcn); x25_channel_t* chan = NULL; int accept = 0; /* set to '1' if o.k. to accept call */ x25_call_info_t* info; /* Make sure there is no call collision */ if (dev != NULL) { printk(KERN_INFO "%s: X.25 incoming call collision on LCN %d!\n", card->devname, new_lcn); x25_clear_call(card, new_lcn, 0, 0); return 1; } /* Make sure D bit is not set in call request */ if (mb->cmd.qdm & 0x02) { printk(KERN_INFO "%s: X.25 incoming call on LCN %d with D-bit set!\n", card->devname, new_lcn); x25_clear_call(card, new_lcn, 0, 0); return 1; } /* Parse call request data */ info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); if (info == NULL) { printk(KERN_ERR "%s: not enough memory to parse X.25 incoming call " "on LCN %d!\n", card->devname, new_lcn); x25_clear_call(card, new_lcn, 0, 0); return 1; } parse_call_info(mb->data, info); printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n", card->devname, new_lcn, mb->data); /* Find available channel */ for (dev = wandev->dev; dev; dev = dev->slave) { chan = dev->priv; if (!chan->svc || (chan->state != WAN_DISCONNECTED)) continue; if (strcmp(info->src, chan->addr) == 0) break; /* If just an '@' is specified, accept all incoming calls */ if (strcmp(chan->addr, "") == 0) break; } if (dev == NULL) { printk(KERN_INFO "%s: no channels available!\n", card->devname); x25_clear_call(card, new_lcn, 0, 0); } /* Check requested protocol encapsulation */ else if (info->nuser == 0) { printk(KERN_INFO "%s: no user data in incoming call on LCN %d!\n", card->devname, new_lcn); x25_clear_call(card, new_lcn, 0, 0); } else switch (info->user[0]) { case 0: /* multiplexed */ chan->protocol = 0; accept = 1; break; case NLPID_IP: /* IP datagrams */ chan->protocol = ETH_P_IP; accept = 1; break; case NLPID_SNAP: /* IPX datagrams */ chan->protocol = ETH_P_IPX; accept = 1; break; default: printk(KERN_INFO "%s: unsupported NLPID 0x%02X in incoming call " "on LCN %d!\n", card->devname, info->user[0], new_lcn); x25_clear_call(card, new_lcn, 0, 249); } if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)) { chan->lcn = new_lcn; if (x25_get_chan_conf(card, chan) == CMD_OK) set_chan_state(dev, WAN_CONNECTED); else x25_clear_call(card, new_lcn, 0, 0); } kfree(info); return 1;}/*============================================================================ * Handle accepted call. */static int call_accepted (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); x25_channel_t* chan; printk(KERN_INFO "%s: X.25 call accepted on LCN %d!\n", card->devname, new_lcn); if (dev == NULL) { printk(KERN_INFO "%s: clearing orphaned connection on LCN %d!\n", card->devname, new_lcn); x25_clear_call(card, new_lcn, 0, 0); return 1; } /* Get channel configuration and notify router */ chan = dev->priv; if (x25_get_chan_conf(card, chan) != CMD_OK) { x25_clear_call(card, new_lcn, 0, 0); return 1; } set_chan_state(dev, WAN_CONNECTED); return 1;}/*============================================================================ * Handle cleared call.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -