📄 isdn_net.c
字号:
int si2; int ematch; int wret; int swapped; int sidx = 0; isdn_net_dev *p; isdn_net_phone *n; ulong flags; char nr[32]; /* Search name in netdev-chain */ save_flags(flags); cli(); if (!setup->phone[0]) { nr[0] = '0'; nr[1] = '\0'; printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n"); } else strcpy(nr, setup->phone); si1 = (int) setup->si1; si2 = (int) setup->si2; if (!setup->eazmsn[0]) { printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n"); eaz = "0"; } else eaz = setup->eazmsn; if (dev->net_verbose > 1) printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz); /* Accept only calls with Si1 = 7 (Data-Transmission) */ if (si1 != 7) { restore_flags(flags); if (dev->net_verbose > 1) printk(KERN_INFO "isdn_net: Service-Indicator not 7, ignored\n"); return 0; } n = (isdn_net_phone *) 0; p = dev->netdev; ematch = wret = swapped = 0;#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx, dev->usage[idx]);#endif while (p) { int matchret; isdn_net_local *lp = p->local; /* If last check has triggered as binding-swap, revert it */ switch (swapped) { case 2: isdn_net_swap_usage(idx, sidx); /* fall through */ case 1: isdn_net_swapbind(di); break; } swapped = 0; if (!(matchret = isdn_msncmp(eaz, isdn_map_eaz2msn(lp->msn, di)))) ematch = 1; /* Remember if more numbers eventually can match */ if (matchret > wret) wret = matchret;#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n", lp->name, lp->msn, lp->flags, lp->dialstate);#endif if ((!matchret) && /* EAZ is matching */ (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */ (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */ (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */ ))) {#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n", lp->pre_device, lp->pre_channel);#endif if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) { if ((lp->pre_channel != ch) || (lp->pre_device != di)) { /* Here we got a problem: * If using an ICN-Card, an incoming call is always signaled on * on the first channel of the card, if both channels are * down. However this channel may be bound exclusive. If the * second channel is free, this call should be accepted. * The solution is horribly but it runs, so what: * We exchange the exclusive bindings of the two channels, the * corresponding variables in the interface-structs. */ if (ch == 0) { sidx = isdn_dc2minor(di, 1);#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: ch is 0\n");#endif if (USG_NONE(dev->usage[sidx])) { /* Second Channel is free, now see if it is bound * exclusive too. */ if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) {#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n");#endif /* Yes, swap bindings only, if the original * binding is bound to channel 1 of this driver */ if ((lp->pre_device == di) && (lp->pre_channel == 1)) { isdn_net_swapbind(di); swapped = 1; } else { /* ... else iterate next device */ p = (isdn_net_dev *) p->next; continue; } } else {#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: 2nd channel is down and unbound\n");#endif /* No, swap always and swap excl-usage also */ isdn_net_swap_usage(idx, sidx); isdn_net_swapbind(di); swapped = 2; } /* Now check for exclusive binding again */#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: final check\n");#endif if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) && ((lp->pre_channel != ch) || (lp->pre_device != di))) {#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: final check failed\n");#endif p = (isdn_net_dev *) p->next; continue; } } } else { /* We are already on the second channel, so nothing to do */#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: already on 2nd channel\n");#endif } } }#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match2\n");#endif n = lp->phone[0]; if (lp->flags & ISDN_NET_SECURE) { while (n) { if (!isdn_msncmp(nr, n->num)) break; n = (isdn_net_phone *) n->next; } } if (n || (!(lp->flags & ISDN_NET_SECURE))) {#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match3\n");#endif /* matching interface found */ /* * Is the state STOPPED? * If so, no dialin is allowed, * so reject actively. * */ if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { restore_flags(flags); printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n", lp->name); return 3; } /* * Is the interface up? * If not, reject the call actively. */ if (!isdn_net_device_started(p)) { restore_flags(flags); printk(KERN_INFO "%s: incoming call, interface down -> rejected\n", lp->name); return 3; } /* Interface is up, now see if it's a slave. If so, see if * it's master and parent slave is online. If not, reject the call. */ if (lp->master) { isdn_net_local *mlp = (isdn_net_local *) lp->master->priv; printk(KERN_DEBUG "ICALLslv: %s\n", lp->name); printk(KERN_DEBUG "master=%s\n", mlp->name); if (mlp->flags & ISDN_NET_CONNECTED) { printk(KERN_DEBUG "master online\n"); /* Master is online, find parent-slave (master if first slave) */ while (mlp->slave) { if ((isdn_net_local *) mlp->slave->priv == lp) break; mlp = (isdn_net_local *) mlp->slave->priv; } } else printk(KERN_DEBUG "master offline\n"); /* Found parent, if it's offline iterate next device */ printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED); if (!(mlp->flags & ISDN_NET_CONNECTED)) { p = (isdn_net_dev *) p->next; continue; } } if (lp->flags & ISDN_NET_CALLBACK) { int chi; /* * Is the state MANUAL? * If so, no callback can be made, * so reject actively. * */ if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { restore_flags(flags); printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n", lp->name); return 3; } printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n", lp->name, nr, eaz); if (lp->phone[1]) { /* Grab a free ISDN-Channel */ if ((chi = isdn_get_free_channel( ISDN_USAGE_NET, lp->l2_proto, lp->l3_proto, lp->pre_device, lp->pre_channel, lp->msn) ) < 0) { printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name); restore_flags(flags); return 0; } /* Setup dialstate. */ lp->dtimer = 0; lp->dialstate = 11; /* Connect interface with channel */ isdn_net_bind_channel(lp, chi);#ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (isdn_ppp_bind(lp) < 0) { isdn_net_unbind_channel(lp); restore_flags(flags); return 0; }#endif /* Initiate dialing by returning 2 or 4 */ restore_flags(flags); return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4; } else printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name); restore_flags(flags); return 0; } else { printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr, eaz); /* if this interface is dialing, it does it probably on a different device, so free this device */ if ((lp->dialstate == 4) || (lp->dialstate == 12)) {#ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) isdn_ppp_free(lp);#endif isdn_net_lp_disconnected(lp); isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); } dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; dev->usage[idx] |= ISDN_USAGE_NET; strcpy(dev->num[idx], nr); isdn_info_update(); dev->st_netdev[idx] = lp->netdev; lp->isdn_device = di; lp->isdn_channel = ch; lp->ppp_slot = -1; lp->flags |= ISDN_NET_CONNECTED; lp->dialstate = 7; lp->dtimer = 0; lp->outgoing = 0; lp->huptimer = 0; lp->hupflags |= ISDN_WAITCHARGE; lp->hupflags &= ~ISDN_HAVECHARGE;#ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (isdn_ppp_bind(lp) < 0) { isdn_net_unbind_channel(lp); restore_flags(flags); return 0; }#endif restore_flags(flags); return 1; } } } p = (isdn_net_dev *) p->next; } /* If none of configured EAZ/MSN matched and not verbose, be silent */ if (!ematch || dev->net_verbose) printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz); restore_flags(flags); return (wret == 2)?5:0;}/* * Search list of net-interfaces for an interface with given name. */isdn_net_dev *isdn_net_findif(char *name){ isdn_net_dev *p = dev->netdev; while (p) { if (!strcmp(p->local->name, name)) return p; p = (isdn_net_dev *) p->next; } return (isdn_net_dev *) NULL;}/* * Force a net-interface to dial out. * This is called from the userlevel-routine below or * from isdn_net_start_xmit(). */intisdn_net_force_dial_lp(isdn_net_local * lp){ if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) { int chi; if (lp->phone[1]) { ulong flags; save_flags(flags); cli(); /* Grab a free ISDN-Channel */ if ((chi = isdn_get_free_channel( ISDN_USAGE_NET, lp->l2_proto, lp->l3_proto, lp->pre_device, lp->pre_channel, lp->msn) ) < 0) { printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name); restore_flags(flags); return -EAGAIN; } lp->dialstate = 1; /* Connect interface with channel */ isdn_net_bind_channel(lp, chi);#ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (isdn_ppp_bind(lp) < 0) { isdn_net_unbind_channel(lp); restore_flags(flags); return -EAGAIN; }#endif /* Initiate dialing */ restore_flags(flags); isdn_net_dial(); return 0; } else return -EINVAL; } else return -EBUSY;}/* * This is called from certain upper protocol layers (multilink ppp * and x25iface encapsulation module) that want to initiate dialing * themselves. */intisdn_net_dial_req(isdn_net_local * lp){ /* is there a better error code? */ if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY; return isdn_net_force_dial_lp(lp);}/* * Force a net-interface to dial out. * This is always called from within userspace (ISDN_IOCTL_NET_DIAL). */intisdn_net_force_dial(char *name){ isdn_net_dev *p = isdn_net_findif(name); if (!p) return -ENODEV; return (isdn_net_force_dial_lp(p->local));}/* * Allocate a new network-interface and initialize its data structures. */char *isdn_net_new(char *name, struct net_device *master){ isdn_net_dev *netdev; /* Avoid creating an existing interface */ if (isdn_net_findif(name)) { printk(KERN_WARNING "isdn_net: interface %s already exists\n", name); return NULL; } if (!(netdev = (isdn_net_dev *) kmalloc(sizeof(isdn_net_dev), GFP_KERNEL))) { printk(KERN_WARNING "isdn_net: Could not allocate net-device\n"); return NULL; } memset(netdev, 0, sizeof(isdn_net_dev)); if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) { printk(KERN_WARNING "isdn_net: Could not allocate device locals\n"); return NULL; } memset(netdev->local, 0, sizeof(isdn_net_local)); if (name == NULL) strcpy(netdev->local->name, " "); else strcpy(netdev->local->name, name); strcpy(netdev->dev.name, netdev->local->name); netdev->dev.priv = netdev->local; netdev->dev.init = isdn_net_init; netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP; if (master) { /* Device shall be a slave */ struct net_device *p = (((isdn_net_local *) master->priv)->slave); struct net_device *q = master; netdev->local->master = master; /* Put device at end of slave-chain */ while (p) { q = p; p = (((isdn_net_local *) p->priv)->slave); } ((isdn_net_local *) q->priv)->slave = &(netdev->dev); } else { /* Device shall be a master */ /* * Watchdog timer (currently) for master only. */ netdev->dev.tx_timeout = isdn_net_tx_timeout; netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT; if (register_netdev(&netdev->dev) != 0) { printk(KERN_WARNING "isdn_net: Could not register net-device\n"); kfree(netdev->local); kfree(netdev); return NULL; } } netdev->local->magic = ISDN_NET_MAGIC; netdev->queue = netdev->local; spin_lock_init(&netdev->queue_lock); netdev->local->last = netdev->local; netdev->local->netdev = netdev; netdev->local->next = netdev->local; netdev->local->tqueue.sync = 0; netdev->local->tqueue.routine = isdn_net_softint; netdev->local->tqueue.data = netdev->local; spin_lock_init(&netdev->local->xmit_lock); netdev->local->isdn_device = -1; netdev->local->isdn_channel = -1; netdev->local->pre_device = -1; netdev->local->pre_channel = -1; netdev->local->exclusive = -1; netdev->local->ppp_slot = -1; netdev->local->pp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -