📄 isdn_net.c
字号:
case 9: case 10: case 12: if (lp->dialstate <= 6) { dev->usage[idx] |= ISDN_USAGE_OUTGOING; isdn_info_update(); } else dev->rx_netdev[idx] = p; lp->dialstate = 0; isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1); if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) isdn_net_ciscohdlck_connected(lp); if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { if (lp->master) { /* is lp a slave? */ isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev; isdn_net_add_to_bundle(nd, lp); } } printk(KERN_INFO "isdn_net: %s connected\n", lp->name); /* If first Chargeinfo comes before B-Channel connect, * we correct the timestamp here. */ lp->chargetime = jiffies; /* reset dial-timeout */ lp->dialstarted = 0; lp->dialwait_timer = 0;#ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) isdn_ppp_wakeup_daemon(lp);#endif#ifdef CONFIG_ISDN_X25 /* try if there are generic concap receiver routines */ if( pops ) if( pops->connect_ind) pops->connect_ind(cprot);#endif /* CONFIG_ISDN_X25 */ /* ppp needs to do negotiations first */ if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) isdn_net_device_wake_queue(lp); return 1; } break; case ISDN_STAT_NODCH: /* No D-Channel avail. */ if (lp->dialstate == 4) { lp->dialstate--; return 1; } break; case ISDN_STAT_CINF: /* Charge-info from TelCo. Calculate interval between * charge-infos and set timestamp for last info for * usage by isdn_net_autohup() */ lp->charge++; if (lp->hupflags & ISDN_HAVECHARGE) { lp->hupflags &= ~ISDN_WAITCHARGE; lp->chargeint = jiffies - lp->chargetime - (2 * HZ); } if (lp->hupflags & ISDN_WAITCHARGE) lp->hupflags |= ISDN_HAVECHARGE; lp->chargetime = jiffies; printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n", lp->name, lp->chargetime); return 1; } } return 0;}/* * Perform dialout for net-interfaces and timeout-handling for * D-Channel-up and B-Channel-up Messages. * This function is initially called from within isdn_net_start_xmit() or * or isdn_net_find_icall() after initializing the dialstate for an * interface. If further calls are needed, the function schedules itself * for a timer-callback via isdn_timer_function(). * The dialstate is also affected by incoming status-messages from * the ISDN-Channel which are handled in isdn_net_stat_callback() above. */voidisdn_net_dial(void){ isdn_net_dev *p = dev->netdev; int anymore = 0; int i; isdn_ctrl cmd; u_char *phone_number; while (p) { isdn_net_local *lp = p->local;#ifdef ISDN_DEBUG_NET_DIAL if (lp->dialstate) printk(KERN_DEBUG "%s: dialstate=%d\n", lp->name, lp->dialstate);#endif switch (lp->dialstate) { case 0: /* Nothing to do for this interface */ break; case 1: /* Initiate dialout. Set phone-number-pointer to first number * of interface. */ lp->dial = lp->phone[1]; if (!lp->dial) { printk(KERN_WARNING "%s: phone number deleted?\n", lp->name); isdn_net_hangup(&p->dev); break; } anymore = 1; if(lp->dialtimeout > 0) if(lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) { lp->dialstarted = jiffies; lp->dialwait_timer = 0; } lp->dialstate++; /* Fall through */ case 2: /* Prepare dialing. Clear EAZ, then set EAZ. */ cmd.driver = lp->isdn_device; cmd.arg = lp->isdn_channel; cmd.command = ISDN_CMD_CLREAZ; isdn_command(&cmd); sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver)); cmd.command = ISDN_CMD_SETEAZ; isdn_command(&cmd); lp->dialretry = 0; anymore = 1; lp->dialstate++; /* Fall through */ case 3: /* Setup interface, dial current phone-number, switch to next number. * If list of phone-numbers is exhausted, increment * retry-counter. */ if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) { char *s; if (dev->global_flags & ISDN_GLOBAL_STOPPED) s = "dial suppressed: isdn system stopped"; else s = "dial suppressed: dialmode `off'"; isdn_net_unreachable(&p->dev, NULL, s); isdn_net_hangup(&p->dev); break; } cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_SETL2; cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); isdn_command(&cmd); cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_SETL3; cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); isdn_command(&cmd); cmd.driver = lp->isdn_device; cmd.arg = lp->isdn_channel; if (!lp->dial) { printk(KERN_WARNING "%s: phone number deleted?\n", lp->name); isdn_net_hangup(&p->dev); break; } if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) { lp->dialstate = 4; printk(KERN_INFO "%s: Open leased line ...\n", lp->name); } else { if(lp->dialtimeout > 0) if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; isdn_net_unreachable(&p->dev, NULL, "dial: timed out"); isdn_net_hangup(&p->dev); break; } cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_DIAL; cmd.parm.setup.si2 = 0; /* check for DOV */ phone_number = lp->dial->num; if ((*phone_number == 'v') || (*phone_number == 'V')) { /* DOV call */ cmd.parm.setup.si1 = 1; } else { /* DATA call */ cmd.parm.setup.si1 = 7; } strcpy(cmd.parm.setup.phone, phone_number); /* * Switch to next number or back to start if at end of list. */ if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) { lp->dial = lp->phone[1]; lp->dialretry++; if (lp->dialretry > lp->dialmax) { if (lp->dialtimeout == 0) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; isdn_net_unreachable(&p->dev, NULL, "dial: tried all numbers dialmax times"); } isdn_net_hangup(&p->dev); break; } } sprintf(cmd.parm.setup.eazmsn, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver)); i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel); if (i >= 0) { strcpy(dev->num[i], cmd.parm.setup.phone); dev->usage[i] |= ISDN_USAGE_OUTGOING; isdn_info_update(); } printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name, lp->dialretry, cmd.parm.setup.phone, (cmd.parm.setup.si1 == 1) ? "DOV" : ""); lp->dtimer = 0;#ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device, lp->isdn_channel);#endif isdn_command(&cmd); } lp->huptimer = 0; lp->outgoing = 1; if (lp->chargeint) { lp->hupflags |= ISDN_HAVECHARGE; lp->hupflags &= ~ISDN_WAITCHARGE; } else { lp->hupflags |= ISDN_WAITCHARGE; lp->hupflags &= ~ISDN_HAVECHARGE; } anymore = 1; lp->dialstate = (lp->cbdelay && (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4; break; case 4: /* Wait for D-Channel-connect. * If timeout, switch back to state 3. * Dialmax-handling moved to state 3. */ if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) lp->dialstate = 3; anymore = 1; break; case 5: /* Got D-Channel-Connect, send B-Channel-request */ cmd.driver = lp->isdn_device; cmd.arg = lp->isdn_channel; cmd.command = ISDN_CMD_ACCEPTB; anymore = 1; lp->dtimer = 0; lp->dialstate++; isdn_command(&cmd); break; case 6: /* Wait for B- or D-Channel-connect. If timeout, * switch back to state 3. */#ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer);#endif if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) lp->dialstate = 3; anymore = 1; break; case 7: /* Got incoming Call, setup L2 and L3 protocols, * then wait for D-Channel-connect */#ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);#endif cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_SETL2; cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); isdn_command(&cmd); cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_SETL3; cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); isdn_command(&cmd); if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15) isdn_net_hangup(&p->dev); else { anymore = 1; lp->dialstate++; } break; case 9: /* Got incoming D-Channel-Connect, send B-Channel-request */ cmd.driver = lp->isdn_device; cmd.arg = lp->isdn_channel; cmd.command = ISDN_CMD_ACCEPTB; isdn_command(&cmd); anymore = 1; lp->dtimer = 0; lp->dialstate++; break; case 8: case 10: /* Wait for B- or D-channel-connect */#ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);#endif if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) isdn_net_hangup(&p->dev); else anymore = 1; break; case 11: /* Callback Delay */ if (lp->dtimer++ > lp->cbdelay) lp->dialstate = 1; anymore = 1; break; case 12: /* Remote does callback. Hangup after cbdelay, then wait for incoming * call (in state 4). */ if (lp->dtimer++ > lp->cbdelay) { printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name); lp->dtimer = 0; lp->dialstate = 4; cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_HANGUP; cmd.arg = lp->isdn_channel; isdn_command(&cmd); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); } anymore = 1; break; default: printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n", lp->dialstate, lp->name); } p = (isdn_net_dev *) p->next; } isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore);}/* * Perform hangup for a net-interface. */voidisdn_net_hangup(struct net_device *d){ isdn_net_local *lp = (isdn_net_local *) d->priv; isdn_ctrl cmd;#ifdef CONFIG_ISDN_X25 struct concap_proto *cprot = lp->netdev->cprot; struct concap_proto_ops *pops = cprot ? cprot->pops : NULL;#endif if (lp->flags & ISDN_NET_CONNECTED) { if (lp->slave != NULL) { isdn_net_local *slp = (isdn_net_local *)lp->slave->priv; if (slp->flags & ISDN_NET_CONNECTED) { printk(KERN_INFO "isdn_net: hang up slave %s before %s\n", slp->name, lp->name); isdn_net_hangup(lp->slave); } } printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);#ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) isdn_ppp_free(lp);#endif isdn_net_lp_disconnected(lp);#ifdef CONFIG_ISDN_X25 /* try if there are generic encap protocol receiver routines and signal the closure of the link */ if( pops && pops -> disconn_ind ) pops -> disconn_ind(cprot);#endif /* CONFIG_ISDN_X25 */ cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_HANGUP; cmd.arg = lp->isdn_channel; isdn_command(&cmd); printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); } isdn_net_unbind_channel(lp);}typedef struct { unsigned short source; unsigned short dest;} ip_ports;static voidisdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp){ u_char *p = skb->nh.raw; /* hopefully, this was set correctly */ unsigned short proto = ntohs(skb->protocol); int data_ofs; ip_ports *ipp; char addinfo[100]; addinfo[0] = '\0'; /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) { /* fall back to old isdn_net_log_packet method() */ char * buf = skb->data; printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->name); p = buf; proto = ETH_P_IP; switch (lp->p_encap) { case ISDN_NET_ENCAP_IPTYP: proto = ntohs(*(unsigned short *) &buf[0]); p = &buf[2]; break; case ISDN_NET_ENCAP_ETHER: proto = ntohs(*(unsigned short *) &buf[12]); p = &buf[14]; break; case ISDN_NET_ENCAP_CISCOHDLC: proto = ntohs(*(unsigned short *) &buf[2]); p = &buf[4]; break;#ifdef CONFIG_ISDN_PPP case ISDN_NET_ENCAP_SYNCPPP: proto = ntohs(skb->protocol); p = &buf[IPPP_MAX_HEADER]; break;#endif } } data_ofs = ((p[0] & 15) * 4); switch (proto) { case ETH_P_IP: switch (p[9]) { case 1: strcpy(addinfo, " ICMP"); break; case 2: strcpy(addinfo, " IGMP"); break; case 4: strcpy(addinfo, " IPIP"); break; case 6: ipp = (ip_ports *) (&p[data_ofs]); sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source), ntohs(ipp->dest)); break; case 8: strcpy(addinfo, " EGP"); break; case 12: strcpy(addinfo, " PUP"); break; case 17: ipp = (ip_ports *) (&p[data_ofs]); sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source), ntohs(ipp->dest)); break; case 22: strcpy(addinfo, " IDP"); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -