1 #include <linux/kernel.h>
2 #include <linux/string.h>
3 #include <linux/timer.h>
4 #include <linux/init.h>
6 /* We are an ethernet device */
7 #include <linux/if_ether.h>
8 #include <linux/netdevice.h>
9 #include <linux/etherdevice.h>
11 #include <linux/skbuff.h>
13 #include <asm/byteorder.h>
14 #include <asm/uaccess.h>
15 #include <asm/checksum.h> /* for ip_fast_csum() */
18 #include <linux/proc_fs.h>
21 #include <linux/atmdev.h>
22 #include <linux/atmlec.h>
23 #include <linux/atmmpc.h>
25 #include <linux/config.h>
26 #include <linux/module.h>
31 #include "resources.h" /* for bind_vcc() */
34 * mpc.c: Implementation of MPOA client kernel part
38 #define dprintk printk /* debug */
40 #define dprintk(format,args...)
44 #define ddprintk printk /* more debug */
46 #define ddprintk(format,args...)
51 #define MPOA_TAG_LEN 4
53 /* mpc_daemon -> kernel */
54 static void MPOA_trigger_rcvd (struct k_message
*msg
, struct mpoa_client
*mpc
);
55 static void MPOA_res_reply_rcvd(struct k_message
*msg
, struct mpoa_client
*mpc
);
56 static void ingress_purge_rcvd(struct k_message
*msg
, struct mpoa_client
*mpc
);
57 static void egress_purge_rcvd(struct k_message
*msg
, struct mpoa_client
*mpc
);
58 static void mps_death(struct k_message
*msg
, struct mpoa_client
*mpc
);
59 static void clean_up(struct k_message
*msg
, struct mpoa_client
*mpc
, int action
);
60 static void MPOA_cache_impos_rcvd(struct k_message
*msg
, struct mpoa_client
*mpc
);
61 static void set_mpc_ctrl_addr_rcvd(struct k_message
*mesg
, struct mpoa_client
*mpc
);
62 static void set_mps_mac_addr_rcvd(struct k_message
*mesg
, struct mpoa_client
*mpc
);
64 static uint8_t *copy_macs(struct mpoa_client
*mpc
, uint8_t *router_mac
,
65 uint8_t *tlvs
, uint8_t mps_macs
, uint8_t device_type
);
66 static void purge_egress_shortcut(struct atm_vcc
*vcc
, eg_cache_entry
*entry
);
68 static void send_set_mps_ctrl_addr(char *addr
, struct mpoa_client
*mpc
);
69 static void mpoad_close(struct atm_vcc
*vcc
);
70 static int msg_from_mpoad(struct atm_vcc
*vcc
, struct sk_buff
*skb
);
72 static void mpc_push(struct atm_vcc
*vcc
, struct sk_buff
*skb
);
73 static int mpc_send_packet(struct sk_buff
*skb
, struct net_device
*dev
);
74 static int mpoa_event_listener(struct notifier_block
*mpoa_notifier
, unsigned long event
, void *dev
);
75 static void mpc_timer_refresh(void);
76 static void mpc_cache_check( unsigned long checking_time
);
78 static struct llc_snap_hdr llc_snap_mpoa_ctrl
= {
81 {0x00, 0x03} /* For MPOA control PDUs */
83 static struct llc_snap_hdr llc_snap_mpoa_data
= {
86 {0x08, 0x00} /* This is for IP PDUs only */
88 static struct llc_snap_hdr llc_snap_mpoa_data_tagged
= {
91 {0x88, 0x4c} /* This is for tagged data PDUs */
94 static struct notifier_block mpoa_notifier
= {
100 #ifdef CONFIG_PROC_FS
101 extern int mpc_proc_init(void);
102 extern void mpc_proc_clean(void);
105 struct mpoa_client
*mpcs
= NULL
; /* FIXME */
106 static struct atm_mpoa_qos
*qos_head
= NULL
;
107 static struct timer_list mpc_timer
;
110 static struct mpoa_client
*find_mpc_by_itfnum(int itf
)
112 struct mpoa_client
*mpc
;
114 mpc
= mpcs
; /* our global linked list */
115 while (mpc
!= NULL
) {
116 if (mpc
->dev_num
== itf
)
121 return NULL
; /* not found */
124 static struct mpoa_client
*find_mpc_by_vcc(struct atm_vcc
*vcc
)
126 struct mpoa_client
*mpc
;
128 mpc
= mpcs
; /* our global linked list */
129 while (mpc
!= NULL
) {
130 if (mpc
->mpoad_vcc
== vcc
)
135 return NULL
; /* not found */
138 static struct mpoa_client
*find_mpc_by_lec(struct net_device
*dev
)
140 struct mpoa_client
*mpc
;
142 mpc
= mpcs
; /* our global linked list */
143 while (mpc
!= NULL
) {
149 return NULL
; /* not found */
153 * Functions for managing QoS list
157 * Overwrites the old entry or makes a new one.
159 struct atm_mpoa_qos
*atm_mpoa_add_qos(uint32_t dst_ip
, struct atm_qos
*qos
)
161 struct atm_mpoa_qos
*entry
;
163 entry
= atm_mpoa_search_qos(dst_ip
);
169 entry
= kmalloc(sizeof(struct atm_qos
), GFP_KERNEL
);
171 printk("mpoa: atm_mpoa_add_qos: out of memory\n");
175 entry
->ipaddr
= dst_ip
;
178 entry
->next
= qos_head
;
184 struct atm_mpoa_qos
*atm_mpoa_search_qos(uint32_t dst_ip
)
186 struct atm_mpoa_qos
*qos
;
189 while( qos
!= NULL
){
190 if(qos
->ipaddr
== dst_ip
) {
200 * Returns 0 for failure
202 int atm_mpoa_delete_qos(struct atm_mpoa_qos
*entry
)
205 struct atm_mpoa_qos
*curr
;
207 if (entry
== NULL
) return 0;
208 if (entry
== qos_head
) {
209 qos_head
= qos_head
->next
;
215 while (curr
!= NULL
) {
216 if (curr
->next
== entry
) {
217 curr
->next
= entry
->next
;
227 void atm_mpoa_disp_qos(char *page
, int *len
)
232 struct atm_mpoa_qos
*qos
;
235 *len
+= sprintf(page
+ *len
, "QoS entries for shortcuts:\n");
236 *len
+= sprintf(page
+ *len
, "IP address\n TX:max_pcr pcr min_pcr max_cdv max_sdu\n RX:max_pcr pcr min_pcr max_cdv max_sdu\n");
238 ipaddr
[sizeof(ipaddr
)-1] = '\0';
239 while (qos
!= NULL
) {
240 ip
= (unsigned char *)&qos
->ipaddr
;
241 sprintf(ipaddr
, "%d.%d.%d.%d", ip
[0], ip
[1], ip
[2], ip
[3]);
242 *len
+= sprintf(page
+ *len
, "%-16s\n %-7d %-7d %-7d %-7d %-7d\n %-7d %-7d %-7d %-7d %-7d\n",
244 qos
->qos
.txtp
.max_pcr
, qos
->qos
.txtp
.pcr
, qos
->qos
.txtp
.min_pcr
, qos
->qos
.txtp
.max_cdv
, qos
->qos
.txtp
.max_sdu
,
245 qos
->qos
.rxtp
.max_pcr
, qos
->qos
.rxtp
.pcr
, qos
->qos
.rxtp
.min_pcr
, qos
->qos
.rxtp
.max_cdv
, qos
->qos
.rxtp
.max_sdu
);
252 static struct net_device
*find_lec_by_itfnum(int itf
)
254 extern struct atm_lane_ops atm_lane_ops
; /* in common.c */
256 if (atm_lane_ops
.get_lecs
== NULL
)
259 return atm_lane_ops
.get_lecs()[itf
]; /* FIXME: something better */
262 static struct mpoa_client
*alloc_mpc(void)
264 struct mpoa_client
*mpc
;
266 mpc
= kmalloc(sizeof (struct mpoa_client
), GFP_KERNEL
);
269 memset(mpc
, 0, sizeof(struct mpoa_client
));
270 #if 0 /* compiler seems to barf on this */
271 mpc
->ingress_lock
= RW_LOCK_UNLOCKED
;
272 mpc
->egress_lock
= RW_LOCK_UNLOCKED
;
275 atm_mpoa_init_cache(mpc
);
277 mpc
->parameters
.mpc_p1
= MPC_P1
;
278 mpc
->parameters
.mpc_p2
= MPC_P2
;
279 memset(mpc
->parameters
.mpc_p3
,0,sizeof(mpc
->parameters
.mpc_p3
));
280 mpc
->parameters
.mpc_p4
= MPC_P4
;
281 mpc
->parameters
.mpc_p5
= MPC_P5
;
282 mpc
->parameters
.mpc_p6
= MPC_P6
;
291 * start_mpc() puts the MPC on line. All the packets destined
292 * to the lec underneath us are now being monitored and
293 * shortcuts will be established.
296 static void start_mpc(struct mpoa_client
*mpc
, struct net_device
*dev
)
299 dprintk("mpoa: (%s) start_mpc:\n", mpc
->dev
->name
);
300 if (dev
->hard_start_xmit
== NULL
) {
301 printk("mpoa: (%s) start_mpc: dev->hard_start_xmit == NULL, not starting\n",
305 mpc
->old_hard_start_xmit
= dev
->hard_start_xmit
;
306 dev
->hard_start_xmit
= mpc_send_packet
;
311 static void stop_mpc(struct mpoa_client
*mpc
)
314 dprintk("mpoa: (%s) stop_mpc:", mpc
->dev
->name
);
316 /* Lets not nullify lec device's dev->hard_start_xmit */
317 if (mpc
->dev
->hard_start_xmit
!= mpc_send_packet
) {
318 dprintk(" mpc already stopped, not fatal\n");
322 mpc
->dev
->hard_start_xmit
= mpc
->old_hard_start_xmit
;
323 mpc
->old_hard_start_xmit
= NULL
;
324 /* close_shortcuts(mpc); ??? FIXME */
329 static const char *mpoa_device_type_string (char type
)
333 return "non-MPOA device";
342 return "both MPS and MPC";
345 return "unspecified (non-MPOA) device";
349 return ""; /* not reached */
353 * lec device calls this via its dev->priv->lane2_ops->associate_indicator()
354 * when it sees a TLV in LE_ARP packet.
355 * We fill in the pointer above when we see a LANE2 lec initializing
356 * See LANE2 spec 3.1.5
358 * Quite a big and ugly function but when you look at it
359 * all it does is to try to locate and parse MPOA Device
361 * We give our lec a pointer to this function and when the
362 * lec sees a TLV it uses the pointer to call this function.
365 static void lane2_assoc_ind(struct net_device
*dev
, uint8_t *mac_addr
,
366 uint8_t *tlvs
, uint32_t sizeoftlvs
)
369 uint8_t length
, mpoa_device_type
, number_of_mps_macs
;
370 uint8_t *end_of_tlvs
;
371 struct mpoa_client
*mpc
;
373 mpoa_device_type
= number_of_mps_macs
= 0; /* silence gcc */
374 dprintk("mpoa: (%s) lane2_assoc_ind: received TLV(s), ", dev
->name
);
375 dprintk("total length of all TLVs %d\n", sizeoftlvs
);
376 mpc
= find_mpc_by_lec(dev
); /* Sampo-Fix: moved here from below */
378 printk("mpoa: (%s) lane2_assoc_ind: no mpc\n", dev
->name
);
381 end_of_tlvs
= tlvs
+ sizeoftlvs
;
382 while (end_of_tlvs
- tlvs
>= 5) {
383 type
= (tlvs
[0] << 24) | (tlvs
[1] << 16) | (tlvs
[2] << 8) | tlvs
[3];
386 dprintk(" type 0x%x length %02x\n", type
, length
);
387 if (tlvs
+ length
> end_of_tlvs
) {
388 printk("TLV value extends past its buffer, aborting parse\n");
393 printk("mpoa: (%s) lane2_assoc_ind: TLV type was 0, returning\n", dev
->name
);
397 if (type
!= TLV_MPOA_DEVICE_TYPE
) {
399 continue; /* skip other TLVs */
401 mpoa_device_type
= *tlvs
++;
402 number_of_mps_macs
= *tlvs
++;
403 dprintk("mpoa: (%s) MPOA device type '%s', ", dev
->name
, mpoa_device_type_string(mpoa_device_type
));
404 if (mpoa_device_type
== MPS_AND_MPC
&&
405 length
< (42 + number_of_mps_macs
*ETH_ALEN
)) { /* :) */
406 printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n",
410 if ((mpoa_device_type
== MPS
|| mpoa_device_type
== MPC
)
411 && length
< 22 + number_of_mps_macs
*ETH_ALEN
) {
412 printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n",
416 if (mpoa_device_type
!= MPS
&& mpoa_device_type
!= MPS_AND_MPC
) {
417 dprintk("ignoring non-MPS device\n");
418 if (mpoa_device_type
== MPC
) tlvs
+= 20;
419 continue; /* we are only interested in MPSs */
421 if (number_of_mps_macs
== 0 && mpoa_device_type
== MPS_AND_MPC
) {
422 printk("\nmpoa: (%s) lane2_assoc_ind: MPS_AND_MPC has zero MACs\n", dev
->name
);
423 continue; /* someone should read the spec */
425 dprintk("this MPS has %d MAC addresses\n", number_of_mps_macs
);
427 /* ok, now we can go and tell our daemon the control address of MPS */
428 send_set_mps_ctrl_addr(tlvs
, mpc
);
430 tlvs
= copy_macs(mpc
, mac_addr
, tlvs
, number_of_mps_macs
, mpoa_device_type
);
431 if (tlvs
== NULL
) return;
433 if (end_of_tlvs
- tlvs
!= 0)
434 printk("mpoa: (%s) lane2_assoc_ind: ignoring %d bytes of trailing TLV carbage\n",
435 dev
->name
, end_of_tlvs
- tlvs
);
440 * Store at least advertizing router's MAC address
441 * plus the possible MAC address(es) to mpc->mps_macs.
442 * For a freshly allocated MPOA client mpc->mps_macs == 0.
444 static uint8_t *copy_macs(struct mpoa_client
*mpc
, uint8_t *router_mac
,
445 uint8_t *tlvs
, uint8_t mps_macs
, uint8_t device_type
)
448 num_macs
= (mps_macs
> 1) ? mps_macs
: 1;
450 if (mpc
->number_of_mps_macs
!= num_macs
) { /* need to reallocate? */
451 if (mpc
->number_of_mps_macs
!= 0) kfree(mpc
->mps_macs
);
452 mpc
->number_of_mps_macs
= 0;
453 mpc
->mps_macs
= kmalloc(num_macs
*ETH_ALEN
, GFP_KERNEL
);
454 if (mpc
->mps_macs
== NULL
) {
455 printk("mpoa: (%s) copy_macs: out of mem\n", mpc
->dev
->name
);
459 memcpy(mpc
->mps_macs
, router_mac
, ETH_ALEN
);
460 tlvs
+= 20; if (device_type
== MPS_AND_MPC
) tlvs
+= 20;
462 memcpy(mpc
->mps_macs
, tlvs
, mps_macs
*ETH_ALEN
);
463 tlvs
+= mps_macs
*ETH_ALEN
;
464 mpc
->number_of_mps_macs
= num_macs
;
469 /* FIXME: tarvitsee työtä */
470 static int send_via_shortcut(struct sk_buff
*skb
, struct mpoa_client
*mpc
)
472 in_cache_entry
*entry
;
478 struct llc_snap_hdr hdr
;
480 } tagged_llc_snap_hdr
= {
481 {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}},
485 buff
= skb
->data
+ mpc
->dev
->hard_header_len
;
486 iph
= (struct iphdr
*)buff
;
489 ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc
->dev
->name
, ipaddr
);
491 entry
= mpc
->in_ops
->search(ipaddr
, mpc
);
493 mpc
->in_ops
->new_entry(ipaddr
, mpc
);
496 if (mpc
->in_ops
->cache_hit(entry
, mpc
) != OPEN
){ /* threshold not exceeded or VCC not ready */
497 ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", mpc
->dev
->name
);
501 ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", mpc
->dev
->name
);
502 /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */
504 ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", mpc
->dev
->name
, iph
->ttl
);
509 iph
->check
= ip_fast_csum((unsigned char *)iph
, iph
->ihl
);
511 if (entry
->ctrl_info
.tag
!= 0) {
512 ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", mpc
->dev
->name
, entry
->ctrl_info
.tag
);
513 tagged_llc_snap_hdr
.tag
= entry
->ctrl_info
.tag
;
514 skb_pull(skb
, ETH_HLEN
); /* get rid of Eth header */
515 skb_push(skb
, sizeof(tagged_llc_snap_hdr
)); /* add LLC/SNAP header */
516 memcpy(skb
->data
, &tagged_llc_snap_hdr
, sizeof(tagged_llc_snap_hdr
));
518 skb_pull(skb
, ETH_HLEN
); /* get rid of Eth header */
519 skb_push(skb
, sizeof(struct llc_snap_hdr
)); /* add LLC/SNAP header + tag */
520 memcpy(skb
->data
, &llc_snap_mpoa_data
, sizeof(struct llc_snap_hdr
));
523 atomic_add(skb
->truesize
, &entry
->shortcut
->tx_inuse
);
524 ATM_SKB(skb
)->iovcnt
= 0; /* just to be safe ... */
525 ATM_SKB(skb
)->atm_options
= entry
->shortcut
->atm_options
;
526 entry
->shortcut
->dev
->ops
->send(entry
->shortcut
, skb
);
527 entry
->packets_fwded
++;
533 * Probably needs some error checks and locking, not sure...
535 static int mpc_send_packet(struct sk_buff
*skb
, struct net_device
*dev
)
538 struct mpoa_client
*mpc
;
542 mpc
= find_mpc_by_lec(dev
); /* this should NEVER fail */
544 printk("mpoa: (%s) mpc_send_packet: no MPC found\n", dev
->name
);
548 eth
= (struct ethhdr
*)skb
->data
;
549 if (eth
->h_proto
!= htons(ETH_P_IP
))
550 goto non_ip
; /* Multi-Protocol Over ATM :-) */
552 while (i
< mpc
->number_of_mps_macs
) {
553 if (memcmp(eth
->h_dest
, (mpc
->mps_macs
+ i
*ETH_ALEN
), ETH_ALEN
) == 0)
554 if ( send_via_shortcut(skb
, mpc
) == 0 ) /* try shortcut */
555 return 0; /* success! */
560 retval
= mpc
->old_hard_start_xmit(skb
,dev
);
565 int atm_mpoa_vcc_attach(struct atm_vcc
*vcc
, long arg
)
568 struct mpoa_client
*mpc
;
569 struct atmmpc_ioc ioc_data
;
570 in_cache_entry
*in_entry
;
574 bytes_left
= copy_from_user(&ioc_data
, (void *)arg
, sizeof(struct atmmpc_ioc
));
575 if (bytes_left
!= 0) {
576 printk("mpoa: mpc_vcc_attach: Short read (missed %d bytes) from userland\n", bytes_left
);
579 ipaddr
= ioc_data
.ipaddr
;
580 if (ioc_data
.dev_num
< 0 || ioc_data
.dev_num
>= MAX_LEC_ITF
)
583 mpc
= find_mpc_by_itfnum(ioc_data
.dev_num
);
587 if (ioc_data
.type
== MPC_SOCKET_INGRESS
) {
588 in_entry
= mpc
->in_ops
->search(ipaddr
, mpc
);
589 if (in_entry
== NULL
|| in_entry
->entry_state
< INGRESS_RESOLVED
) {
590 printk("mpoa: (%s) mpc_vcc_attach: did not find RESOLVED entry from ingress cache\n",
594 ip
= (unsigned char*)&in_entry
->ctrl_info
.in_dst_ip
;
595 printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %u.%u.%u.%u\n",
596 mpc
->dev
->name
, ip
[0], ip
[1], ip
[2], ip
[3]);
597 in_entry
->shortcut
= vcc
;
599 printk("mpoa: (%s) mpc_vcc_attach: attaching egress SVC\n", mpc
->dev
->name
);
602 vcc
->proto_data
= mpc
->dev
;
603 vcc
->push
= mpc_push
;
611 static void mpc_vcc_close(struct atm_vcc
*vcc
, struct net_device
*dev
)
613 struct mpoa_client
*mpc
;
614 in_cache_entry
*in_entry
;
615 eg_cache_entry
*eg_entry
;
617 mpc
= find_mpc_by_lec(dev
);
619 printk("mpoa: (%s) mpc_vcc_close: close for unknown MPC\n", dev
->name
);
623 dprintk("mpoa: (%s) mpc_vcc_close:\n", dev
->name
);
624 in_entry
= mpc
->in_ops
->search_by_vcc(vcc
, mpc
);
626 unsigned char *ip
= (unsigned char *)&in_entry
->ctrl_info
.in_dst_ip
;
627 dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %u.%u.%u.%u\n",
628 mpc
->dev
->name
, ip
[0], ip
[1], ip
[2], ip
[3]);
629 in_entry
->shortcut
= NULL
;
631 eg_entry
= mpc
->eg_ops
->search_by_vcc(vcc
, mpc
);
633 dprintk("mpoa: (%s) mpc_vcc_close: egress SVC closed\n", mpc
->dev
->name
);
634 eg_entry
->shortcut
= NULL
;
637 if (in_entry
== NULL
&& eg_entry
== NULL
)
638 dprintk("mpoa: (%s) mpc_vcc_close: unused vcc closed\n", dev
->name
);
643 static void mpc_push(struct atm_vcc
*vcc
, struct sk_buff
*skb
)
645 struct net_device
*dev
= (struct net_device
*)vcc
->proto_data
;
646 struct sk_buff
*new_skb
;
648 struct mpoa_client
*mpc
;
652 ddprintk("mpoa: (%s) mpc_push:\n", dev
->name
);
654 dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", dev
->name
);
655 mpc_vcc_close(vcc
, dev
);
660 if (memcmp(skb
->data
, &llc_snap_mpoa_ctrl
, sizeof(struct llc_snap_hdr
)) == 0) {
661 dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev
->name
);
662 skb_queue_tail(&vcc
->recvq
, skb
); /* Pass control packets to daemon */
663 wake_up(&vcc
->sleep
);
667 /* data coming over the shortcut */
668 atm_return(vcc
, skb
->truesize
);
670 mpc
= find_mpc_by_lec(dev
);
672 printk("mpoa: (%s) mpc_push: unknown MPC\n", dev
->name
);
676 if (memcmp(skb
->data
, &llc_snap_mpoa_data_tagged
, sizeof(struct llc_snap_hdr
)) == 0) { /* MPOA tagged data */
677 ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", dev
->name
);
679 } else if (memcmp(skb
->data
, &llc_snap_mpoa_data
, sizeof(struct llc_snap_hdr
)) == 0) { /* MPOA data */
680 printk("mpoa: (%s) mpc_push: non-tagged data packet arrived\n", dev
->name
);
681 printk(" mpc_push: non-tagged data unsupported, purging\n");
685 printk("mpoa: (%s) mpc_push: garbage arrived, purging\n", dev
->name
);
690 tmp
= skb
->data
+ sizeof(struct llc_snap_hdr
);
691 tag
= *(uint32_t *)tmp
;
693 eg
= mpc
->eg_ops
->search_by_tag(tag
, mpc
);
695 printk("mpoa: (%s) mpc_push: Didn't find egress cache entry, tag = %u\n",
697 purge_egress_shortcut(vcc
, NULL
);
703 * See if ingress MPC is using shortcut we opened as a return channel.
704 * This means we have a bi-directional vcc opened by us.
706 if (eg
->shortcut
== NULL
) {
708 printk("mpoa: (%s) mpc_push: egress SVC in use\n", dev
->name
);
711 skb_pull(skb
, sizeof(struct llc_snap_hdr
) + sizeof(tag
)); /* get rid of LLC/SNAP header */
712 new_skb
= skb_realloc_headroom(skb
, eg
->ctrl_info
.DH_length
); /* LLC/SNAP is shorter than MAC header :( */
714 if (new_skb
== NULL
) return;
715 skb_push(new_skb
, eg
->ctrl_info
.DH_length
); /* add MAC header */
716 memcpy(new_skb
->data
, eg
->ctrl_info
.DLL_header
, eg
->ctrl_info
.DH_length
);
717 new_skb
->protocol
= eth_type_trans(new_skb
, dev
);
718 new_skb
->nh
.raw
= new_skb
->data
;
720 eg
->latest_ip_addr
= new_skb
->nh
.iph
->saddr
;
728 static struct atmdev_ops mpc_ops
= { /* only send is required */
729 NULL
, /* dev_close */
731 mpoad_close
, /* close */
733 NULL
, /* getsockopt */
734 NULL
, /* setsockopt */
735 msg_from_mpoad
, /* send */
741 NULL
, /* change_qos */
742 NULL
, /* free_rx_skb */
746 static struct atm_dev mpc_dev
= {
747 &mpc_ops
, /* device operations */
748 NULL
, /* PHY operations */
749 "mpc", /* device type name */
750 42, /* device index (dummy) */
751 NULL
, /* VCC table */
753 NULL
, /* per-device data */
754 NULL
, /* private PHY data */
755 0, /* device flags */
756 NULL
, /* local ATM address */
758 /* rest of the members will be 0 */
761 int atm_mpoa_mpoad_attach (struct atm_vcc
*vcc
, int arg
)
763 struct mpoa_client
*mpc
;
764 struct lec_priv
*priv
;
767 init_timer(&mpc_timer
);
770 /* This lets us now how our LECs are doing */
771 register_netdevice_notifier(&mpoa_notifier
);
774 mpc
= find_mpc_by_itfnum(arg
);
776 dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg
);
779 mpc
->dev
= find_lec_by_itfnum(arg
); /* NULL if there was no lec */
781 if (mpc
->mpoad_vcc
) {
782 printk("mpoa: mpoad_attach: mpoad is already present for itf %d\n", arg
);
786 if (mpc
->dev
) { /* check if the lec is LANE2 capable */
787 priv
= (struct lec_priv
*)mpc
->dev
->priv
;
788 if (priv
->lane_version
< 2)
791 priv
->lane2_ops
->associate_indicator
= lane2_assoc_ind
;
794 mpc
->mpoad_vcc
= vcc
;
795 bind_vcc(vcc
, &mpc_dev
);
796 vcc
->flags
|= ATM_VF_READY
| ATM_VF_META
;
799 char empty
[ATM_ESA_LEN
];
800 memset(empty
, 0, ATM_ESA_LEN
);
802 start_mpc(mpc
, mpc
->dev
);
803 /* set address if mpcd e.g. gets killed and restarted.
804 * If we do not do it now we have to wait for the next LE_ARP
806 if ( memcmp(mpc
->mps_ctrl_addr
, empty
, ATM_ESA_LEN
) != 0 )
807 send_set_mps_ctrl_addr(mpc
->mps_ctrl_addr
, mpc
);
814 static void send_set_mps_ctrl_addr(char *addr
, struct mpoa_client
*mpc
)
816 struct k_message mesg
;
818 memcpy (mpc
->mps_ctrl_addr
, addr
, ATM_ESA_LEN
);
820 mesg
.type
= SET_MPS_CTRL_ADDR
;
821 memcpy(mesg
.MPS_ctrl
, addr
, ATM_ESA_LEN
);
822 msg_to_mpoad(&mesg
, mpc
);
827 static void mpoad_close(struct atm_vcc
*vcc
)
830 struct mpoa_client
*mpc
;
833 mpc
= find_mpc_by_vcc(vcc
);
835 printk("mpoa: mpoad_close: did not find MPC\n");
838 if (!mpc
->mpoad_vcc
) {
839 printk("mpoa: mpoad_close: close for non-present mpoad\n");
843 mpc
->mpoad_vcc
= NULL
;
845 struct lec_priv
*priv
= (struct lec_priv
*)mpc
->dev
->priv
;
846 priv
->lane2_ops
->associate_indicator
= NULL
;
850 /* clear the caches */
851 write_lock_irqsave(&mpc
->ingress_lock
, flags
);
852 while(mpc
->in_ops
->cache_remove(mpc
->in_cache
, mpc
));
853 write_unlock_irqrestore(&mpc
->ingress_lock
, flags
);
855 write_lock_irqsave(&mpc
->egress_lock
, flags
);
856 while(mpc
->eg_ops
->cache_remove(mpc
->eg_cache
, mpc
));
857 write_unlock_irqrestore(&mpc
->egress_lock
, flags
);
859 while ( (skb
= skb_dequeue(&vcc
->recvq
)) ){
860 atm_return(vcc
, skb
->truesize
);
864 printk("mpoa: (%s) going down\n",
865 (mpc
->dev
) ? mpc
->dev
->name
: "<unknown>");
874 static int msg_from_mpoad(struct atm_vcc
*vcc
, struct sk_buff
*skb
)
877 struct mpoa_client
*mpc
= find_mpc_by_vcc(vcc
);
878 struct k_message
*mesg
= (struct k_message
*)skb
->data
;
879 atomic_sub(skb
->truesize
+ATM_PDU_OVHD
, &vcc
->tx_inuse
);
882 printk("mpoa: msg_from_mpoad: no mpc found\n");
885 dprintk("mpoa: (%s) msg_from_mpoad:", (mpc
->dev
) ? mpc
->dev
->name
: "<unknown>");
887 case MPOA_RES_REPLY_RCVD
:
888 dprintk(" mpoa_res_reply_rcvd\n");
889 MPOA_res_reply_rcvd(mesg
, mpc
);
891 case MPOA_TRIGGER_RCVD
:
892 dprintk(" mpoa_trigger_rcvd\n");
893 MPOA_trigger_rcvd(mesg
, mpc
);
895 case INGRESS_PURGE_RCVD
:
896 dprintk(" nhrp_purge_rcvd\n");
897 ingress_purge_rcvd(mesg
, mpc
);
899 case EGRESS_PURGE_RCVD
:
900 dprintk(" egress_purge_reply_rcvd\n");
901 egress_purge_rcvd(mesg
, mpc
);
904 dprintk(" mps_death\n");
905 mps_death(mesg
, mpc
);
907 case CACHE_IMPOS_RCVD
:
908 dprintk(" cache_impos_rcvd\n");
909 MPOA_cache_impos_rcvd(mesg
, mpc
);
911 case SET_MPC_CTRL_ADDR
:
912 dprintk(" set_mpc_ctrl_addr\n");
913 set_mpc_ctrl_addr_rcvd(mesg
, mpc
);
915 case SET_MPS_MAC_ADDR
:
916 dprintk(" set_mps_mac_addr\n");
917 set_mps_mac_addr_rcvd(mesg
, mpc
);
919 case CLEAN_UP_AND_EXIT
:
920 dprintk(" clean_up_and_exit\n");
921 clean_up(mesg
, mpc
, DIE
);
924 dprintk(" reload\n");
925 clean_up(mesg
, mpc
, RELOAD
);
928 dprintk(" set_mpc_params\n");
929 mpc
->parameters
= mesg
->content
.params
;
932 dprintk(" unknown message %d\n", mesg
->type
);
940 int msg_to_mpoad(struct k_message
*mesg
, struct mpoa_client
*mpc
)
944 if (mpc
== NULL
|| !mpc
->mpoad_vcc
) {
945 printk("mpoa: msg_to_mpoad: mesg %d to a non-existent mpoad\n", mesg
->type
);
949 skb
= alloc_skb(sizeof(struct k_message
), GFP_ATOMIC
);
952 skb_put(skb
, sizeof(struct k_message
));
953 memcpy(skb
->data
, mesg
, sizeof(struct k_message
));
954 atm_force_charge(mpc
->mpoad_vcc
, skb
->truesize
);
955 skb_queue_tail(&mpc
->mpoad_vcc
->recvq
, skb
);
956 wake_up(&mpc
->mpoad_vcc
->sleep
);
961 static int mpoa_event_listener(struct notifier_block
*mpoa_notifier
, unsigned long event
, void *dev_ptr
)
963 struct net_device
*dev
;
964 struct mpoa_client
*mpc
;
965 struct lec_priv
*priv
;
967 dev
= (struct net_device
*)dev_ptr
;
968 if (dev
->name
== NULL
|| strncmp(dev
->name
, "lec", 3))
969 return NOTIFY_DONE
; /* we are only interested in lec:s */
972 case NETDEV_REGISTER
: /* a new lec device was allocated */
973 priv
= (struct lec_priv
*)dev
->priv
;
974 if (priv
->lane_version
< 2)
976 priv
->lane2_ops
->associate_indicator
= lane2_assoc_ind
;
977 mpc
= find_mpc_by_itfnum(priv
->itfnum
);
979 dprintk("mpoa: mpoa_event_listener: allocating new mpc for %s\n",
983 printk("mpoa: mpoa_event_listener: no new mpc");
987 mpc
->dev_num
= priv
->itfnum
;
989 dprintk("mpoa: (%s) was initialized\n", dev
->name
);
991 case NETDEV_UNREGISTER
:
992 /* the lec device was deallocated */
993 mpc
= find_mpc_by_lec(dev
);
996 dprintk("mpoa: device (%s) was deallocated\n", dev
->name
);
1001 /* the dev was ifconfig'ed up */
1002 mpc
= find_mpc_by_lec(dev
);
1005 if (mpc
->mpoad_vcc
!= NULL
) {
1006 start_mpc(mpc
, dev
);
1010 /* the dev was ifconfig'ed down */
1011 /* this means dev->start == 0 and
1012 * the flow of packets from the
1015 mpc
= find_mpc_by_lec(dev
);
1018 if (mpc
->mpoad_vcc
!= NULL
) {
1024 case NETDEV_CHANGEMTU
:
1025 case NETDEV_CHANGEADDR
:
1026 case NETDEV_GOING_DOWN
:
1036 * Functions which are called after a message is received from mpcd.
1037 * Msg is reused on purpose.
1041 static void MPOA_trigger_rcvd(struct k_message
*msg
, struct mpoa_client
*client
)
1043 uint32_t dst_ip
= msg
->content
.in_info
.in_dst_ip
;
1044 in_cache_entry
*entry
;
1046 entry
= client
->in_ops
->search(dst_ip
, client
);
1047 if( entry
== NULL
){
1048 entry
= client
->in_ops
->new_entry(dst_ip
, client
);
1049 entry
->entry_state
= INGRESS_RESOLVING
;
1050 msg
->type
= SND_MPOA_RES_RQST
;
1051 msg
->content
.in_info
= entry
->ctrl_info
;
1052 msg_to_mpoad(msg
,client
);
1053 do_gettimeofday(&(entry
->reply_wait
));
1057 if( entry
->entry_state
== INGRESS_INVALID
){
1058 entry
->entry_state
= INGRESS_RESOLVING
;
1059 msg
->type
= SND_MPOA_RES_RQST
;
1060 msg
->content
.in_info
= entry
->ctrl_info
;
1061 msg_to_mpoad(msg
,client
);
1062 do_gettimeofday(&(entry
->reply_wait
));
1066 printk("mpoa: (%s) MPOA_trigger_rcvd: entry already in resolving state\n",
1067 (client
->dev
) ? client
->dev
->name
: "<unknown>");
1072 * Things get complicated because we have to check if there's an egress
1073 * shortcut with suitable traffic parameters we could use.
1075 static void check_qos_and_open_shortcut(struct k_message
*msg
, struct mpoa_client
*client
, in_cache_entry
*entry
){
1076 uint32_t dst_ip
= msg
->content
.in_info
.in_dst_ip
;
1077 unsigned char *ip
= (unsigned char *)&dst_ip
;
1078 struct atm_mpoa_qos
*qos
= atm_mpoa_search_qos(dst_ip
);
1079 eg_cache_entry
*eg_entry
= client
->eg_ops
->search_by_src_ip(dst_ip
, client
);
1080 if(eg_entry
&& eg_entry
->shortcut
){
1081 if(eg_entry
->shortcut
->qos
.txtp
.traffic_class
&
1082 msg
->qos
.txtp
.traffic_class
&
1083 (qos
? qos
->qos
.txtp
.traffic_class
: ATM_UBR
| ATM_CBR
)){
1084 if(eg_entry
->shortcut
->qos
.txtp
.traffic_class
== ATM_UBR
)
1085 entry
->shortcut
= eg_entry
->shortcut
;
1086 else if(eg_entry
->shortcut
->qos
.txtp
.max_pcr
> 0)
1087 entry
->shortcut
= eg_entry
->shortcut
;
1089 if(entry
->shortcut
){
1090 dprintk("mpoa: (%s) using egress SVC to reach %d.%d.%d.%d\n",client
->dev
->name
, ip
[0], ip
[1], ip
[2], ip
[3]);
1094 /* No luck in the egress cache we must open an ingress SVC */
1095 msg
->type
= OPEN_INGRESS_SVC
;
1096 if (qos
&& (qos
->qos
.txtp
.traffic_class
== msg
->qos
.txtp
.traffic_class
))
1098 msg
->qos
= qos
->qos
;
1099 printk("mpoa: (%s) trying to get a CBR shortcut\n",client
->dev
->name
);
1101 else memset(&msg
->qos
,0,sizeof(struct atm_qos
));
1102 msg_to_mpoad(msg
, client
);
1106 static void MPOA_res_reply_rcvd(struct k_message
*msg
, struct mpoa_client
*client
)
1110 uint32_t dst_ip
= msg
->content
.in_info
.in_dst_ip
;
1111 in_cache_entry
*entry
= client
->in_ops
->search(dst_ip
, client
);
1112 ip
= (unsigned char *)&dst_ip
;
1113 dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %d.%d.%d.%d\n", client
->dev
->name
, ip
[0], ip
[1], ip
[2], ip
[3]);
1114 ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", client
->dev
->name
, entry
);
1116 printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", client
->dev
->name
);
1119 ddprintk(" entry_state = %d ", entry
->entry_state
);
1121 if (entry
->entry_state
== INGRESS_RESOLVED
) {
1122 printk("\nmpoa: (%s) MPOA_res_reply_rcvd for RESOLVED entry!\n", client
->dev
->name
);
1126 entry
->ctrl_info
= msg
->content
.in_info
;
1127 do_gettimeofday(&(entry
->tv
));
1128 do_gettimeofday(&(entry
->reply_wait
)); /* Used in refreshing func from now on */
1129 entry
->refresh_time
= 0;
1130 ddprintk("entry->shortcut = %p\n", entry
->shortcut
);
1132 if(entry
->entry_state
== INGRESS_RESOLVING
&& entry
->shortcut
!= NULL
){
1133 entry
->entry_state
= INGRESS_RESOLVED
;
1134 return; /* Shortcut already open... */
1137 if (entry
->shortcut
!= NULL
) {
1138 printk("mpoa: (%s) MPOA_res_reply_rcvd: entry->shortcut != NULL, impossible!\n",
1143 check_qos_and_open_shortcut(msg
, client
, entry
);
1144 entry
->entry_state
= INGRESS_RESOLVED
;
1150 static void ingress_purge_rcvd(struct k_message
*msg
, struct mpoa_client
*mpc
)
1152 uint32_t dst_ip
= msg
->content
.in_info
.in_dst_ip
;
1153 uint32_t mask
= msg
->ip_mask
;
1154 unsigned char *ip
= (unsigned char *)&dst_ip
;
1156 in_cache_entry
*entry
= mpc
->in_ops
->search_with_mask(dst_ip
, mpc
, mask
);
1157 if( entry
== NULL
){
1158 printk("mpoa: (%s) ingress_purge_rcvd: recieved a purge for an entry that doesn't exist, ", mpc
->dev
->name
);
1159 printk("ip = %u.%u.%u.%u\n", ip
[0], ip
[1], ip
[2], ip
[3]);
1162 while(entry
!= NULL
){
1163 dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" ,
1164 mpc
->dev
->name
, ip
[0], ip
[1], ip
[2], ip
[3]);
1165 mpc
->in_ops
->cache_remove(entry
, mpc
);
1166 entry
= mpc
->in_ops
->search_with_mask(dst_ip
, mpc
, mask
);
1171 static void egress_purge_rcvd(struct k_message
*msg
, struct mpoa_client
*mpc
)
1173 unsigned long flags
;
1174 uint32_t cache_id
= msg
->content
.eg_info
.cache_id
;
1175 eg_cache_entry
*entry
= mpc
->eg_ops
->search_by_cache_id(cache_id
, mpc
);
1177 if( entry
== NULL
){
1178 printk("mpoa: (%s) egress_purge_rcvd: received a purge reply for an entry that doesn't exist\n", mpc
->dev
->name
);
1182 write_lock_irqsave(&mpc
->egress_lock
, flags
);
1183 mpc
->eg_ops
->cache_remove(entry
, mpc
);
1184 write_unlock_irqrestore(&mpc
->egress_lock
, flags
);
1189 static void purge_egress_shortcut(struct atm_vcc
*vcc
, eg_cache_entry
*entry
)
1191 struct k_message
*purge_msg
;
1192 struct sk_buff
*skb
;
1194 dprintk("mpoa: purge_egress_shortcut: entering\n");
1196 printk("mpoa: purge_egress_shortcut: vcc == NULL\n");
1200 skb
= alloc_skb(sizeof(struct k_message
), GFP_ATOMIC
);
1202 printk("mpoa: purge_egress_shortcut: out of memory\n");
1206 skb_put(skb
, sizeof(struct k_message
));
1207 memset(skb
->data
, 0, sizeof(struct k_message
));
1208 purge_msg
= (struct k_message
*)skb
->data
;
1209 purge_msg
->type
= DATA_PLANE_PURGE
;
1211 purge_msg
->content
.eg_info
= entry
->ctrl_info
;
1213 atm_force_charge(vcc
, skb
->truesize
);
1214 skb_queue_tail(&vcc
->recvq
, skb
);
1215 wake_up(&vcc
->sleep
);
1216 dprintk("mpoa: purge_egress_shortcut: exiting:\n");
1222 * Our MPS died. Tell our daemon to send NHRP data plane purge to each
1223 * of the egress shortcuts we have.
1225 static void mps_death( struct k_message
* msg
, struct mpoa_client
* mpc
)
1228 unsigned long flags
;
1229 eg_cache_entry
*entry
;
1231 dprintk("mpoa: (%s) mps_death:\n", mpc
->dev
->name
);
1233 if(memcmp(msg
->MPS_ctrl
, mpc
->mps_ctrl_addr
, ATM_ESA_LEN
)){
1234 printk("mpoa: (%s) mps_death: wrong MPS\n", mpc
->dev
->name
);
1238 entry
= mpc
->eg_cache
;
1239 while (entry
!= NULL
) {
1240 purge_egress_shortcut(entry
->shortcut
, entry
);
1241 entry
= entry
->next
;
1244 write_lock_irqsave(&mpc
->ingress_lock
, flags
);
1245 while(mpc
->in_ops
->cache_remove(mpc
->in_cache
, mpc
));
1246 write_unlock_irqrestore(&mpc
->ingress_lock
, flags
);
1248 write_lock_irqsave(&mpc
->egress_lock
, flags
);
1249 while(mpc
->eg_ops
->cache_remove(mpc
->eg_cache
, mpc
));
1250 write_unlock_irqrestore(&mpc
->egress_lock
, flags
);
1255 static void MPOA_cache_impos_rcvd( struct k_message
* msg
, struct mpoa_client
* mpc
){
1257 uint16_t holding_time
;
1258 unsigned long flags
;
1259 eg_cache_entry
*entry
= mpc
->eg_ops
->search_by_cache_id(msg
->content
.eg_info
.cache_id
, mpc
);
1261 holding_time
= msg
->content
.eg_info
.holding_time
;
1262 dprintk("mpoa: (%s) MPOA_cache_impos_rcvd: entry = %p, holding_time = %u\n",
1263 mpc
->dev
->name
, entry
, holding_time
);
1264 if(entry
== NULL
&& holding_time
) {
1265 mpc
->eg_ops
->new_entry(msg
, mpc
);
1269 mpc
->eg_ops
->update(entry
, holding_time
);
1273 write_lock_irqsave(&mpc
->egress_lock
, flags
);
1274 mpc
->eg_ops
->cache_remove(entry
, mpc
);
1275 write_unlock_irqrestore(&mpc
->egress_lock
, flags
);
1281 static void set_mpc_ctrl_addr_rcvd(struct k_message
*mesg
, struct mpoa_client
*mpc
)
1283 struct lec_priv
*priv
;
1286 uint8_t tlv
[4 + 1 + 1 + 1 + ATM_ESA_LEN
];
1288 tlv
[0] = 00; tlv
[1] = 0xa0; tlv
[2] = 0x3e; tlv
[3] = 0x2a; /* type */
1289 tlv
[4] = 1 + 1 + ATM_ESA_LEN
; /* length */
1290 tlv
[5] = 0x02; /* MPOA client */
1291 tlv
[6] = 0x00; /* number of MPS MAC addresses */
1293 memcpy(&tlv
[7], mesg
->MPS_ctrl
, ATM_ESA_LEN
); /* MPC ctrl ATM addr */
1294 memcpy(mpc
->our_ctrl_addr
, mesg
->MPS_ctrl
, ATM_ESA_LEN
);
1296 dprintk("mpoa: (%s) setting MPC ctrl ATM address to ",
1297 (mpc
->dev
) ? mpc
->dev
->name
: "<unknown>");
1298 for (i
= 7; i
< sizeof(tlv
); i
++)
1299 dprintk("%02x ", tlv
[i
]);
1303 priv
= (struct lec_priv
*)mpc
->dev
->priv
;
1304 retval
= priv
->lane2_ops
->associate_req(mpc
->dev
, mpc
->dev
->dev_addr
, tlv
, sizeof(tlv
));
1306 printk("mpoa: (%s) MPOA device type TLV association failed\n", mpc
->dev
->name
);
1307 retval
= priv
->lane2_ops
->resolve(mpc
->dev
, NULL
, 1, NULL
, NULL
);
1309 printk("mpoa: (%s) targetless LE_ARP request failed\n", mpc
->dev
->name
);
1315 static void set_mps_mac_addr_rcvd(struct k_message
*msg
, struct mpoa_client
*client
){
1317 if(client
->number_of_mps_macs
)
1318 kfree(client
->mps_macs
);
1319 client
->number_of_mps_macs
= 0;
1320 client
->mps_macs
= kmalloc(ETH_ALEN
,GFP_KERNEL
);
1321 if (client
->mps_macs
== NULL
) {
1322 printk("mpoa: set_mps_mac_addr_rcvd: out of memory\n");
1325 client
->number_of_mps_macs
= 1;
1326 memcpy(client
->mps_macs
, msg
->MPS_ctrl
, ETH_ALEN
);
1332 * purge egress cache and tell daemon to 'action' (DIE, RELOAD)
1334 static void clean_up(struct k_message
*msg
, struct mpoa_client
*mpc
, int action
){
1336 unsigned long flags
;
1337 eg_cache_entry
*entry
;
1338 msg
->type
= SND_EGRESS_PURGE
;
1341 read_lock_irqsave(&mpc
->egress_lock
, flags
);
1342 entry
= mpc
->eg_cache
;
1343 while(entry
!= NULL
){
1344 msg
->content
.eg_info
= entry
->ctrl_info
;
1345 dprintk("mpoa: cache_id %u\n", entry
->ctrl_info
.cache_id
);
1346 msg_to_mpoad(msg
, mpc
);
1347 entry
= entry
->next
;
1349 read_unlock_irqrestore(&mpc
->egress_lock
, flags
);
1352 msg_to_mpoad(msg
, mpc
);
1356 static void mpc_timer_refresh()
1358 mpc_timer
.expires
= jiffies
+ (MPC_P2
* HZ
);
1359 mpc_timer
.data
= mpc_timer
.expires
;
1360 mpc_timer
.function
= mpc_cache_check
;
1361 add_timer(&mpc_timer
);
1366 static void mpc_cache_check( unsigned long checking_time
)
1368 struct mpoa_client
*mpc
= mpcs
;
1369 static unsigned long previous_resolving_check_time
= 0;
1370 static unsigned long previous_refresh_time
= 0;
1372 while( mpc
!= NULL
){
1373 mpc
->in_ops
->clear_count(mpc
);
1374 mpc
->eg_ops
->clear_expired(mpc
);
1375 if(checking_time
- previous_resolving_check_time
> mpc
->parameters
.mpc_p4
* HZ
){
1376 mpc
->in_ops
->check_resolving(mpc
);
1377 previous_resolving_check_time
= checking_time
;
1379 if(checking_time
- previous_refresh_time
> mpc
->parameters
.mpc_p5
* HZ
){
1380 mpc
->in_ops
->refresh(mpc
);
1381 previous_refresh_time
= checking_time
;
1385 mpc_timer_refresh();
1390 void atm_mpoa_init_ops(struct atm_mpoa_ops
*ops
)
1392 ops
->mpoad_attach
= atm_mpoa_mpoad_attach
;
1393 ops
->vcc_attach
= atm_mpoa_vcc_attach
;
1395 #ifdef CONFIG_PROC_FS
1396 if(mpc_proc_init() != 0)
1397 printk(KERN_INFO
"mpoa: failed to initialize /proc/mpoa\n");
1399 printk(KERN_INFO
"mpoa: /proc/mpoa initialized\n");
1402 printk("mpc.c: " __DATE__
" " __TIME__
" initialized\n");
1408 int init_module(void)
1410 extern struct atm_mpoa_ops atm_mpoa_ops
;
1412 atm_mpoa_init_ops(&atm_mpoa_ops
);
1417 void cleanup_module(void)
1419 extern struct atm_mpoa_ops atm_mpoa_ops
;
1420 struct mpoa_client
*mpc
, *tmp
;
1421 struct atm_mpoa_qos
*qos
, *nextqos
;
1422 struct lec_priv
*priv
;
1425 printk("mpc.c: module in use\n");
1428 #ifdef CONFIG_PROC_FS
1432 del_timer(&mpc_timer
);
1433 unregister_netdevice_notifier(&mpoa_notifier
);
1434 atm_mpoa_ops
.mpoad_attach
= NULL
;
1435 atm_mpoa_ops
.vcc_attach
= NULL
;
1439 while (mpc
!= NULL
) {
1441 if (mpc
->dev
!= NULL
) {
1443 priv
= (struct lec_priv
*)mpc
->dev
->priv
;
1444 if (priv
->lane2_ops
!= NULL
)
1445 priv
->lane2_ops
->associate_indicator
= NULL
;
1447 ddprintk("mpoa: cleanup_module: about to clear caches\n");
1448 while(mpc
->in_ops
->cache_remove(mpc
->in_cache
, mpc
));
1449 while(mpc
->eg_ops
->cache_remove(mpc
->eg_cache
, mpc
));
1450 ddprintk("mpoa: cleanup_module: caches cleared\n");
1451 kfree(mpc
->mps_macs
);
1452 memset(mpc
, 0, sizeof(struct mpoa_client
));
1453 ddprintk("mpoa: cleanup_module: about to kfree %p\n", mpc
);
1455 ddprintk("mpoa: cleanup_module: next mpc is at %p\n", tmp
);
1461 while (qos
!= NULL
) {
1462 nextqos
= qos
->next
;
1463 dprintk("mpoa: cleanup_module: freeing qos entry %p\n", qos
);