📄 mpc.c
字号:
ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", mpc->dev->name); mpc->in_ops->put(entry); return 1; } ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", mpc->dev->name); /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */ if (iph->ttl <= 1) { ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", mpc->dev->name, iph->ttl); mpc->in_ops->put(entry); return 1; } iph->ttl--; iph->check = 0; iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); if (entry->ctrl_info.tag != 0) { ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag); tagged_llc_snap_hdr.tag = entry->ctrl_info.tag; skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ skb_push(skb, sizeof(tagged_llc_snap_hdr)); /* add LLC/SNAP header */ memcpy(skb->data, &tagged_llc_snap_hdr, sizeof(tagged_llc_snap_hdr)); } else { skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ skb_push(skb, sizeof(struct llc_snap_hdr)); /* add LLC/SNAP header + tag */ memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)); } atomic_add(skb->truesize, &entry->shortcut->tx_inuse); ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */ ATM_SKB(skb)->atm_options = entry->shortcut->atm_options; entry->shortcut->send(entry->shortcut, skb); entry->packets_fwded++; mpc->in_ops->put(entry); return 0;}/* * Probably needs some error checks and locking, not sure... */static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev){ int retval; struct mpoa_client *mpc; struct ethhdr *eth; int i = 0; mpc = find_mpc_by_lec(dev); /* this should NEVER fail */ if(mpc == NULL) { printk("mpoa: (%s) mpc_send_packet: no MPC found\n", dev->name); goto non_ip; } eth = (struct ethhdr *)skb->data; if (eth->h_proto != htons(ETH_P_IP)) goto non_ip; /* Multi-Protocol Over ATM :-) */ while (i < mpc->number_of_mps_macs) { if (memcmp(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN), ETH_ALEN) == 0) if ( send_via_shortcut(skb, mpc) == 0 ) /* try shortcut */ return 0; /* success! */ i++; } non_ip: retval = mpc->old_hard_start_xmit(skb,dev); return retval;}int atm_mpoa_vcc_attach(struct atm_vcc *vcc, long arg){ int bytes_left; struct mpoa_client *mpc; struct atmmpc_ioc ioc_data; in_cache_entry *in_entry; uint32_t ipaddr; unsigned char *ip; bytes_left = copy_from_user(&ioc_data, (void *)arg, sizeof(struct atmmpc_ioc)); if (bytes_left != 0) { printk("mpoa: mpc_vcc_attach: Short read (missed %d bytes) from userland\n", bytes_left); return -EFAULT; } ipaddr = ioc_data.ipaddr; if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF) return -EINVAL; mpc = find_mpc_by_itfnum(ioc_data.dev_num); if (mpc == NULL) return -EINVAL; if (ioc_data.type == MPC_SOCKET_INGRESS) { in_entry = mpc->in_ops->get(ipaddr, mpc); if (in_entry == NULL || in_entry->entry_state < INGRESS_RESOLVED) { printk("mpoa: (%s) mpc_vcc_attach: did not find RESOLVED entry from ingress cache\n", mpc->dev->name); if (in_entry != NULL) mpc->in_ops->put(in_entry); return -EINVAL; } ip = (unsigned char*)&in_entry->ctrl_info.in_dst_ip; printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %u.%u.%u.%u\n", mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); in_entry->shortcut = vcc; mpc->in_ops->put(in_entry); } else { printk("mpoa: (%s) mpc_vcc_attach: attaching egress SVC\n", mpc->dev->name); } vcc->proto_data = mpc->dev; vcc->push = mpc_push; return 0;}/* * */static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev){ struct mpoa_client *mpc; in_cache_entry *in_entry; eg_cache_entry *eg_entry; mpc = find_mpc_by_lec(dev); if (mpc == NULL) { printk("mpoa: (%s) mpc_vcc_close: close for unknown MPC\n", dev->name); return; } dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name); in_entry = mpc->in_ops->get_by_vcc(vcc, mpc); if (in_entry) { unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&in_entry->ctrl_info.in_dst_ip; dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %u.%u.%u.%u\n", mpc->dev->name, ip[0], ip[1], ip[2], ip[3]); in_entry->shortcut = NULL; mpc->in_ops->put(in_entry); } eg_entry = mpc->eg_ops->get_by_vcc(vcc, mpc); if (eg_entry) { dprintk("mpoa: (%s) mpc_vcc_close: egress SVC closed\n", mpc->dev->name); eg_entry->shortcut = NULL; mpc->eg_ops->put(eg_entry); } if (in_entry == NULL && eg_entry == NULL) dprintk("mpoa: (%s) mpc_vcc_close: unused vcc closed\n", dev->name); return;}static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb){ struct net_device *dev = (struct net_device *)vcc->proto_data; struct sk_buff *new_skb; eg_cache_entry *eg; struct mpoa_client *mpc; uint32_t tag; char *tmp; ddprintk("mpoa: (%s) mpc_push:\n", dev->name); if (skb == NULL) { dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", dev->name); mpc_vcc_close(vcc, dev); return; } skb->dev = dev; if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) { dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name); skb_queue_tail(&vcc->recvq, skb); /* Pass control packets to daemon */ wake_up(&vcc->sleep); return; } /* data coming over the shortcut */ atm_return(vcc, skb->truesize); mpc = find_mpc_by_lec(dev); if (mpc == NULL) { printk("mpoa: (%s) mpc_push: unknown MPC\n", dev->name); return; } if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */ ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", dev->name); } else if (memcmp(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */ printk("mpoa: (%s) mpc_push: non-tagged data packet arrived\n", dev->name); printk(" mpc_push: non-tagged data unsupported, purging\n"); dev_kfree_skb_any(skb); return; } else { printk("mpoa: (%s) mpc_push: garbage arrived, purging\n", dev->name); dev_kfree_skb_any(skb); return; } tmp = skb->data + sizeof(struct llc_snap_hdr); tag = *(uint32_t *)tmp; eg = mpc->eg_ops->get_by_tag(tag, mpc); if (eg == NULL) { printk("mpoa: (%s) mpc_push: Didn't find egress cache entry, tag = %u\n", dev->name,tag); purge_egress_shortcut(vcc, NULL); dev_kfree_skb_any(skb); return; } /* * See if ingress MPC is using shortcut we opened as a return channel. * This means we have a bi-directional vcc opened by us. */ if (eg->shortcut == NULL) { eg->shortcut = vcc; printk("mpoa: (%s) mpc_push: egress SVC in use\n", dev->name); } skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); /* get rid of LLC/SNAP header */ new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); /* LLC/SNAP is shorter than MAC header :( */ dev_kfree_skb_any(skb); if (new_skb == NULL){ mpc->eg_ops->put(eg); return; } skb_push(new_skb, eg->ctrl_info.DH_length); /* add MAC header */ memcpy(new_skb->data, eg->ctrl_info.DLL_header, eg->ctrl_info.DH_length); new_skb->protocol = eth_type_trans(new_skb, dev); new_skb->nh.raw = new_skb->data; eg->latest_ip_addr = new_skb->nh.iph->saddr; eg->packets_rcvd++; mpc->eg_ops->put(eg); netif_rx(new_skb); return;}static struct atmdev_ops mpc_ops = { /* only send is required */ close: mpoad_close, send: msg_from_mpoad};static struct atm_dev mpc_dev = { &mpc_ops, /* device operations */ NULL, /* PHY operations */ "mpc", /* device type name */ 42, /* device index (dummy) */ NULL, /* VCC table */ NULL, /* last VCC */ NULL, /* per-device data */ NULL, /* private PHY data */ { 0 }, /* device flags */ NULL, /* local ATM address */ { 0 } /* no ESI */ /* rest of the members will be 0 */};int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg){ struct mpoa_client *mpc; struct lec_priv *priv; if (mpcs == NULL) { init_timer(&mpc_timer); mpc_timer_refresh(); /* This lets us now how our LECs are doing */ register_netdevice_notifier(&mpoa_notifier); } mpc = find_mpc_by_itfnum(arg); if (mpc == NULL) { dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg); mpc = alloc_mpc(); mpc->dev_num = arg; mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */ } if (mpc->mpoad_vcc) { printk("mpoa: mpoad_attach: mpoad is already present for itf %d\n", arg); return -EADDRINUSE; } if (mpc->dev) { /* check if the lec is LANE2 capable */ priv = (struct lec_priv *)mpc->dev->priv; if (priv->lane_version < 2) mpc->dev = NULL; else priv->lane2_ops->associate_indicator = lane2_assoc_ind; } mpc->mpoad_vcc = vcc; bind_vcc(vcc, &mpc_dev); set_bit(ATM_VF_META,&vcc->flags); set_bit(ATM_VF_READY,&vcc->flags); if (mpc->dev) { char empty[ATM_ESA_LEN]; memset(empty, 0, ATM_ESA_LEN); start_mpc(mpc, mpc->dev); /* set address if mpcd e.g. gets killed and restarted. * If we do not do it now we have to wait for the next LE_ARP */ if ( memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0 ) send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc); } MOD_INC_USE_COUNT; return arg;}static void send_set_mps_ctrl_addr(char *addr, struct mpoa_client *mpc){ struct k_message mesg; memcpy (mpc->mps_ctrl_addr, addr, ATM_ESA_LEN); mesg.type = SET_MPS_CTRL_ADDR; memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN); msg_to_mpoad(&mesg, mpc); return;}static void mpoad_close(struct atm_vcc *vcc){ struct mpoa_client *mpc; struct sk_buff *skb; mpc = find_mpc_by_vcc(vcc); if (mpc == NULL) { printk("mpoa: mpoad_close: did not find MPC\n"); return; } if (!mpc->mpoad_vcc) { printk("mpoa: mpoad_close: close for non-present mpoad\n"); return; } mpc->mpoad_vcc = NULL; if (mpc->dev) { struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv; priv->lane2_ops->associate_indicator = NULL; stop_mpc(mpc); } mpc->in_ops->destroy_cache(mpc); mpc->eg_ops->destroy_cache(mpc); while ( (skb = skb_dequeue(&vcc->recvq)) ){ atm_return(vcc, skb->truesize); kfree_skb(skb); } printk("mpoa: (%s) going down\n", (mpc->dev) ? mpc->dev->name : "<unknown>"); MOD_DEC_USE_COUNT; return;}/* * */static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb){ struct mpoa_client *mpc = find_mpc_by_vcc(vcc); struct k_message *mesg = (struct k_message*)skb->data; atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse); if (mpc == NULL) { printk("mpoa: msg_from_mpoad: no mpc found\n"); return 0; } dprintk("mpoa: (%s) msg_from_mpoad:", (mpc->dev) ? mpc->dev->name : "<unknown>"); switch(mesg->type) { case MPOA_RES_REPLY_RCVD: dprintk(" mpoa_res_reply_rcvd\n"); MPOA_res_reply_rcvd(mesg, mpc); break; case MPOA_TRIGGER_RCVD: dprintk(" mpoa_trigger_rcvd\n"); MPOA_trigger_rcvd(mesg, mpc); break; case INGRESS_PURGE_RCVD: dprintk(" nhrp_purge_rcvd\n"); ingress_purge_rcvd(mesg, mpc); break; case EGRESS_PURGE_RCVD: dprintk(" egress_purge_reply_rcvd\n"); egress_purge_rcvd(mesg, mpc); break; case MPS_DEATH: dprintk(" mps_death\n"); mps_death(mesg, mpc); break; case CACHE_IMPOS_RCVD: dprintk(" cache_impos_rcvd\n"); MPOA_cache_impos_rcvd(mesg, mpc); break; case SET_MPC_CTRL_ADDR: dprintk(" set_mpc_ctrl_addr\n"); set_mpc_ctrl_addr_rcvd(mesg, mpc); break; case SET_MPS_MAC_ADDR: dprintk(" set_mps_mac_addr\n"); set_mps_mac_addr_rcvd(mesg, mpc); break; case CLEAN_UP_AND_EXIT: dprintk(" clean_up_and_exit\n"); clean_up(mesg, mpc, DIE); break; case RELOAD: dprintk(" reload\n"); clean_up(mesg, mpc, RELOAD); break; case SET_MPC_PARAMS: dprintk(" set_mpc_params\n"); mpc->parameters = mesg->content.params; break; default: dprintk(" unknown message %d\n", mesg->type); break; } kfree_skb(skb); return 0;}/* Remember that this function may not do things that sleep */int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc){ struct sk_buff *skb; if (mpc == NULL || !mpc->mpoad_vcc) { printk("mpoa: msg_to_mpoad: mesg %d to a non-existent mpoad\n", mesg->type); return -ENXIO; } skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); if (skb == NULL) return -ENOMEM; skb_put(skb, sizeof(struct k_message)); memcpy(skb->data, mesg, sizeof(struct k_message)); atm_force_charge(mpc->mpoad_vcc, skb->truesize); skb_queue_tail(&mpc->mpoad_vcc->recvq, skb); wake_up(&mpc->mpoad_vcc->sleep); return 0;}static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev_ptr){ struct net_device *dev; struct mpoa_client *mpc; struct lec_priv *priv; dev = (struct net_device *)dev_ptr; if (dev->name == NULL || strncmp(dev->name, "lec", 3)) return NOTIFY_DONE; /* we are only interested in lec:s */ switch (event) { case NETDEV_REGISTER: /* a new lec device was allocated */ priv = (struct lec_priv *)dev->priv; if (priv->lane_version < 2) break; priv->lane2_ops->associate_indicator = lane2_assoc_ind; mpc = find_mpc_by_itfnum(priv->itfnum); if (mpc == NULL) { dprintk("mpoa: mpoa_event_listener: allocating new mpc for %s\n", dev->name); mpc = alloc_mpc(); if (mpc == NULL) { printk("mpoa: mpoa_event_listener: no new mpc"); break; } } mpc->dev_num = priv->itfnum; mpc->dev = dev; dprintk("mpoa: (%s) was initialized\n", dev->name); break; case NETDEV_UNREGISTER: /* the lec device was deallocated */ mpc = find_mpc_by_lec(dev); if (mpc == NULL) break; dprintk("mpoa: device (%s) was deallocated\n", dev->name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -