📄 isdn_net.c
字号:
ch->addr = CISCO_ADDR_UNICAST; ch->ctrl = 0; ch->type = htons(CISCO_TYPE_SLARP); s = (cisco_slarp *)skb_put(skb, sizeof(cisco_slarp)); if (is_reply) { s->code = htonl(CISCO_SLARP_REPLY); memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32)); memset(&s->slarp.reply.netmask, 0, sizeof(__u32)); } else { lp->cisco_myseq++; s->code = htonl(CISCO_SLARP_KEEPALIVE); s->slarp.keepalive.my_seq = htonl(lp->cisco_myseq); s->slarp.keepalive.your_seq = htonl(lp->cisco_yourseq); } s->rel = 0xffff; s->t1 = t >> 16; s->t0 = t & 0xffff; isdn_net_write_super(lp, skb);}static voidisdn_net_slarp_in(isdn_net_local *lp, struct sk_buff *skb){ cisco_slarp *s = (cisco_slarp *)skb->data; switch (ntohl(s->code)) { case CISCO_SLARP_REQUEST: isdn_net_slarp_send(lp, 1); break; case CISCO_SLARP_REPLY: /* Ignore replies */ break; case CISCO_SLARP_KEEPALIVE: lp->cisco_yourseq = s->slarp.keepalive.my_seq; if (ntohl(s->slarp.keepalive.my_seq == lp->cisco_myseq)) { if (lp->cisco_loop++ == 2) { printk(KERN_WARNING "%s: Keepalive Loop\n", lp->name); lp->cisco_myseq ^= jiffies; } } else lp->cisco_loop = 0; break; } kfree_skb(skb);}/* * Called every 10 sec. via timer-interrupt if * any network-interface has Cisco-Keepalive-Encapsulation * and is online. * Send Keepalive-Packet and re-schedule. */voidisdn_net_slarp_out(void){ isdn_net_dev *p = dev->netdev; int anymore = 0; while (p) { isdn_net_local *l = p->local; if ((l->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) && (l->flags & ISDN_NET_CONNECTED) && (!l->dialstate) ) { anymore = 1; isdn_net_slarp_send(l, 0); } p = (isdn_net_dev *) p->next; } isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, anymore);}/* * Got a packet from ISDN-Channel. */static voidisdn_net_receive(struct net_device *ndev, struct sk_buff *skb){ isdn_net_local *lp = (isdn_net_local *) ndev->priv; isdn_net_local *olp = lp; /* original 'lp' */#ifdef CONFIG_ISDN_PPP int proto = PPP_PROTOCOL(skb->data);#endif#ifdef CONFIG_ISDN_X25 struct concap_proto *cprot = lp -> netdev -> cprot;#endif cisco_hdr *ch; lp->transcount += skb->len; lp->stats.rx_packets++; lp->stats.rx_bytes += skb->len; if (lp->master) { /* Bundling: If device is a slave-device, deliver to master, also * handle master's statistics and hangup-timeout */ ndev = lp->master; lp = (isdn_net_local *) ndev->priv; lp->stats.rx_packets++; lp->stats.rx_bytes += skb->len; } skb->dev = ndev; skb->pkt_type = PACKET_HOST; skb->mac.raw = skb->data;#ifdef ISDN_DEBUG_NET_DUMP isdn_dumppkt("R:", skb->data, skb->len, 40);#endif switch (lp->p_encap) { case ISDN_NET_ENCAP_ETHER: /* Ethernet over ISDN */ olp->huptimer = 0; lp->huptimer = 0; skb->protocol = isdn_net_type_trans(skb, ndev); break; case ISDN_NET_ENCAP_UIHDLC: /* HDLC with UI-frame (for ispa with -h1 option) */ olp->huptimer = 0; lp->huptimer = 0; skb_pull(skb, 2); /* Fall through */ case ISDN_NET_ENCAP_RAWIP: /* RAW-IP without MAC-Header */ olp->huptimer = 0; lp->huptimer = 0; skb->protocol = htons(ETH_P_IP); break; case ISDN_NET_ENCAP_CISCOHDLCK: ch = (cisco_hdr *)skb->data; if ((ch->addr != CISCO_ADDR_UNICAST) && (ch->addr != CISCO_ADDR_BROADCAST) ) { printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n", lp->name, ch->addr); kfree_skb(skb); return; } if (ch->ctrl != 0) { printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n", lp->name, ch->ctrl); kfree_skb(skb); return; } switch (ntohs(ch->type)) { case CISCO_TYPE_INET: skb_pull(skb, 4); skb->protocol = htons(ETH_P_IP); break; case CISCO_TYPE_SLARP: skb_pull(skb, 4); isdn_net_slarp_in(olp, skb); return; default: printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n", lp->name, ch->type); kfree_skb(skb); return; } break; case ISDN_NET_ENCAP_CISCOHDLC: /* CISCO-HDLC IP with type field and fake I-frame-header */ skb_pull(skb, 2); /* Fall through */ case ISDN_NET_ENCAP_IPTYP: /* IP with type field */ olp->huptimer = 0; lp->huptimer = 0; skb->protocol = *(unsigned short *) &(skb->data[0]); skb_pull(skb, 2); if (*(unsigned short *) skb->data == 0xFFFF) skb->protocol = htons(ETH_P_802_3); break;#ifdef CONFIG_ISDN_PPP case ISDN_NET_ENCAP_SYNCPPP: /* * If encapsulation is syncppp, don't reset * huptimer on LCP packets. */ if (proto != PPP_LCP) { olp->huptimer = 0; lp->huptimer = 0; } isdn_ppp_receive(lp->netdev, olp, skb); return;#endif default:#ifdef CONFIG_ISDN_X25 /* try if there are generic sync_device receiver routines */ if(cprot) if(cprot -> pops) if( cprot -> pops -> data_ind){ cprot -> pops -> data_ind(cprot,skb); return; };#endif /* CONFIG_ISDN_X25 */ printk(KERN_WARNING "%s: unknown encapsulation, dropping\n", lp->name); kfree_skb(skb); return; } netif_rx(skb); return;}/* * A packet arrived via ISDN. Search interface-chain for a corresponding * interface. If found, deliver packet to receiver-function and return 1, * else return 0. */intisdn_net_rcv_skb(int idx, struct sk_buff *skb){ isdn_net_dev *p = dev->rx_netdev[idx]; if (p) { isdn_net_local *lp = p->local; if ((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate)) { isdn_net_receive(&p->dev, skb); return 1; } } return 0;}static intmy_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len){ struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); /* * Set the protocol type. For a packet of type ETH_P_802_3 we * put the length here instead. It is up to the 802.2 layer to * carry protocol information. */ if (type != ETH_P_802_3) 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; 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: skb_push(skb, 4); skb->data[0] = 0x0f; skb->data[1] = 0x00; *((ushort *) & skb->data[2]) = htons(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; if (ndev == NULL) { printk(KERN_WARNING "isdn_net_init: dev = NULL!\n"); return -ENODEV; } if (ndev->priv == NULL) { printk(KERN_WARNING "isdn_net_init: dev->priv = NULL!\n"); return -ENODEV; } 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;#ifdef CONFIG_ISDN_PPP ndev->do_ioctl = isdn_ppp_dev_ioctl;#endif 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -