📄 isdn_net.c
字号:
skb = alloc_skb(hl + len, GFP_ATOMIC); if (skb) skb_reserve(skb, hl); else printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__); return skb;}/* cisco hdlck device private ioctls */static intisdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ isdn_net_local *lp = (isdn_net_local *) dev->priv; unsigned long len = 0; unsigned long expires = 0; int tmp = 0; int period = lp->cisco_keepalive_period; s8 debserint = lp->cisco_debserint; int rc = 0; if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK) return -EINVAL; switch (cmd) { /* get/set keepalive period */ case SIOCGKEEPPERIOD: len = (unsigned long)sizeof(lp->cisco_keepalive_period); if (copy_to_user(ifr->ifr_data, &lp->cisco_keepalive_period, len)) rc = -EFAULT; break; case SIOCSKEEPPERIOD: tmp = lp->cisco_keepalive_period; len = (unsigned long)sizeof(lp->cisco_keepalive_period); if (copy_from_user(&period, ifr->ifr_data, len)) rc = -EFAULT; if ((period > 0) && (period <= 32767)) lp->cisco_keepalive_period = period; else rc = -EINVAL; if (!rc && (tmp != lp->cisco_keepalive_period)) { expires = (unsigned long)(jiffies + lp->cisco_keepalive_period * HZ); mod_timer(&lp->cisco_timer, expires); printk(KERN_INFO "%s: Keepalive period set " "to %d seconds.\n", lp->name, lp->cisco_keepalive_period); } break; /* get/set debugging */ case SIOCGDEBSERINT: len = (unsigned long)sizeof(lp->cisco_debserint); if (copy_to_user(ifr->ifr_data, &lp->cisco_debserint, len)) rc = -EFAULT; break; case SIOCSDEBSERINT: len = (unsigned long)sizeof(lp->cisco_debserint); if (copy_from_user(&debserint, ifr->ifr_data, len)) rc = -EFAULT; if ((debserint >= 0) && (debserint <= 64)) lp->cisco_debserint = debserint; else rc = -EINVAL; break; default: rc = -EINVAL; break; } return (rc);}/* called via cisco_timer.function */static voidisdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data){ isdn_net_local *lp = (isdn_net_local *) data; struct sk_buff *skb; unsigned char *p; unsigned long last_cisco_myseq = lp->cisco_myseq; int myseq_diff = 0; if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) { printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); return; } lp->cisco_myseq++; myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen); if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) { /* line up -> down */ lp->cisco_line_state = 0; printk (KERN_WARNING "UPDOWN: Line protocol on Interface %s," " changed state to down\n", lp->name); /* should stop routing higher-level data accross */ } else if ((!lp->cisco_line_state) && (myseq_diff >= 0) && (myseq_diff <= 2)) { /* line down -> up */ lp->cisco_line_state = 1; printk (KERN_WARNING "UPDOWN: Line protocol on Interface %s," " changed state to up\n", lp->name); /* restart routing higher-level data accross */ } if (lp->cisco_debserint) printk (KERN_DEBUG "%s: HDLC " "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n", lp->name, last_cisco_myseq, lp->cisco_mineseen, ((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040), lp->cisco_yourseq, ((lp->cisco_line_state) ? "line up" : "line down")); skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); if (!skb) return; p = skb_put(skb, 4 + 14); /* cisco header */ p += put_u8 (p, CISCO_ADDR_UNICAST); p += put_u8 (p, CISCO_CTRL); p += put_u16(p, CISCO_TYPE_SLARP); /* slarp keepalive */ p += put_u32(p, CISCO_SLARP_KEEPALIVE); p += put_u32(p, lp->cisco_myseq); p += put_u32(p, lp->cisco_yourseq); p += put_u16(p, 0xffff); // reliablity, always 0xffff isdn_net_write_super(lp, skb); lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ; add_timer(&lp->cisco_timer);}static voidisdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp){ struct sk_buff *skb; unsigned char *p; skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); if (!skb) return; p = skb_put(skb, 4 + 14); /* cisco header */ p += put_u8 (p, CISCO_ADDR_UNICAST); p += put_u8 (p, CISCO_CTRL); p += put_u16(p, CISCO_TYPE_SLARP); /* slarp request */ p += put_u32(p, CISCO_SLARP_REQUEST); p += put_u32(p, 0); // address p += put_u32(p, 0); // netmask p += put_u16(p, 0); // unused isdn_net_write_super(lp, skb);}static void isdn_net_ciscohdlck_connected(isdn_net_local *lp){ lp->cisco_myseq = 0; lp->cisco_mineseen = 0; lp->cisco_yourseq = 0; lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT; lp->cisco_last_slarp_in = 0; lp->cisco_line_state = 0; lp->cisco_debserint = 0; /* send slarp request because interface/seq.no.s reset */ isdn_net_ciscohdlck_slarp_send_request(lp); init_timer(&lp->cisco_timer); lp->cisco_timer.data = (unsigned long) lp; lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive; lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ; add_timer(&lp->cisco_timer);}static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp){ del_timer(&lp->cisco_timer);}static voidisdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp){ struct sk_buff *skb; unsigned char *p; struct in_device *in_dev = NULL; u32 addr = 0; /* local ipv4 address */ u32 mask = 0; /* local netmask */ if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) { /* take primary(first) address of interface */ struct in_ifaddr *ifa = in_dev->ifa_list; if (ifa != NULL) { addr = ifa->ifa_local; mask = ifa->ifa_mask; } } skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); if (!skb) return; p = skb_put(skb, 4 + 14); /* cisco header */ p += put_u8 (p, CISCO_ADDR_UNICAST); p += put_u8 (p, CISCO_CTRL); p += put_u16(p, CISCO_TYPE_SLARP); /* slarp reply, send own ip/netmask; if values are nonsense remote * should think we are unable to provide it with an address via SLARP */ p += put_u32(p, CISCO_SLARP_REPLY); p += put_u32(p, addr); // address p += put_u32(p, mask); // netmask p += put_u16(p, 0); // unused isdn_net_write_super(lp, skb);}static voidisdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb){ unsigned char *p; int period; u32 code; u32 my_seq, addr; u32 your_seq, mask; u32 local; u16 unused; if (skb->len < 14) return; p = skb->data; p += get_u32(p, &code); switch (code) { case CISCO_SLARP_REQUEST: lp->cisco_yourseq = 0; isdn_net_ciscohdlck_slarp_send_reply(lp); break; case CISCO_SLARP_REPLY: addr = ntohl(*(u32 *)p); mask = ntohl(*(u32 *)(p+4)); if (mask != 0xfffffffc) goto slarp_reply_out; if ((addr & 3) == 0 || (addr & 3) == 3) goto slarp_reply_out; local = addr ^ 3; printk(KERN_INFO "%s: got slarp reply: " "remote ip: %d.%d.%d.%d, " "local ip: %d.%d.%d.%d " "mask: %d.%d.%d.%d\n", lp->name, HIPQUAD(addr), HIPQUAD(local), HIPQUAD(mask)); break; slarp_reply_out: printk(KERN_INFO "%s: got invalid slarp " "reply (%d.%d.%d.%d/%d.%d.%d.%d) " "- ignored\n", lp->name, HIPQUAD(addr), HIPQUAD(mask)); break; case CISCO_SLARP_KEEPALIVE: period = (int)((jiffies - lp->cisco_last_slarp_in + HZ/2 - 1) / HZ); if (lp->cisco_debserint && (period != lp->cisco_keepalive_period) && lp->cisco_last_slarp_in) { printk(KERN_DEBUG "%s: Keepalive period mismatch - " "is %d but should be %d.\n", lp->name, period, lp->cisco_keepalive_period); } lp->cisco_last_slarp_in = jiffies; p += get_u32(p, &my_seq); p += get_u32(p, &your_seq); p += get_u16(p, &unused); lp->cisco_yourseq = my_seq; lp->cisco_mineseen = your_seq; break; }}static voidisdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb){ unsigned char *p; u8 addr; u8 ctrl; u16 type; if (skb->len < 4) goto out_free; p = skb->data; p += get_u8 (p, &addr); p += get_u8 (p, &ctrl); p += get_u16(p, &type); skb_pull(skb, 4); if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) { printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n", lp->name, addr); goto out_free; } if (ctrl != CISCO_CTRL) { printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n", lp->name, ctrl); goto out_free; } switch (type) { case CISCO_TYPE_SLARP: isdn_net_ciscohdlck_slarp_in(lp, skb); goto out_free; case CISCO_TYPE_CDP: if (lp->cisco_debserint) printk(KERN_DEBUG "%s: Received CDP packet. use " "\"no cdp enable\" on cisco.\n", lp->name); goto out_free; default: /* no special cisco protocol */ skb->protocol = htons(type); netif_rx(skb); return; } out_free: kfree_skb(skb);}/* * 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_X25 struct concap_proto *cprot = lp -> netdev -> cprot;#endif 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: isdn_net_ciscohdlck_receive(lp, skb); return; 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: /* huptimer is done in isdn_ppp_push_higher */ 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -