All of lore.kernel.org
 help / color / mirror / Atom feed
From: "John W. Linville" <linville@tuxdriver.com>
To: Jeff Garzik <jeff@garzik.org>
Cc: netdev@vger.kernel.org, linux-wireless@vger.kernel.org
Subject: Re: Please pull 'fixes-jgarzik' branch of wireless-2.6 (this time for real!)
Date: Thu, 8 Nov 2007 09:01:32 -0500	[thread overview]
Message-ID: <20071108140132.GG11957@tuxdriver.com> (raw)
In-Reply-To: <20071108013429.GA11957@tuxdriver.com>

Clearly having a bad week...just ignore this thread and I'll post a
totally new request shortly.

Thanks,

John

On Wed, Nov 07, 2007 at 08:34:29PM -0500, John W. Linville wrote:
> On Wed, Nov 07, 2007 at 02:24:19PM -0500, Jeff Garzik wrote:
> > On Wed, Nov 07, 2007 at 02:13:29PM -0500, John W. Linville wrote:
> > > Jeff,
> > > 
> > > If you haven't already pulled this then please hold-off.  I'll post
> > > a new request soon.
> > 
> > Haven't pulled yet...
> 
> Jeff,
> 
> These fixes are additive on top of the previous request in this thread.
> That request is archived here:
> 
> 	http://marc.info/?l=linux-wireless&m=119438263704232&w=2
> 
> Also, note that the first three from Michael Buesch in the list below
> were already sent to you directed for 2.6.25, but I think they belong in
> 2.6.24 instead.  I cherry-picked them, so I'm fairly certain git will be
> smart enough to drop them from your 2.6.25 branch when you rebase.
> 
> Let me know if there are any problems!
> 
> Thanks,
> 
> John
> 
> ---
> 
> The entire series (i.e. both from yesterday and today) is available
> here:
> 
> 	http://www.kernel.org/pub//linux/kernel/people/linville/wireless-2.6/fixes-jgarzik/
> 
> ---
> 
> The following changes since commit 33a463d0c82cad08a64526c217f6d835a51dfc1c:
>   Michael Buesch (1):
>         b43: pcmcia-host initialization bugfixes
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git fixes-jgarzik
> 
> Michael Buesch (6):
>       b43: Fix rfkill callback deadlock
>       b43: debugfs SHM read buffer overrun fix
>       b43: Rewrite and fix rfkill init
>       b43: properly request pcmcia IRQ
>       b43legacy: Fix sparse warning
>       b43: Fix kconfig dependencies for rfkill and leds
> 
> Stefano Brivio (4):
>       b43legacy: fix possible buffer overrun in debugfs
>       b43legacy: add me as maintainer and fix URLs
>       b43: fix shared IRQ race condition
>       b43legacy: fix shared IRQ race condition
> 
>  MAINTAINERS                              |   10 ++-
>  drivers/net/wireless/b43/Kconfig         |   10 ++-
>  drivers/net/wireless/b43/debugfs.c       |    2 +-
>  drivers/net/wireless/b43/main.c          |   19 +++---
>  drivers/net/wireless/b43/pcmcia.c        |    8 ++
>  drivers/net/wireless/b43/rfkill.c        |  115 +++++++++++++----------------
>  drivers/net/wireless/b43/rfkill.h        |   14 +---
>  drivers/net/wireless/b43legacy/debugfs.c |    2 +-
>  drivers/net/wireless/b43legacy/main.c    |   21 +++---
>  9 files changed, 100 insertions(+), 101 deletions(-)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1c7c229..6a97027 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -787,23 +787,25 @@ B43 WIRELESS DRIVER
>  P:	Michael Buesch
>  M:	mb@bu3sch.de
>  P:	Stefano Brivio
> -M:	st3@riseup.net
> +M:	stefano.brivio@polimi.it
>  L:	linux-wireless@vger.kernel.org
> -W:	http://bcm43xx.berlios.de/
> +W:	http://linuxwireless.org/en/users/Drivers/b43
>  S:	Maintained
>  
>  B43LEGACY WIRELESS DRIVER
>  P:	Larry Finger
>  M:	Larry.Finger@lwfinger.net
> +P:	Stefano Brivio
> +M:	stefano.brivio@polimi.it
>  L:	linux-wireless@vger.kernel.org
> -W:	http://bcm43xx.berlios.de/
> +W:	http://linuxwireless.org/en/users/Drivers/b43
>  S:	Maintained
>  
>  BCM43XX WIRELESS DRIVER (SOFTMAC BASED VERSION)
>  P:	Larry Finger
>  M:	Larry.Finger@lwfinger.net
>  P:	Stefano Brivio
> -M:	st3@riseup.net
> +M:	stefano.brivio@polimi.it
>  L:	linux-wireless@vger.kernel.org
>  W:	http://bcm43xx.berlios.de/
>  S:	Maintained
> diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
> index e3c573e..fdbc351 100644
> --- a/drivers/net/wireless/b43/Kconfig
> +++ b/drivers/net/wireless/b43/Kconfig
> @@ -61,16 +61,18 @@ config B43_PCMCIA
>  
>  	  If unsure, say N.
>  
> -# LED support
> +# This config option automatically enables b43 LEDS support,
> +# if it's possible.
>  config B43_LEDS
>  	bool
> -	depends on B43 && MAC80211_LEDS
> +	depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43)
>  	default y
>  
> -# RFKILL support
> +# This config option automatically enables b43 RFKILL support,
> +# if it's possible.
>  config B43_RFKILL
>  	bool
> -	depends on B43 && RFKILL && RFKILL_INPUT && INPUT_POLLDEV
> +	depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43)
>  	default y
>  
>  config B43_DEBUG
> diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
> index 734e70e..ef0075d 100644
> --- a/drivers/net/wireless/b43/debugfs.c
> +++ b/drivers/net/wireless/b43/debugfs.c
> @@ -128,7 +128,7 @@ static ssize_t shm_read_file(struct b43_wldev *dev,
>  	__le16 *le16buf = (__le16 *)buf;
>  
>  	for (i = 0; i < 0x1000; i++) {
> -		if (bufsize <= 0)
> +		if (bufsize < sizeof(tmp))
>  			break;
>  		tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i);
>  		le16buf[i] = cpu_to_le16(tmp);
> diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
> index 5058e60..2b17c1d 100644
> --- a/drivers/net/wireless/b43/main.c
> +++ b/drivers/net/wireless/b43/main.c
> @@ -2985,6 +2985,16 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
>  
>  	if (b43_status(dev) < B43_STAT_STARTED)
>  		return;
> +
> +	/* Disable and sync interrupts. We must do this before than
> +	 * setting the status to INITIALIZED, as the interrupt handler
> +	 * won't care about IRQs then. */
> +	spin_lock_irqsave(&wl->irq_lock, flags);
> +	dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
> +	b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);	/* flush */
> +	spin_unlock_irqrestore(&wl->irq_lock, flags);
> +	b43_synchronize_irq(dev);
> +
>  	b43_set_status(dev, B43_STAT_INITIALIZED);
>  
>  	mutex_unlock(&wl->mutex);
> @@ -2995,13 +3005,6 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
>  
>  	ieee80211_stop_queues(wl->hw);	//FIXME this could cause a deadlock, as mac80211 seems buggy.
>  
> -	/* Disable and sync interrupts. */
> -	spin_lock_irqsave(&wl->irq_lock, flags);
> -	dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
> -	b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);	/* flush */
> -	spin_unlock_irqrestore(&wl->irq_lock, flags);
> -	b43_synchronize_irq(dev);
> -
>  	b43_mac_suspend(dev);
>  	free_irq(dev->dev->irq, dev);
>  	b43dbg(wl, "Wireless interface stopped\n");
> @@ -3661,7 +3664,6 @@ static int b43_setup_modes(struct b43_wldev *dev,
>  
>  static void b43_wireless_core_detach(struct b43_wldev *dev)
>  {
> -	b43_rfkill_free(dev);
>  	/* We release firmware that late to not be required to re-request
>  	 * is all the time when we reinit the core. */
>  	b43_release_firmware(dev);
> @@ -3747,7 +3749,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
>  	if (!wl->current_dev)
>  		wl->current_dev = dev;
>  	INIT_WORK(&dev->restart_work, b43_chip_reset);
> -	b43_rfkill_alloc(dev);
>  
>  	b43_radio_turn_off(dev, 1);
>  	b43_switch_analog(dev, 0);
> diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
> index 4b6648f..b79a6bd 100644
> --- a/drivers/net/wireless/b43/pcmcia.c
> +++ b/drivers/net/wireless/b43/pcmcia.c
> @@ -112,6 +112,14 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
>  	if (res != CS_SUCCESS)
>  		goto err_disable;
>  
> +	dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED;
> +	dev->irq.IRQInfo1 = IRQ_LEVEL_ID | IRQ_SHARE_ID;
> +	dev->irq.Handler = NULL; /* The handler is registered later. */
> +	dev->irq.Instance = NULL;
> +	res = pcmcia_request_irq(dev, &dev->irq);
> +	if (res != CS_SUCCESS)
> +		goto err_disable;
> +
>  	res = pcmcia_request_configuration(dev, &dev->conf);
>  	if (res != CS_SUCCESS)
>  		goto err_disable;
> diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
> index 800e0a6..9b1f905 100644
> --- a/drivers/net/wireless/b43/rfkill.c
> +++ b/drivers/net/wireless/b43/rfkill.c
> @@ -47,32 +47,35 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
>  	struct b43_wldev *dev = poll_dev->private;
>  	struct b43_wl *wl = dev->wl;
>  	bool enabled;
> +	bool report_change = 0;
>  
>  	mutex_lock(&wl->mutex);
>  	B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
>  	enabled = b43_is_hw_radio_enabled(dev);
>  	if (unlikely(enabled != dev->radio_hw_enable)) {
>  		dev->radio_hw_enable = enabled;
> +		report_change = 1;
>  		b43info(wl, "Radio hardware status changed to %s\n",
>  			enabled ? "ENABLED" : "DISABLED");
> -		mutex_unlock(&wl->mutex);
> +	}
> +	mutex_unlock(&wl->mutex);
> +
> +	if (unlikely(report_change))
>  		input_report_key(poll_dev->input, KEY_WLAN, enabled);
> -	} else
> -		mutex_unlock(&wl->mutex);
>  }
>  
> -/* Called when the RFKILL toggled in software.
> - * This is called without locking. */
> +/* Called when the RFKILL toggled in software. */
>  static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
>  {
>  	struct b43_wldev *dev = data;
>  	struct b43_wl *wl = dev->wl;
>  	int err = 0;
>  
> -	mutex_lock(&wl->mutex);
> -	if (b43_status(dev) < B43_STAT_INITIALIZED)
> -		goto out_unlock;
> +	if (!wl->rfkill.registered)
> +		return 0;
>  
> +	mutex_lock(&wl->mutex);
> +	B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
>  	switch (state) {
>  	case RFKILL_STATE_ON:
>  		if (!dev->radio_hw_enable) {
> @@ -89,7 +92,6 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
>  			b43_radio_turn_off(dev, 0);
>  		break;
>  	}
> -
>  out_unlock:
>  	mutex_unlock(&wl->mutex);
>  
> @@ -98,11 +100,11 @@ out_unlock:
>  
>  char * b43_rfkill_led_name(struct b43_wldev *dev)
>  {
> -	struct b43_wl *wl = dev->wl;
> +	struct b43_rfkill *rfk = &(dev->wl->rfkill);
>  
> -	if (!wl->rfkill.rfkill)
> +	if (!rfk->registered)
>  		return NULL;
> -	return rfkill_get_led_name(wl->rfkill.rfkill);
> +	return rfkill_get_led_name(rfk->rfkill);
>  }
>  
>  void b43_rfkill_init(struct b43_wldev *dev)
> @@ -111,53 +113,13 @@ void b43_rfkill_init(struct b43_wldev *dev)
>  	struct b43_rfkill *rfk = &(wl->rfkill);
>  	int err;
>  
> -	if (rfk->rfkill) {
> -		err = rfkill_register(rfk->rfkill);
> -		if (err) {
> -			b43warn(wl, "Failed to register RF-kill button\n");
> -			goto err_free_rfk;
> -		}
> -	}
> -	if (rfk->poll_dev) {
> -		err = input_register_polled_device(rfk->poll_dev);
> -		if (err) {
> -			b43warn(wl, "Failed to register RF-kill polldev\n");
> -			goto err_free_polldev;
> -		}
> -	}
> -
> -	return;
> -err_free_rfk:
> -	rfkill_free(rfk->rfkill);
> -	rfk->rfkill = NULL;
> -err_free_polldev:
> -	input_free_polled_device(rfk->poll_dev);
> -	rfk->poll_dev = NULL;
> -}
> -
> -void b43_rfkill_exit(struct b43_wldev *dev)
> -{
> -	struct b43_rfkill *rfk = &(dev->wl->rfkill);
> -
> -	if (rfk->poll_dev)
> -		input_unregister_polled_device(rfk->poll_dev);
> -	if (rfk->rfkill)
> -		rfkill_unregister(rfk->rfkill);
> -}
> -
> -void b43_rfkill_alloc(struct b43_wldev *dev)
> -{
> -	struct b43_wl *wl = dev->wl;
> -	struct b43_rfkill *rfk = &(wl->rfkill);
> +	rfk->registered = 0;
>  
> +	rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
> +	if (!rfk->rfkill)
> +		goto out_error;
>  	snprintf(rfk->name, sizeof(rfk->name),
>  		 "b43-%s", wiphy_name(wl->hw->wiphy));
> -
> -	rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
> -	if (!rfk->rfkill) {
> -		b43warn(wl, "Failed to allocate RF-kill button\n");
> -		return;
> -	}
>  	rfk->rfkill->name = rfk->name;
>  	rfk->rfkill->state = RFKILL_STATE_ON;
>  	rfk->rfkill->data = dev;
> @@ -165,18 +127,45 @@ void b43_rfkill_alloc(struct b43_wldev *dev)
>  	rfk->rfkill->user_claim_unsupported = 1;
>  
>  	rfk->poll_dev = input_allocate_polled_device();
> -	if (rfk->poll_dev) {
> -		rfk->poll_dev->private = dev;
> -		rfk->poll_dev->poll = b43_rfkill_poll;
> -		rfk->poll_dev->poll_interval = 1000; /* msecs */
> -	} else
> -		b43warn(wl, "Failed to allocate RF-kill polldev\n");
> +	if (!rfk->poll_dev)
> +		goto err_free_rfk;
> +	rfk->poll_dev->private = dev;
> +	rfk->poll_dev->poll = b43_rfkill_poll;
> +	rfk->poll_dev->poll_interval = 1000; /* msecs */
> +
> +	err = rfkill_register(rfk->rfkill);
> +	if (err)
> +		goto err_free_polldev;
> +	err = input_register_polled_device(rfk->poll_dev);
> +	if (err)
> +		goto err_unreg_rfk;
> +
> +	rfk->registered = 1;
> +
> +	return;
> +err_unreg_rfk:
> +	rfkill_unregister(rfk->rfkill);
> +err_free_polldev:
> +	input_free_polled_device(rfk->poll_dev);
> +	rfk->poll_dev = NULL;
> +err_free_rfk:
> +	rfkill_free(rfk->rfkill);
> +	rfk->rfkill = NULL;
> +out_error:
> +	rfk->registered = 0;
> +	b43warn(wl, "RF-kill button init failed\n");
>  }
>  
> -void b43_rfkill_free(struct b43_wldev *dev)
> +void b43_rfkill_exit(struct b43_wldev *dev)
>  {
>  	struct b43_rfkill *rfk = &(dev->wl->rfkill);
>  
> +	if (!rfk->registered)
> +		return;
> +	rfk->registered = 0;
> +
> +	input_unregister_polled_device(rfk->poll_dev);
> +	rfkill_unregister(rfk->rfkill);
>  	input_free_polled_device(rfk->poll_dev);
>  	rfk->poll_dev = NULL;
>  	rfkill_free(rfk->rfkill);
> diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h
> index 29544e8..adacf93 100644
> --- a/drivers/net/wireless/b43/rfkill.h
> +++ b/drivers/net/wireless/b43/rfkill.h
> @@ -15,14 +15,14 @@ struct b43_rfkill {
>  	struct rfkill *rfkill;
>  	/* The poll device for the RFKILL input button */
>  	struct input_polled_dev *poll_dev;
> +	/* Did initialization succeed? Used for freeing. */
> +	bool registered;
>  	/* The unique name of this rfkill switch */
> -	char name[32];
> +	char name[sizeof("b43-phy4294967295")];
>  };
>  
> -/* All the init functions return void, because we are not interested
> +/* The init function returns void, because we are not interested
>   * in failing the b43 init process when rfkill init failed. */
> -void b43_rfkill_alloc(struct b43_wldev *dev);
> -void b43_rfkill_free(struct b43_wldev *dev);
>  void b43_rfkill_init(struct b43_wldev *dev);
>  void b43_rfkill_exit(struct b43_wldev *dev);
>  
> @@ -36,12 +36,6 @@ struct b43_rfkill {
>  	/* empty */
>  };
>  
> -static inline void b43_rfkill_alloc(struct b43_wldev *dev)
> -{
> -}
> -static inline void b43_rfkill_free(struct b43_wldev *dev)
> -{
> -}
>  static inline void b43_rfkill_init(struct b43_wldev *dev)
>  {
>  }
> diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c
> index eefa6fb..619b453 100644
> --- a/drivers/net/wireless/b43legacy/debugfs.c
> +++ b/drivers/net/wireless/b43legacy/debugfs.c
> @@ -124,7 +124,7 @@ static ssize_t shm_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufs
>  	__le16 *le16buf = (__le16 *)buf;
>  
>  	for (i = 0; i < 0x1000; i++) {
> -		if (bufsize <= 0)
> +		if (bufsize < sizeof(tmp))
>  			break;
>  		tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 2 * i);
>  		le16buf[i] = cpu_to_le16(tmp);
> diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
> index f0e56df..3bde1e9 100644
> --- a/drivers/net/wireless/b43legacy/main.c
> +++ b/drivers/net/wireless/b43legacy/main.c
> @@ -2781,6 +2781,17 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
>  
>  	if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
>  		return;
> +
> +	/* Disable and sync interrupts. We must do this before than
> +	 * setting the status to INITIALIZED, as the interrupt handler
> +	 * won't care about IRQs then. */
> +	spin_lock_irqsave(&wl->irq_lock, flags);
> +	dev->irq_savedstate = b43legacy_interrupt_disable(dev,
> +							  B43legacy_IRQ_ALL);
> +	b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */
> +	spin_unlock_irqrestore(&wl->irq_lock, flags);
> +	b43legacy_synchronize_irq(dev);
> +
>  	b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
>  
>  	mutex_unlock(&wl->mutex);
> @@ -2791,14 +2802,6 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
>  
>  	ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */
>  
> -	/* Disable and sync interrupts. */
> -	spin_lock_irqsave(&wl->irq_lock, flags);
> -	dev->irq_savedstate = b43legacy_interrupt_disable(dev,
> -							  B43legacy_IRQ_ALL);
> -	b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */
> -	spin_unlock_irqrestore(&wl->irq_lock, flags);
> -	b43legacy_synchronize_irq(dev);
> -
>  	b43legacy_mac_suspend(dev);
>  	free_irq(dev->dev->irq, dev);
>  	b43legacydbg(wl, "Wireless interface stopped\n");
> @@ -3332,7 +3335,7 @@ out_mutex_unlock:
>  	return err;
>  }
>  
> -void b43legacy_stop(struct ieee80211_hw *hw)
> +static void b43legacy_stop(struct ieee80211_hw *hw)
>  {
>  	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
>  	struct b43legacy_wldev *dev = wl->current_dev;
> -- 
> John W. Linville
> linville@tuxdriver.com
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
John W. Linville
linville@tuxdriver.com

      reply	other threads:[~2007-11-08 14:01 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-11-06 20:07 Please pull 'fixes-jgarzik' branch of wireless-2.6 John W. Linville
2007-11-07 19:13 ` John W. Linville
2007-11-07 19:24   ` Jeff Garzik
2007-11-08  1:34     ` Please pull 'fixes-jgarzik' branch of wireless-2.6 (this time for real!) John W. Linville
2007-11-08 14:01       ` John W. Linville [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20071108140132.GG11957@tuxdriver.com \
    --to=linville@tuxdriver.com \
    --cc=jeff@garzik.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.