📄 lec.c
字号:
if (mesg->content.normal.no_source_le_narp) break; /* FALL THROUGH */ case l_arp_update: lec_arp_update(priv, mesg->content.normal.mac_addr, mesg->content.normal.atm_addr, mesg->content.normal.flag, mesg->content.normal.targetless_le_arp); pr_debug("lec: in l_arp_update\n"); if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */ pr_debug("lec: LANE2 3.1.5, got tlvs, size %d\n", mesg->sizeoftlvs); lane2_associate_ind(dev, mesg->content.normal.mac_addr, tmp, mesg->sizeoftlvs); } break; case l_config: priv->maximum_unknown_frame_count = mesg->content.config.maximum_unknown_frame_count; priv->max_unknown_frame_time = (mesg->content.config.max_unknown_frame_time * HZ); priv->max_retry_count = mesg->content.config.max_retry_count; priv->aging_time = (mesg->content.config.aging_time * HZ); priv->forward_delay_time = (mesg->content.config.forward_delay_time * HZ); priv->arp_response_time = (mesg->content.config.arp_response_time * HZ); priv->flush_timeout = (mesg->content.config.flush_timeout * HZ); priv->path_switching_delay = (mesg->content.config.path_switching_delay * HZ); priv->lane_version = mesg->content.config.lane_version; /* LANE2 */ priv->lane2_ops = NULL; if (priv->lane_version > 1) priv->lane2_ops = &lane2_ops; if (dev->change_mtu(dev, mesg->content.config.mtu)) printk("%s: change_mtu to %d failed\n", dev->name, mesg->content.config.mtu); priv->is_proxy = mesg->content.config.is_proxy; break; case l_flush_tran_id: lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr, mesg->content.normal.flag); break; case l_set_lecid: priv->lecid = (unsigned short)(0xffff & mesg->content.normal.flag); break; case l_should_bridge:#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) { struct net_bridge_fdb_entry *f; pr_debug ("%s: bridge zeppelin asks about %s\n", dev->name, print_mac(mac, mesg->content.proxy.mac_addr)); if (br_fdb_get_hook == NULL || dev->br_port == NULL) break; f = br_fdb_get_hook(dev->br_port->br, mesg->content.proxy.mac_addr); if (f != NULL && f->dst->dev != dev && f->dst->state == BR_STATE_FORWARDING) { /* hit from bridge table, send LE_ARP_RESPONSE */ struct sk_buff *skb2; struct sock *sk; pr_debug ("%s: entry found, responding to zeppelin\n", dev->name); skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); if (skb2 == NULL) { br_fdb_put_hook(f); break; } skb2->len = sizeof(struct atmlec_msg); skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg)); atm_force_charge(priv->lecd, skb2->truesize); sk = sk_atm(priv->lecd); skb_queue_tail(&sk->sk_receive_queue, skb2); sk->sk_data_ready(sk, skb2->len); } if (f != NULL) br_fdb_put_hook(f); }#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ break; default: printk("%s: Unknown message type %d\n", dev->name, mesg->type); dev_kfree_skb(skb); return -EINVAL; } dev_kfree_skb(skb); return 0;}static void lec_atm_close(struct atm_vcc *vcc){ struct sk_buff *skb; struct net_device *dev = (struct net_device *)vcc->proto_data; struct lec_priv *priv = (struct lec_priv *)dev->priv; priv->lecd = NULL; /* Do something needful? */ netif_stop_queue(dev); lec_arp_destroy(priv); if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) printk("%s lec_atm_close: closing with messages pending\n", dev->name); while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) { atm_return(vcc, skb->truesize); dev_kfree_skb(skb); } printk("%s: Shut down!\n", dev->name); module_put(THIS_MODULE);}static struct atmdev_ops lecdev_ops = { .close = lec_atm_close, .send = lec_atm_send};static struct atm_dev lecatm_dev = { .ops = &lecdev_ops, .type = "lec", .number = 999, /* dummy device number */ .lock = __SPIN_LOCK_UNLOCKED(lecatm_dev.lock)};/* * LANE2: new argument struct sk_buff *data contains * the LE_ARP based TLVs introduced in the LANE2 spec */static intsend_to_lecd(struct lec_priv *priv, atmlec_msg_type type, unsigned char *mac_addr, unsigned char *atm_addr, struct sk_buff *data){ struct sock *sk; struct sk_buff *skb; struct atmlec_msg *mesg; if (!priv || !priv->lecd) { return -1; } skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); if (!skb) return -1; skb->len = sizeof(struct atmlec_msg); mesg = (struct atmlec_msg *)skb->data; memset(mesg, 0, sizeof(struct atmlec_msg)); mesg->type = type; if (data != NULL) mesg->sizeoftlvs = data->len; if (mac_addr) memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN); else mesg->content.normal.targetless_le_arp = 1; if (atm_addr) memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN); atm_force_charge(priv->lecd, skb->truesize); sk = sk_atm(priv->lecd); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); if (data != NULL) { pr_debug("lec: about to send %d bytes of data\n", data->len); atm_force_charge(priv->lecd, data->truesize); skb_queue_tail(&sk->sk_receive_queue, data); sk->sk_data_ready(sk, skb->len); } return 0;}/* shamelessly stolen from drivers/net/net_init.c */static int lec_change_mtu(struct net_device *dev, int new_mtu){ if ((new_mtu < 68) || (new_mtu > 18190)) return -EINVAL; dev->mtu = new_mtu; return 0;}static void lec_set_multicast_list(struct net_device *dev){ /* * by default, all multicast frames arrive over the bus. * eventually support selective multicast service */ return;}static void lec_init(struct net_device *dev){ dev->change_mtu = lec_change_mtu; dev->open = lec_open; dev->stop = lec_close; dev->hard_start_xmit = lec_start_xmit; dev->tx_timeout = lec_tx_timeout; dev->get_stats = lec_get_stats; dev->set_multicast_list = lec_set_multicast_list; dev->do_ioctl = NULL; printk("%s: Initialized!\n", dev->name); return;}static unsigned char lec_ctrl_magic[] = { 0xff, 0x00, 0x01, 0x01};#define LEC_DATA_DIRECT_8023 2#define LEC_DATA_DIRECT_8025 3static int lec_is_data_direct(struct atm_vcc *vcc){ return ((vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8023) || (vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025));}static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb){ unsigned long flags; struct net_device *dev = (struct net_device *)vcc->proto_data; struct lec_priv *priv = (struct lec_priv *)dev->priv;#if DUMP_PACKETS >0 int i = 0; char buf[300]; printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name, vcc->vpi, vcc->vci);#endif if (!skb) { pr_debug("%s: null skb\n", dev->name); lec_vcc_close(priv, vcc); return; }#if DUMP_PACKETS > 0 printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name, skb->len, priv->lecid);#if DUMP_PACKETS >= 2 for (i = 0; i < skb->len && i < 99; i++) { sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]); }#elif DUMP_PACKETS >= 1 for (i = 0; i < skb->len && i < 30; i++) { sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]); }#endif /* DUMP_PACKETS >= 1 */ if (i == skb->len) printk("%s\n", buf); else printk("%s...\n", buf);#endif /* DUMP_PACKETS > 0 */ if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) { /* Control frame, to daemon */ struct sock *sk = sk_atm(vcc); pr_debug("%s: To daemon\n", dev->name); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); } else { /* Data frame, queue to protocol handlers */ struct lec_arp_table *entry; unsigned char *src, *dst; atm_return(vcc, skb->truesize); if (*(__be16 *) skb->data == htons(priv->lecid) || !priv->lecd || !(dev->flags & IFF_UP)) { /* * Probably looping back, or if lecd is missing, * lecd has gone down */ pr_debug("Ignoring frame...\n"); dev_kfree_skb(skb); return; }#ifdef CONFIG_TR if (priv->is_trdev) dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest; else#endif dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest; /* * If this is a Data Direct VCC, and the VCC does not match * the LE_ARP cache entry, delete the LE_ARP cache entry. */ spin_lock_irqsave(&priv->lec_arp_lock, flags); if (lec_is_data_direct(vcc)) {#ifdef CONFIG_TR if (priv->is_trdev) src = ((struct lecdatahdr_8025 *)skb->data)-> h_source; else#endif src = ((struct lecdatahdr_8023 *)skb->data)-> h_source; entry = lec_arp_find(priv, src); if (entry && entry->vcc != vcc) { lec_arp_remove(priv, entry); lec_arp_put(entry); } } spin_unlock_irqrestore(&priv->lec_arp_lock, flags); if (!(dst[0] & 0x01) && /* Never filter Multi/Broadcast */ !priv->is_proxy && /* Proxy wants all the packets */ memcmp(dst, dev->dev_addr, dev->addr_len)) { dev_kfree_skb(skb); return; } if (!hlist_empty(&priv->lec_arp_empty_ones)) { lec_arp_check_empties(priv, vcc, skb); } skb_pull(skb, 2); /* skip lec_id */#ifdef CONFIG_TR if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev); else#endif skb->protocol = eth_type_trans(skb, dev); priv->stats.rx_packets++; priv->stats.rx_bytes += skb->len; memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(skb); }}static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb){ struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc); struct net_device *dev = skb->dev; if (vpriv == NULL) { printk("lec_pop(): vpriv = NULL!?!?!?\n"); return; } vpriv->old_pop(vcc, skb); if (vpriv->xoff && atm_may_send(vcc, 0)) { vpriv->xoff = 0; if (netif_running(dev) && netif_queue_stopped(dev)) netif_wake_queue(dev); }}static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg){ struct lec_vcc_priv *vpriv; int bytes_left; struct atmlec_ioc ioc_data; /* Lecd must be up in this case */ bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc)); if (bytes_left != 0) { printk ("lec: lec_vcc_attach, copy from user failed for %d bytes\n", bytes_left); } if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF || !dev_lec[ioc_data.dev_num]) return -EINVAL; if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL))) return -ENOMEM; vpriv->xoff = 0; vpriv->old_pop = vcc->pop; vcc->user_back = vpriv; vcc->pop = lec_pop; lec_vcc_added(dev_lec[ioc_data.dev_num]->priv, &ioc_data, vcc, vcc->push); vcc->proto_data = dev_lec[ioc_data.dev_num]; vcc->push = lec_push; return 0;}static int lec_mcast_attach(struct atm_vcc *vcc, int arg){ if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg]) return -EINVAL; vcc->proto_data = dev_lec[arg]; return (lec_mcast_make((struct lec_priv *)dev_lec[arg]->priv, vcc));}/* Initialize device. */static int lecd_attach(struct atm_vcc *vcc, int arg){ int i; struct lec_priv *priv; if (arg < 0) i = 0; else i = arg;#ifdef CONFIG_TR if (arg >= MAX_LEC_ITF) return -EINVAL;#else /* Reserve the top NUM_TR_DEVS for TR */ if (arg >= (MAX_LEC_ITF - NUM_TR_DEVS)) return -EINVAL;#endif if (!dev_lec[i]) { int is_trdev, size; is_trdev = 0; if (i >= (MAX_LEC_ITF - NUM_TR_DEVS)) is_trdev = 1; size = sizeof(struct lec_priv);#ifdef CONFIG_TR if (is_trdev) dev_lec[i] = alloc_trdev(size); else#endif dev_lec[i] = alloc_etherdev(size); if (!dev_lec[i]) return -ENOMEM; snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i); if (register_netdev(dev_lec[i])) { free_netdev(dev_lec[i]); return -EINVAL; } priv = dev_lec[i]->priv; priv->is_trdev = is_trdev; lec_init(dev_lec[i]); } else { priv = dev_lec[i]->priv; if (priv->lecd) return -EADDRINUSE; } lec_arp_init(priv); priv->itfnum = i; /* LANE2 addition */ priv->lecd = vcc; vcc->dev = &lecatm_dev; vcc_insert_socket(sk_atm(vcc)); vcc->proto_data = dev_lec[i]; set_bit(ATM_VF_META, &vcc->flags); set_bit(ATM_VF_READY, &vcc->flags); /* Set default values to these variables */ priv->maximum_unknown_frame_count = 1; priv->max_unknown_frame_time = (1 * HZ); priv->vcc_timeout_period = (1200 * HZ); priv->max_retry_count = 1; priv->aging_time = (300 * HZ); priv->forward_delay_time = (15 * HZ); priv->topology_change = 0; priv->arp_response_time = (1 * HZ); priv->flush_timeout = (4 * HZ); priv->path_switching_delay = (6 * HZ); if (dev_lec[i]->flags & IFF_UP) { netif_start_queue(dev_lec[i]); } __module_get(THIS_MODULE); return i;}#ifdef CONFIG_PROC_FSstatic char *lec_arp_get_status_string(unsigned char status){ static char *lec_arp_status_string[] = { "ESI_UNKNOWN ", "ESI_ARP_PENDING ", "ESI_VC_PENDING ", "<Undefined> ", "ESI_FLUSH_PENDING ",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -