Hi Greg,

When the bonding driver attempts to read the link status via xxx_get_settings() the enslaved usb-eth driver crash the kernel. Which shouldn't be much of surprise - since pegasus|rtl8150_get_settins() is been called from a timer. The original work was done by Mike Nix - thanks.

Fixed that using in_atomic() check. I am not sure this is the best/proper thing to do, although it seems to work.

Haven't checked the other usb-ethernet drivers, but i suspect they are as vulnerable as pegasus and rtl8150 are. It's probably a good idea to warn their respective maintainers.


Petko



On Sat, 15 Jan 2005, Mike Nix wrote:



David Brownell wrote:

Patch attached....
Creates a single-threaded work queue for the pegasus driver. Each adapter gets a delayed task in the work queue, which executes set_carrier() every 2 seconds.



Does creating a work queue create a dedicated task? This is the sort of thing I suspect doesn't need a dedicated task.

You can use schedule_delayed_work() instead of queue_*();
that's what I normally use for low-load background tasks.

- Dave

It does - the reason I didn't use schedule_delayed_work() is that it uses a common global work list.
It is, I think, possible that the following might happen:


- you have as many Pegasus devices as CPUs
- read_mii_register blocks for some reason on each device (perhaps due to a USB problem or similar)
- the global queue is not single threaded


I think this would block the whole global queue, preventing work that could otherwise be done.
The way to resolve that would be to have a single work entry for the whole driver, and maintain a list of pegasus devices to check - really the difference is the kernel maintains the list for us the way I've done it, and each device is timed independantly (ie devices may not be always checked in the same order)
Also, if we think of other things that can happen async at a later date, we're all set...


I'll have a look at the code for the global queue, in particular if it only allows one work entry per CPU to run in parrallel. If it allows unlimited entries in parrallel, the global queue would be an option.

Mike

--
WA Network Maintenance            I can tell a computer
http://www.wanm.com.au            to do anything!
PO Box 492,                       I just wish they'd
Bridgetown 6255.                  listen to me!
Phone: 04-1798-1973   Fax: 04-0929-1138

You can import this changeset into BK by piping this whole message to:
'| bk receive [path to repository]' or apply the patch as usual.

===================================================================


[EMAIL PROTECTED], 2005-02-03 18:07:07+02:00, [EMAIL PROTECTED]
  changes mainly include adding work queue to both drivers
  and a bunch of other small fixes.
  
  Signed-off-by: Petko Manolov <[EMAIL PROTECTED]>


 pegasus.c |   61 +++++++++++++++++++++--------
 rtl8150.c |  127 ++++++++++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 148 insertions(+), 40 deletions(-)


diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
--- a/drivers/usb/net/pegasus.c 2005-02-03 18:08:32 +02:00
+++ b/drivers/usb/net/pegasus.c 2005-02-03 18:08:32 +02:00
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 1999-2003 Petko Manolov ([EMAIL PROTECTED])
+ *  Copyright (c) 1999-2005 Petko Manolov ([EMAIL PROTECTED])
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -47,7 +47,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.5.12 (2005/01/13)"
+#define DRIVER_VERSION "v0.6.12 (2005/01/13)"
 #define DRIVER_AUTHOR "Petko Manolov <[EMAIL PROTECTED]>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
@@ -301,20 +301,20 @@
        if (i < REG_TIMEOUT) {
                get_registers(pegasus, PhyData, 2, &regdi);
                *regd = le16_to_cpu(regdi);
-               return 0;
+               return 1;
        }
        warn("%s: failed", __FUNCTION__);
 
-       return 1;
+       return 0;
 }
 
 static int mdio_read(struct net_device *dev, int phy_id, int loc)
 {
        pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev);
-       int res;
+       __le16 res;
 
-       read_mii_word(pegasus, phy_id, loc, (u16 *) & res);
-       return res & 0xffff;
+       read_mii_word(pegasus, phy_id, loc, &res);
+       return (int)res;
 }
 
 static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
@@ -636,7 +636,7 @@
 
        return;
 
-      tl_sched:
+tl_sched:
        tasklet_schedule(&pegasus->rx_tl);
 }
 
@@ -845,14 +845,14 @@
 static void set_carrier(struct net_device *net)
 {
        pegasus_t *pegasus = netdev_priv(net);
-       short tmp;
+       __le16 tmp;
 
-       read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
+       if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp))
+               return;
        if (tmp & BMSR_LSTATUS)
                netif_carrier_on(net);
        else
                netif_carrier_off(net);
-
 }
 
 static void free_all_urbs(pegasus_t * pegasus)
@@ -997,8 +997,7 @@
        return set_register(pegasus, WakeupControl, reg78);
 }
 
-static inline void
-pegasus_reset_wol(struct net_device *dev)
+static inline void pegasus_reset_wol(struct net_device *dev)
 {
        struct ethtool_wolinfo wol;
        
@@ -1009,10 +1008,17 @@
 static int
 pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-       pegasus_t *pegasus = netdev_priv(dev);
+       pegasus_t *pegasus;
+
+       if (in_atomic())
+               return 0;
+
+       pegasus = netdev_priv(dev);
        mii_ethtool_gset(&pegasus->mii, ecmd);
+
        return 0;
 }
+
 static int
 pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
@@ -1149,6 +1155,20 @@
                set_register(pegasus, Reg81, 2);
 }
 
+
+struct workqueue_struct *pegasus_workqueue = NULL;
+#define CARRIER_CHECK_DELAY (2 * HZ)
+
+void check_carrier(void *data)
+{
+       pegasus_t *pegasus = data;
+       set_carrier(pegasus->net);
+       if (!(pegasus->flags & PEGASUS_UNPLUG)) {
+               queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
+                       CARRIER_CHECK_DELAY);
+       }
+}
+
 static int pegasus_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -1175,6 +1195,8 @@
 
        tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus);
 
+       INIT_WORK(&pegasus->carrier_check, check_carrier, pegasus);
+
        pegasus->usb = dev;
        pegasus->net = net;
        SET_MODULE_OWNER(net);
@@ -1212,12 +1234,14 @@
                dev_warn(&intf->dev, "can't locate MII phy, using default\n");
                pegasus->phy = 1;
        }
+       pegasus->mii.phy_id = pegasus->phy;
        usb_set_intfdata(intf, pegasus);
        SET_NETDEV_DEV(net, &intf->dev);
        pegasus_reset_wol(net);
        res = register_netdev(net);
        if (res)
                goto out3;
+       queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, 
CARRIER_CHECK_DELAY);
        pr_info("%s: %s\n", net->name, usb_dev_id[dev_index].name);
        return 0;
 
@@ -1239,11 +1263,12 @@
 
        usb_set_intfdata(intf, NULL);
        if (!pegasus) {
-               warn("unregistering non-existant device");
+               warn("unregistering non-existent device");
                return;
        }
 
        pegasus->flags |= PEGASUS_UNPLUG;
+       cancel_delayed_work(&pegasus->carrier_check);
        unregister_netdev(pegasus->net);
        usb_put_dev(interface_to_usbdev(intf));
        free_all_urbs(pegasus);
@@ -1253,7 +1278,7 @@
        free_netdev(pegasus->net);
 }
 
-static int pegasus_suspend (struct usb_interface *intf, pm_message_t state)
+static int pegasus_suspend (struct usb_interface *intf, u32 state)
 {
        struct pegasus *pegasus = usb_get_intfdata(intf);
        
@@ -1281,11 +1306,15 @@
 static int __init pegasus_init(void)
 {
        pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION);
+       pegasus_workqueue = create_singlethread_workqueue("pegasus");
+       if (!pegasus_workqueue)
+               return -ENOMEM;
        return usb_register(&pegasus_driver);
 }
 
 static void __exit pegasus_exit(void)
 {
+       destroy_workqueue(pegasus_workqueue);
        usb_deregister(&pegasus_driver);
 }
 
diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
--- a/drivers/usb/net/rtl8150.c 2005-02-03 18:08:32 +02:00
+++ b/drivers/usb/net/rtl8150.c 2005-02-03 18:08:32 +02:00
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2002 Petko Manolov ([EMAIL PROTECTED])
+ *  Copyright (c) 2002-2005 Petko Manolov ([EMAIL PROTECTED])
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -20,7 +20,7 @@
 #include <asm/uaccess.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v0.6.2 (2004/08/27)"
+#define DRIVER_VERSION "v0.6.3 (2005/01/20)"
 #define DRIVER_AUTHOR "Petko Manolov <[EMAIL PROTECTED]>"
 #define DRIVER_DESC "rtl8150 based usb-ethernet driver"
 
@@ -124,6 +124,12 @@
 #define        RTL8150_UNPLUG          2
 #define        RX_URB_FAIL             3
 
+/* Basic Mode Control Register definitions */
+#define RTL8150_BMCR_DUPLEX            (1<<8)
+#define RTL8150_BMCR_ANE_RESTART       (1<<9)
+#define RTL8150_BMCR_ANE               (1<<12)
+#define RTL8150_BMCR_SPD_SET           (1<<13)
+
 /* Define these values to match your device */
 #define VENDOR_ID_REALTEK              0x0bda
 #define        VENDOR_ID_MELCO                 0x0411
@@ -160,11 +166,14 @@
        spinlock_t rx_pool_lock;
        struct usb_ctrlrequest dr;
        int intr_interval;
-       __le16 rx_creg;
+       struct work_struct carrier_check;
+       __le16 rx_creg, stored_bmcr, stored_lpa;
        u8 *intr_buff;
        u8 phy;
 };
 
+struct workqueue_struct *rtl8150_workqueue = NULL;
+
 typedef struct rtl8150 rtl8150_t;
 
 static unsigned long multicast_filter_limit = 32;
@@ -172,6 +181,7 @@
 static void fill_skb_pool(rtl8150_t *);
 static void free_skb_pool(rtl8150_t *);
 static inline struct sk_buff *pull_skb(rtl8150_t *);
+static void set_carrier(struct net_device *);
 static void rtl8150_disconnect(struct usb_interface *intf);
 static int rtl8150_probe(struct usb_interface *intf,
                           const struct usb_device_id *id);
@@ -256,7 +266,6 @@
        data[1] = data[2] = 0;
        tmp = indx | PHY_READ | PHY_GO;
        i = 0;
-
        set_registers(dev, PHYADD, sizeof(data), data);
        set_registers(dev, PHYCNT, 1, &tmp);
        do {
@@ -485,6 +494,11 @@
 
        dev = (rtl8150_t *)data;
 
+       if (!netif_device_present(dev->netdev))
+               return;
+       if (test_bit(RTL8150_UNPLUG, &dev->flags))
+               return;;
+
        spin_lock_irq(&dev->rx_pool_lock);
        fill_skb_pool(dev);
        spin_unlock_irq(&dev->rx_pool_lock);
@@ -582,6 +596,16 @@
 }
 
 
+static void check_carrier(void *data)
+{
+       rtl8150_t *dev = (rtl8150_t *)data;
+
+       set_carrier(dev->netdev);
+       if (test_bit(RTL8150_UNPLUG, &dev->flags))
+               queue_delayed_work(rtl8150_workqueue, &dev->carrier_check, HZ);
+}
+
+
 /*
 **
 **     network related part of the code
@@ -711,7 +735,7 @@
        short tmp;
 
        get_registers(dev, CSCR, 2, &tmp);
-       if (tmp & CSCR_LINK_STATUS)
+       if (!(tmp & CSCR_LINK_STATUS))
                netif_carrier_on(netdev);
        else
                netif_carrier_off(netdev);
@@ -728,7 +752,7 @@
                return -ENOMEM;
 
        set_registers(dev, IDR, 6, netdev->dev_addr);
-       
+
        usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
                      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
        if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
@@ -741,6 +765,7 @@
        netif_start_queue(netdev);
        enable_net_traffic(dev);
        set_carrier(netdev);
+       netif_device_attach(netdev);
 
        return res;
 }
@@ -750,15 +775,18 @@
        rtl8150_t *dev = netdev_priv(netdev);
        int res = 0;
 
+       netif_device_detach(netdev);
        netif_stop_queue(netdev);
        if (!test_bit(RTL8150_UNPLUG, &dev->flags))
                disable_net_traffic(dev);
+       tasklet_kill(&dev->tl);
        unlink_all_urbs(dev);
 
        return res;
 }
 
-static void rtl8150_get_drvinfo(struct net_device *netdev, struct 
ethtool_drvinfo *info)
+static void
+rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
 {
        rtl8150_t *dev = netdev_priv(netdev);
 
@@ -767,10 +795,14 @@
        usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info);
 }
 
-static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd 
*ecmd)
+static int
+rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
        rtl8150_t *dev = netdev_priv(netdev);
-       short lpa, bmcr;
+       __le16 lpa, bmcr;
+
+       if (in_atomic())
+               return 0;
 
        ecmd->supported = (SUPPORTED_10baseT_Half |
                          SUPPORTED_10baseT_Full |
@@ -781,8 +813,10 @@
        ecmd->port = PORT_TP;
        ecmd->transceiver = XCVR_INTERNAL;
        ecmd->phy_address = dev->phy;
+
        get_registers(dev, BMCR, 2, &bmcr);
        get_registers(dev, ANLP, 2, &lpa);
+
        if (bmcr & BMCR_ANENABLE) {
                ecmd->autoneg = AUTONEG_ENABLE;
                ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
@@ -803,10 +837,46 @@
        return 0;
 }
 
+static int
+rtl8150_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+       rtl8150_t *dev = netdev_priv(netdev);
+       __le16 bmcr;
+
+       get_registers(dev, BMCR, 2, &bmcr);
+       if (ecmd->autoneg)
+               bmcr |= RTL8150_BMCR_ANE;
+       else {
+               bmcr &= ~RTL8150_BMCR_ANE;
+               if (ecmd->speed == 10)
+                       bmcr &= ~RTL8150_BMCR_SPD_SET;
+               if (ecmd->speed == 100)
+                       bmcr |= RTL8150_BMCR_SPD_SET;
+               if (ecmd->duplex) 
+                       bmcr |= RTL8150_BMCR_DUPLEX;
+               else
+                       bmcr &= ~RTL8150_BMCR_DUPLEX;
+       }
+       set_registers(dev, BMCR, 2, &bmcr);
+       return 0;
+}
+
+static u32 rtl8150_link_ok(struct net_device *dev)
+{
+       __le16 tmp;
+
+       rtl8150_t *udev = netdev_priv(dev);
+       get_registers(udev, CSCR, 2, &tmp);
+       if (!(tmp & CSCR_LINK_STATUS))
+               return 1;
+       return 0;
+}
+
 static struct ethtool_ops ops = {
        .get_drvinfo = rtl8150_get_drvinfo,
        .get_settings = rtl8150_get_settings,
-       .get_link = ethtool_op_get_link
+       .set_settings = rtl8150_set_settings,
+       .get_link = rtl8150_link_ok
 };
 
 static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -873,6 +943,7 @@
        netdev->mtu = RTL8150_MTU;
        SET_ETHTOOL_OPS(netdev, &ops);
        dev->intr_interval = 100;       /* 100ms */
+       INIT_WORK(&dev->carrier_check, check_carrier, (void *)dev);
 
        if (!alloc_all_urbs(dev)) {
                err("out of memory");
@@ -883,15 +954,15 @@
                goto out1;
        }
        fill_skb_pool(dev);
-       set_ethernet_addr(dev);
-       info("%s: rtl8150 is detected", netdev->name);
-       
+       set_ethernet_addr(dev); 
        usb_set_intfdata(intf, dev);
        SET_NETDEV_DEV(netdev, &intf->dev);
        if (register_netdev(netdev) != 0) {
                err("couldn't register the device");
                goto out2;
        }
+       queue_delayed_work(rtl8150_workqueue, &dev->carrier_check, HZ);
+       info("%s: rtl8150 is detected", netdev->name);
        return 0;
 
 out2:
@@ -910,27 +981,35 @@
        rtl8150_t *dev = usb_get_intfdata(intf);
 
        usb_set_intfdata(intf, NULL);
-       if (dev) {
-               set_bit(RTL8150_UNPLUG, &dev->flags);
-               unregister_netdev(dev->netdev);
-               unlink_all_urbs(dev);
-               free_all_urbs(dev);
-               free_skb_pool(dev);
-               if (dev->rx_skb)
-                       dev_kfree_skb(dev->rx_skb);
-               kfree(dev->intr_buff);
-               free_netdev(dev->netdev);
+       if (!dev) {
+               warn("trying to unregister non-existent device\n");
+               return;
        }
+
+       set_bit(RTL8150_UNPLUG, &dev->flags);
+       cancel_delayed_work(&dev->carrier_check);
+       unregister_netdev(dev->netdev);
+       usb_put_dev(interface_to_usbdev(intf));
+       free_all_urbs(dev);
+       free_skb_pool(dev);
+       if (dev->rx_skb)
+               dev_kfree_skb(dev->rx_skb);
+       kfree(dev->intr_buff);
+       free_netdev(dev->netdev);
 }
 
 static int __init usb_rtl8150_init(void)
 {
-       info(DRIVER_DESC " " DRIVER_VERSION);
+       pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION);
+       rtl8150_workqueue = create_singlethread_workqueue("rtl8150");
+       if (!rtl8150_workqueue)
+               return -ENOMEM;
        return usb_register(&rtl8150_driver);
 }
 
 static void __exit usb_rtl8150_exit(void)
 {
+       destroy_workqueue(rtl8150_workqueue);
        usb_deregister(&rtl8150_driver);
 }
 

===================================================================


This BitKeeper patch contains the following changesets:
1.4151
## Wrapped with gzip_uu ##


M'XL( (!, D(  [59>V_:2A;_&W^*V52W"[T\_+8)3=4TH!8U22-(=O>N*EG&
M'L#"V*QGG#:Z=#_[GC-C&PC0W#;=YC'&,[EMAIL PROTECTED]
MC)_6)C0):=9.\B"[EMAIL PROTECTED]&S,T^7M",I.BP+.K.,SA;SEMZV%3AT
[EMAIL PROTECTED]"'%3VMC0;O[R[/1XIR=D8NYGXRHV/*R=F9,EF\#7,:
MMQ=9ZL_;:39;5]MK754U3=,MU;!LS5KKKF&8:\U6)R$\AKK3G4[LKB(U>GM(
M]UU>EJJKAF89ANZN#;5KZTJ?:&U3LS2B6AU5[Z@&T=Q3U8'OWU7]5%7)=WB3
MWW724I5WY/D67"@!"00-(TL_2N('$B5!G(>4^&$8)3/R)<T6Y#\YS2GA*9FD
M?$["+$)G ZF?A,0GDSP!;Z=3 ILT(VSIQS&91E\I:\,9^!Y'LX2&K70Z;4T>
M3LD-F):2*S])X_2>O"XLW3'QC?*1&+IA&LK-)FA*ZP?_*8KJJ\H;@NGR5CH)
M0U/HW\G9I)/[EMAIL PROTECTED]"_-U"UWK5F.H:^MJ65.?'L2!/;$F4R^%Y4=
[EMAIL PROTECTED]:PM,*P+:NV';YO%BLY\EC-)+D-IJEW-7FN:X6AKW3',P T"
MLTM5=QJZ/Z3:#N]MU533M;JB5(Z2'"Z=9VC^W3+Z"YIC69EKU=$,0Y25!M6S
M4U7VJ>7^E:HR+=+2[%]65SFCX:/RR:@[EMAIL PROTECTED])@C#N\YR1V.=0-13,?" Z
M831(DY#U! ,LP,)B\B6"TIO 'KZ4;B$1(TGZA:Q2QJ))3)%HY3-&[EMAIL PROTECTED];
[EMAIL PROTECTED]( [EMAIL PROTECTED],3U1N7R>:
M,L1?Y!4A%^GJ(8MF<T[J08-HW6ZWA?%_I&R]4!8\G[$V2_,LH%,('[EMAIL PROTECTED]
M;ZG(4_Q^$=)IE%#2'PW_,1AY\#,>?KHF)_=JVVYK.JDC^XZJ=32C<:+T#=5$
M4KG4:AGE>980K8<[KMS!I=Q0<4.3)&*I>5Y,-1L2@(DMF^BXY<!2PZ3PEE'D
M0:Z$]<)G3;*:/WA1V"1Q&C3)2R!L]"K^]2CA#<[EMAIL PROTECTED]&ITG=-
MH9=<2O%\N0(25_H!%Q ?34G]F KRH?4&=&EBVGCOKL8CT ;X-!J5'P1+"UCV
[EMAIL PROTECTED]<!3)0877V?1F')T@/E*0=Q<9WQ+ [EMAIL PROTECTED](;V/ DI>P=I 
M9IK( ;':2JTDY>15\=A3/DO]H\3S>;J,@OJ66AB%SQ49.4,1P-E;09;6441/
M\(8> <?PR2J><"QK)CP6JF$-BQ+VBA>E?*_: >[7=Y>7O2JO+LY'HR$DUL6'
MP<5'KS^X//\#<@I2^<._&\!9^ (B%2R\P,^RB&9U\>I5Z'._H?QYR%J0@;N0
M!>BZDJR*$:9X3[KC;YNWT]B?,?*2W S>GX_OQM[=]<WEW?M&@X"(FC0JI+'_
M0$-A3'W/,HAVQ:R0Z0G%F\"@=L!,5.*;\DUZTA$9/KP>WGK__#3Z6#_&:]<7
M5>8U>H*-+FNHHH5,;<OR )]L)RE&5-<QNY]IVZ'[EMAIL PROTECTED])]33=E3LJU5OOB9TG]
M)$\ 840,[EMAIL PROTECTED](I)--VTD"OPDH/&N;D<4D3(M6\H4:U54
MO"HF^%G!1"-E+4'_]6"?9E,?RPD>ITV2&[J8.+2!K%R#&)LDV\[C )H!AU0'
M2V+*YZ(U5/OUDX+DI,JU/1Y;%=@:7'^Z&EP)VUW1B$(*.J8/6QSWZ7L' [EMAIL PROTECTED]
MIQ" _#)$]SU.>R#.U("A9IN.V5WKNN$Z F_8YL_!#0W.MW3S_XXW$&NP$FQ(
MF"%!!LY_/@<,4: )R$L!)R94\O(9@'L6^_=4X(==[('$40(/G(8[<":DG 8\
M2A.87#-(U!8943_F=/%WV$N#? E5X>,^,D )[EMAIL PROTECTED]"VS'^0X(CZC#_KZB 1
M]A/HI KM+T8GF'[EMAIL PROTECTED] TGD(GQ@:<Z"J [EMAIL PROTECTED]&^9CYQ5YYS-P^!5 
.U I
[EMAIL PROTECTED]>R+Q'!,4*_,_*J4TD8W5ZB$V"P7XR\_MW-Y>!?M5I=>_W:;1P^<WX]
M\$:#\>WYZ%:<ZQX_)QEI^I$3XYN^-Q[<%J<,'(M]S19.P 7FQM;\+4?O3G?L
M;7#55P_ZUJP)29AFT%,GRR"K/L0K'SN0C;/[EMAIL PROTECTED]' 2,<)Y)B;SBL&]?8(
M/[EMAIL PROTECTED]&_KED!FINL0J^B5<"2:%H< AP &2CA"$3&]$9)[EMAIL 
PROTECTED]>I.(UTO7
MR0$.DTN0B?&^3274M5Q05]W1][M8H[2="[EMAIL PROTECTED]>WWC0DZ/B\"SNVE?Y150^,
MYCWOEU2/[EMAIL PROTECTED] %I [EMAIL PROTECTED]<BEP#P!3 
#L78TBOR^'U1P_R]/9N#%+[CJ&)
MTV(!'SDF9EIM)R(^YWXPKU=F#1U+WSL$_>WQ(02.->ZS!0Q,;Q'%<5TJSV/,
M \>6DF'1MV.BE$;/,'&R^RB9IH=R24K";!9;,)-YFL8E!8[W:8H&[EMAIL PROTECTED])O
[EMAIL PROTECTED]<_8"88 F90N&W$&%($08QJ]*#ZFH2K+>GT?C0<0NT[;@%V':A
M31K6(7W9L_4]E-G;=X!-^A:F5%:@KTI$Q^I"#+:L)M$A+_%4F?,HJ/7&SWF:
MT!D:BYMD?;;7"^$\C1D5L%N<>7E&[EMAIL PROTECTED]'[EMAIL 
PROTECTED]):2IR/D)6=-&CI%NT
MC]4Z2!KFJYA^;9"C5')((!$:=%RQZMPWV3F>].<F3[Z)NY?("$2M91 197CI
MXNB-\<_=>[EMAIL PROTECTED];[%QHAQU$:H=7W=Z3[67[3P*/[EMAIL PROTECTED],!,
M:V_G-2AT*-WA:M5&K02L.GML/[!R1,?9NE8=ZI6/KE1%TV](J_NN:\,-8.A*
M6([2*?[U%IWJAV$FG5.# UT3U7YNSZZ)[G;R&SLMS4'P)[$B#4^:[EMAIL PROTECTED]
MO '[EMAIL PROTECTED])"I*W+IX](!X%Y+BY?QVZ?'U.Q&VE&JS $WAK
MY4A[:F3UCMS8]FW%HQM5/&G2XU&)E[-5+E*W7EW2/)YZL%&\FS;PX#2C,)+B
MV,NS"2N35;QD"V !S:Y\B<X14@ &P1ZF(R;YHCR\LPGGQ89\"=(R;Y)/IQ7S
[EMAIL PROTECTED]<Q(NT/I7F;>)YV^ WD]*J-H?C"_("7B\6>!M#P/:?(1D1;D? %Q/
MW#T+DLW=<X_'P;MGUS .7SWWR7N;_T\2$67Y\LSQX0896A/E?T6A!LN[&@  
 

Reply via email to