⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isdn_net.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -