📄 isdn_net.c
字号:
eth->h_proto = htons(type); else eth->h_proto = htons(len); /* * Set the source hardware address. */ if (saddr) memcpy(eth->h_source, saddr, dev->addr_len); else memcpy(eth->h_source, dev->dev_addr, dev->addr_len); /* * Anyway, the loopback-device should never use this function... */ if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { memset(eth->h_dest, 0, dev->addr_len); return ETH_HLEN /*(dev->hard_header_len)*/; } if (daddr) { memcpy(eth->h_dest, daddr, dev->addr_len); return ETH_HLEN /*dev->hard_header_len*/; } return -ETH_HLEN /*dev->hard_header_len*/;}/* * build an header * depends on encaps that is being used. */static intisdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned plen){ isdn_net_local *lp = dev->priv; unsigned char *p; ushort len = 0; switch (lp->p_encap) { case ISDN_NET_ENCAP_ETHER: len = my_eth_header(skb, dev, type, daddr, saddr, plen); break;#ifdef CONFIG_ISDN_PPP case ISDN_NET_ENCAP_SYNCPPP: /* stick on a fake header to keep fragmentation code happy. */ len = IPPP_MAX_HEADER; skb_push(skb,len); break;#endif case ISDN_NET_ENCAP_RAWIP: printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n"); len = 0; break; case ISDN_NET_ENCAP_IPTYP: /* ethernet type field */ *((ushort *) skb_push(skb, 2)) = htons(type); len = 2; break; case ISDN_NET_ENCAP_UIHDLC: /* HDLC with UI-Frames (for ispa with -h1 option) */ *((ushort *) skb_push(skb, 2)) = htons(0x0103); len = 2; break; case ISDN_NET_ENCAP_CISCOHDLC: case ISDN_NET_ENCAP_CISCOHDLCK: p = skb_push(skb, 4); p += put_u8 (p, CISCO_ADDR_UNICAST); p += put_u8 (p, CISCO_CTRL); p += put_u16(p, type); len = 4; break;#ifdef CONFIG_ISDN_X25 default: /* try if there are generic concap protocol routines */ if( lp-> netdev -> cprot ){ printk(KERN_WARNING "isdn_net_header called with concap_proto!\n"); len = 0; break; } break;#endif /* CONFIG_ISDN_X25 */ } return len;}/* We don't need to send arp, because we have point-to-point connections. */static intisdn_net_rebuild_header(struct sk_buff *skb){ struct net_device *dev = skb->dev; isdn_net_local *lp = dev->priv; int ret = 0; if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { struct ethhdr *eth = (struct ethhdr *) skb->data; /* * Only ARP/IP is currently supported */ if (eth->h_proto != htons(ETH_P_IP)) { printk(KERN_WARNING "isdn_net: %s don't know how to resolve type %d addresses?\n", dev->name, (int) eth->h_proto); memcpy(eth->h_source, dev->dev_addr, dev->addr_len); return 0; } /* * Try to get ARP to resolve the header. */#ifdef CONFIG_INET ret = arp_find(eth->h_dest, skb);#endif } return ret;}/* * Interface-setup. (just after registering a new interface) */static intisdn_net_init(struct net_device *ndev){ ushort max_hlhdr_len = 0; isdn_net_local *lp = (isdn_net_local *) ndev->priv; int drvidx, i; ether_setup(ndev); lp->org_hhc = ndev->hard_header_cache; lp->org_hcu = ndev->header_cache_update; /* Setup the generic properties */ ndev->hard_header = NULL; ndev->hard_header_cache = NULL; ndev->header_cache_update = NULL; ndev->mtu = 1500; ndev->flags = IFF_NOARP|IFF_POINTOPOINT; ndev->type = ARPHRD_ETHER; ndev->addr_len = ETH_ALEN; /* for clients with MPPP maybe higher values better */ ndev->tx_queue_len = 30; for (i = 0; i < ETH_ALEN; i++) ndev->broadcast[i] = 0xff; /* The ISDN-specific entries in the device structure. */ ndev->open = &isdn_net_open; ndev->hard_start_xmit = &isdn_net_start_xmit; /* * up till binding we ask the protocol layer to reserve as much * as we might need for HL layer */ for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) if (dev->drv[drvidx]) if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen) max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen; ndev->hard_header_len = ETH_HLEN + max_hlhdr_len; ndev->stop = &isdn_net_close; ndev->get_stats = &isdn_net_get_stats; ndev->rebuild_header = &isdn_net_rebuild_header; ndev->do_ioctl = NULL; return 0;}static voidisdn_net_swapbind(int drvidx){ isdn_net_dev *p;#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: swapping ch of %d\n", drvidx);#endif p = dev->netdev; while (p) { if (p->local->pre_device == drvidx) switch (p->local->pre_channel) { case 0: p->local->pre_channel = 1; break; case 1: p->local->pre_channel = 0; break; } p = (isdn_net_dev *) p->next; }}static voidisdn_net_swap_usage(int i1, int i2){ int u1 = dev->usage[i1] & ISDN_USAGE_EXCLUSIVE; int u2 = dev->usage[i2] & ISDN_USAGE_EXCLUSIVE;#ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: usage of %d and %d\n", i1, i2);#endif dev->usage[i1] &= ~ISDN_USAGE_EXCLUSIVE; dev->usage[i1] |= u2; dev->usage[i2] &= ~ISDN_USAGE_EXCLUSIVE; dev->usage[i2] |= u1; isdn_info_update();}/* * An incoming call-request has arrived. * Search the interface-chain for an appropriate interface. * If found, connect the interface to the ISDN-channel and initiate * D- and B-Channel-setup. If secure-flag is set, accept only * configured phone-numbers. If callback-flag is set, initiate * callback-dialing. * * Return-Value: 0 = No appropriate interface for this call. * 1 = Call accepted * 2 = Reject call, wait cbdelay, then call back * 3 = Reject call * 4 = Wait cbdelay, then call back * 5 = No appropriate interface for this call, * would eventually match if CID was longer. */intisdn_net_find_icall(int di, int ch, int idx, setup_parm *setup){ char *eaz; int si1; int si2; int ematch; int wret; int swapped; int sidx = 0; u_long flags; isdn_net_dev *p; isdn_net_phone *n; char nr[32]; char *my_eaz; /* Search name in netdev-chain */ 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 DATA and VOICE calls at this stage * local eaz is checked later for allowed call types */ if ((si1 != 7) && (si1 != 1)) { if (dev->net_verbose > 1) printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 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; /* check acceptable call types for DOV */ my_eaz = isdn_map_eaz2msn(lp->msn, di); if (si1 == 1) { /* it's a DOV call, check if we allow it */ if (*my_eaz == 'v' || *my_eaz == 'V' || *my_eaz == 'b' || *my_eaz == 'B') my_eaz++; /* skip to allow a match */ else my_eaz = NULL; /* force non match */ } else { /* it's a DATA call, check if we allow it */ if (*my_eaz == 'b' || *my_eaz == 'B') my_eaz++; /* skip to allow a match */ } if (my_eaz) matchret = isdn_msncmp(eaz, my_eaz); else matchret = 1; if (!matchret) 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) { 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)) { 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) { 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 */ spin_lock_irqsave(&dev->lock, flags); if ((chi = isd
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -