From: Bernhard Noelte <bernhard@noelte-family.de>
To: Luiz Augusto von Dentz <luiz.dentz@gmail.com>,
linux-bluetooth@vger.kernel.org
Subject: Re: Re: [Patch BlueZ 1/1] Make network server interface handling more robust
Date: Mon, 19 Sep 2016 22:28:31 +0200 [thread overview]
Message-ID: <9969450.4Wx3dLe6K4@comitvend> (raw)
In-Reply-To: <CABBYNZK6zeHyyX6GFAFdkq3mJOOBOz8kxLr0Bakxq5qTsmJofA@mail.gmail.com>
Hi Luiz,
> I guess there should probably be a way to prevent systemd-udev to
> change to rename the interface
As I mentioned, I could not manage. Also makes Bluez depend on a configuration
where it is not necessary.
> or then we need kernel changes to make
> sure the interface index is sent.
It looks like the "correct" solution, but this one does not change
the kernel API.
> sleep is no acceptable in the daemon code, it should never block in
> any circumstances.
Yes, obviously.
Thank you for the review. I will prepare a new patch.
Bobby
Am Montag, 19. September 2016, 15:16:06 CEST schrieben Sie:
> Hi Bobby,
>
> On Sun, Sep 18, 2016 at 7:35 PM, Bobby Noelte <b0661n0e17e@gmail.com> wrote:
> > From: "b0661n0e71e@gmail.com" <b0661.n0e17e@gmail.com>
> >
> > Interface names may be renamed by udev (systemd-udev) after creation
> > before the interface is up. Interfaces may also be renamed when
> > the interface is down due to a bluetoothd restart.
>
> I guess there should probably be a way to prevent systemd-udev to
> change to rename the interface or then we need kernel changes to make
> sure the interface index is sent.
>
> > Use the interface index, that does not change on renaming, where possible.
> > Also do some retries when the creation of an interface fails.
> > ---
> >
> > profiles/network/bnep.c | 311
> > ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 260
> > insertions(+), 51 deletions(-)
> >
> > diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
> > index 9bf0b18..cba0f63 100644
> > --- a/profiles/network/bnep.c
> > +++ b/profiles/network/bnep.c
> > @@ -65,6 +65,7 @@ struct bnep {
> >
> > uint16_t dst;
> > bdaddr_t dst_addr;
> > char iface[16];
> >
> > + unsigned int ifindex;
> >
> > guint attempts;
> > guint setup_to;
> > guint watch;
> >
> > @@ -98,25 +99,109 @@ int bnep_cleanup(void)
> >
> > return 0;
> >
> > }
> >
> > +/**
> > + * private: for local use only.
> > + *
> > + * bnep_indextoname() - Return interface name corresponding to interface
> > index. + * @ifindex interface index.
> > + * @iface interface name, output only, will be filled with '<unknown>' in
> > case of error. + *
> > + * The name is placed in the buffer pointed to by ifname.
> > + * The buffer must allow for the storage of at least IF_NAMESIZE bytes.
> > + *
> > + * On success 0 is returned. On error errno as a negative value is
> > returned. + */
> > +static int bnep_indextoname(unsigned int ifindex, char *iface)
> > +{
> > + int err;
> > +
> > + err = 0;
> > + if (if_indextoname(ifindex, iface) == 0) {
> > + err = -errno;
> > + strncpy(iface, "<unknown>", 10);
> > + }
> > + return err;
> > +}
> > +
> > +/**
> > + * private: for local use only.
> > + *
> > + * bnep_nametoindext() - Return interface index corresponding to
> > interface name. + * @iface interface name
> > + * @ifindex interface index, output only, will be filled with 0 in case
> > of error. + *
> > + * The interface index is placed in the variable pointed to by ifindex.
> > + *
> > + * In case the interface is temporarily unavailable do a retry.
> > + *
> > + * On success 0 is returned. On error errno as a negative value is
> > returned. + */
> > +static int bnep_nametoindex(const char *iface, unsigned int *ifindex)
> > +{
> > + int retry;
> > + int err;
> > +
> > + retry = 0;
> > + while (retry < 2) {
> > + DBG("get interface index for device %s retry %d", iface,
> > retry); + *ifindex = if_nametoindex(iface);
> > + if (*ifindex != 0) {
> > + DBG("got interface index %d for added device %s
> > retry %d", + *ifindex, iface, retry);
> > + err = 0;
> > + } else {
> > + err = -errno;
> > + }
> > + if (err != -EAGAIN)
> > + break;
> > + /* EAGAIN - Resource temporarily unavailable */
> > + retry++;
> > + sleep(1);
>
> sleep is no acceptable in the daemon code, it should never block in
> any circumstances.
>
> > + }
> > + return err;
> > +}
> > +
> >
> > static int bnep_conndel(const bdaddr_t *dst)
> > {
> >
> > + int err;
> >
> > struct bnep_conndel_req req;
> >
> > + char addr[20];
> >
> > + ba2str(dst, &addr[0]);
> >
> > memset(&req, 0, sizeof(req));
> > baswap((bdaddr_t *)&req.dst, dst);
> > req.flags = 0;
> >
> > - if (ioctl(ctl, BNEPCONNDEL, &req) < 0) {
> > - int err = -errno;
> > - error("bnep: Failed to kill connection: %s (%d)",
> > - strerror(-err),
> > -err); + err = ioctl(ctl, BNEPCONNDEL, &req);
> > + if (err < 0) {
> > + err = -errno;
> > + error("bnep: Failed to kill connection %s: %s (%d)",
> > + addr, strerror(-err), -err);
> >
> > return err;
> >
> > }
> >
> > + DBG("deleted device %s, %d", addr, err);
> > +
> >
> > return 0;
> >
> > }
> >
> > -static int bnep_connadd(int sk, uint16_t role, char *dev)
> > +/**
> > + * private: for local use only.
> > + *
> > + * bnep_connadd() - Add bluetooth ethernet connection.
> > + * @sk bluez control socket.
> > + * @role
> > + * @dev device name, template for new interface name (e.g. "bnep%d") or
> > name. + * @dst bluetooth address, only needed for retries.
> > + * @ifindex interface index, ouput only - new interface index
> > + *
> > + * In case the interface can not be accessed by the device name (e.g. due
> > to udev rename) do a retry. + *
> > + * On success 0 is returned. On error errno as a negative value is
> > returned. + */
> > +static int bnep_connadd(int sk, uint16_t role, char *dev, const bdaddr_t
> > *dst, unsigned int *ifindex)>
> > {
> >
> > struct bnep_connadd_req req;
> >
> > + int err;
> > + int retry;
> >
> > memset(&req, 0, sizeof(req));
> > strncpy(req.device, dev, 16);
> >
> > @@ -125,15 +210,40 @@ static int bnep_connadd(int sk, uint16_t role, char
> > *dev)>
> > req.sock = sk;
> > req.role = role;
> > req.flags = (1 << BNEP_SETUP_RESPONSE);
> >
> > - if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
> > - int err = -errno;
> > - error("bnep: Failed to add device %s: %s(%d)",
> > - dev, strerror(-err),
> > -err);
> > - return err;
> > +
> > + retry = 0;
> > +
> > + while (retry < 2) {
> > + DBG("add device %s retry %d", req.device, retry);
> > +
> > + err = ioctl(ctl, BNEPCONNADD, &req);
> > + if (err < 0) {
> > + err = -errno;
> > + break;
> > + }
> > + DBG("added device %s retry %d", req.device, retry);
> > + /*
> > + * There is a potential race condition between udev
> > renaming the interface + * after being created by
> > BNEPCONNADD and bnep_nametoindex providing + * the
> > interface index.
> > + */
> > + err = bnep_nametoindex(&req.device[0], ifindex);
> > + if (!err)
> > + break;
> > +
> > + /* Prepare retry */
> > + retry++;
> > + bnep_conndel(dst);
> > + /* Give BT some time to really delete. */
> > + sleep(1);
>
> We aint gonna fix any race condition with sleep.
>
> > }
> >
> > - strncpy(dev, req.device, 16);
> > - return 0;
> > + if (err) {
> > + error("bnep: Failed to add device %s with interface index
> > %d: %s(%d)", + req.device, *ifindex,
> > strerror(-err), -err); + }
> > +
> > + return err;
> >
> > }
> >
> > static uint32_t bnep_getsuppfeat(void)
> >
> > @@ -148,51 +258,108 @@ static uint32_t bnep_getsuppfeat(void)
> >
> > return feat;
> >
> > }
> >
> > -static int bnep_if_up(const char *devname)
> > +/**
> > + * private: for local use only.
> > + *
> > + * bnep_if_up() - Bring interface up.
> > + * @ifindex interface index
> > + *
> > + * In case the interface can not be accessed (e.g. due to udev rename) do
> > a retry. + *
> > + * On success 0 is returned. On error errno as a negative value is
> > returned. + */
> > +static int bnep_if_up(unsigned int ifindex)
> >
> > {
> >
> > struct ifreq ifr;
> >
> > - int sk, err = 0;
> > + int sk, err;
> > + int retry;
> >
> > sk = socket(AF_INET, SOCK_DGRAM, 0);
> >
> > memset(&ifr, 0, sizeof(ifr));
> >
> > - strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
> > -
> >
> > ifr.ifr_flags |= IFF_UP;
> > ifr.ifr_flags |= IFF_MULTICAST;
> >
> > - if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) < 0) {
> > + retry = 0;
> > + while (retry < 2) {
> > + err = bnep_indextoname(ifindex, ifr.ifr_name);
> > + if (err)
> > + break;
> > + /*
> > + * There is a potential race condition between udev
> > renaming the interface + * after the name is retrieved by
> > bnep_nametoindex and the usage of the + * interface name by
> > ioctl.
> > + */
> > + if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) == 0)
> > + break;
> >
> > err = -errno;
> >
> > - error("bnep: Could not bring up %s: %s(%d)",
> > - devname, strerror(-err),
> > -err); + DBG("could not bring up interface %s with index
> > %d: %s(%d) retry %d", + ifr.ifr_name, ifindex,
> > strerror(-err), -err, retry); +
> > + /* Prepare retry */
> > + retry++;
> > + sleep(1);
>
> Ditto.
>
> > }
> >
> > close(sk);
> >
> > + if (err) {
> > + error("bnep: Could not bring up interface %s with index
> > %d: %s(%d)", + ifr.ifr_name, ifindex,
> > strerror(-err), -err); + }
> > +
> >
> > return err;
> >
> > }
> >
> > -static int bnep_if_down(const char *devname)
> > +/**
> > + * private: for local use only.
> > + *
> > + * bnep_if_down() - Bring interface down.
> > + * @ifindex interface index
> > + *
> > + * In case the interface can not be accessed (e.g. due to udev rename) do
> > a retry. + *
> > + * On success 0 is returned. On error errno as a negative value is
> > returned. + */
> > +static int bnep_if_down(unsigned int ifindex)
> >
> > {
> >
> > struct ifreq ifr;
> >
> > - int sk, err = 0;
> > + int sk, err;
> > + int retry;
> >
> > sk = socket(AF_INET, SOCK_DGRAM, 0);
> >
> > memset(&ifr, 0, sizeof(ifr));
> >
> > - strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
> > -
> >
> > ifr.ifr_flags &= ~IFF_UP;
> >
> > - /* Bring down the interface */
> > - if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) < 0) {
> > + retry = 0;
> > + while (retry < 2) {
> > + err = bnep_indextoname(ifindex, ifr.ifr_name);
> > + if (err)
> > + break;
> > + /*
> > + * There is a potential race condition between udev
> > renaming the interface + * after the name is retrieved by
> > bnep_nametoindex and the usage of the + * interface name by
> > ioctl.
> > + */
> > + if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) == 0)
> > + break;
> >
> > err = -errno;
> >
> > - error("bnep: Could not bring down %s: %s(%d)",
> > - devname, strerror(-err),
> > -err); + DBG("could not bring down interface %s with index
> > %d: %s(%d) retry %d", + ifr.ifr_name, ifindex,
> > strerror(-err), -err, retry); +
> > + /* Prepare retry */
> > + retry++;
> > + sleep(1);
>
> Ditto.
>
> > }
> >
> > close(sk);
> >
> > + if (err) {
> > + error("bnep: Could not bring down interface %s with index
> > %d: %s(%d)", + ifr.ifr_name, ifindex,
> > strerror(-err), -err); + }
> > +
> >
> > return err;
> >
> > }
> >
> > @@ -270,14 +437,19 @@ static gboolean bnep_setup_cb(GIOChannel *chan,
> > GIOCondition cond,>
> > setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
> >
> > sk = g_io_channel_unix_get_fd(session->io);
> >
> > - if (bnep_connadd(sk, session->src, session->iface) < 0)
> > + if (bnep_connadd(sk, session->src, session->iface,
> > &session->dst_addr, &session->ifindex) < 0)>
> > goto failed;
> >
> > - if (bnep_if_up(session->iface) < 0) {
> > + if (bnep_if_up(session->ifindex) < 0) {
> >
> > bnep_conndel(&session->dst_addr);
> > goto failed;
> >
> > }
> >
> > + /* Update interface name to current one only after interface is
> > up.
> > + * Only at that time the name should be stable (no udev rename).
> > + */
> > + bnep_indextoname(session->ifindex, session->iface);
> > +
> >
> > session->watch = g_io_add_watch(session->io,
> >
> > G_IO_ERR | G_IO_HUP | G_IO_NVAL,
> > (GIOFunc) bnep_watchdog_cb,
> > session);
> >
> > @@ -305,7 +477,7 @@ static int bnep_setup_conn_req(struct bnep *session)
> >
> > req = (void *) pkt;
> > req->type = BNEP_CONTROL;
> > req->ctrl = BNEP_SETUP_CONN_REQ;
> >
> > - req->uuid_size = 2; /* 16bit UUID */
> > + req->uuid_size = 2; /* 16bit UUID */
> >
> > s = (void *) req->service;
> > s->src = htons(session->src);
> > s->dst = htons(session->dst);
> >
> > @@ -354,6 +526,7 @@ struct bnep *bnep_new(int sk, uint16_t local_role,
> > uint16_t remote_role,>
> > session->dst = remote_role;
> > strncpy(session->iface, iface, 16);
> > session->iface[15] = '\0';
> >
> > + session->ifindex = 0;
> >
> > g_io_channel_set_close_on_unref(session->io, TRUE);
> > session->watch = g_io_add_watch(session->io,
> >
> > @@ -430,20 +603,26 @@ void bnep_disconnect(struct bnep *session)
> >
> > session->io = NULL;
> >
> > }
> >
> > - bnep_if_down(session->iface);
> > + bnep_if_down(session->ifindex);
> >
> > bnep_conndel(&session->dst_addr);
> >
> > }
> >
> > -static int bnep_add_to_bridge(const char *devname, const char *bridge)
> > +static int bnep_add_to_bridge(unsigned int ifindex, const char *bridge)
> >
> > {
> >
> > - int ifindex;
> >
> > struct ifreq ifr;
> > int sk, err = 0;
> >
> > + char devname[IF_NAMESIZE];
> >
> > - if (!devname || !bridge)
> > + DBG("add interface index %d to bridge %s", ifindex, bridge);
> > + if (!ifindex || !bridge)
> >
> > return -EINVAL;
> >
> > - ifindex = if_nametoindex(devname);
> > + err = bnep_indextoname(ifindex, &devname[0]);
> > + if (err) {
> > + error("bnep: Can't add interface %s with index %d to the
> > bridge %s: %s(%d)", + devname,
> > ifindex, bridge, strerror(-err), -err); + return -EINVAL;
> > + }
> >
> > sk = socket(AF_INET, SOCK_STREAM, 0);
> > if (sk < 0)
> >
> > @@ -451,7 +630,8 @@ static int bnep_add_to_bridge(const char *devname,
> > const char *bridge)>
> > memset(&ifr, 0, sizeof(ifr));
> > strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
> >
> > - ifr.ifr_ifindex = ifindex;
> > + ifr.ifr_ifindex = (int)ifindex;
> > +
> >
> > if (ioctl(sk, SIOCBRADDIF, &ifr) < 0) {
> >
> > err = -errno;
> >
> > @@ -466,16 +646,21 @@ static int bnep_add_to_bridge(const char *devname,
> > const char *bridge)>
> > return err;
> >
> > }
> >
> > -static int bnep_del_from_bridge(const char *devname, const char *bridge)
> > +static int bnep_del_from_bridge(unsigned int ifindex, const char *bridge)
> >
> > {
> >
> > - int ifindex;
> >
> > struct ifreq ifr;
> > int sk, err = 0;
> >
> > + char devname[IF_NAMESIZE];
> >
> > - if (!devname || !bridge)
> > + if (!ifindex || !bridge)
> >
> > return -EINVAL;
> >
> > - ifindex = if_nametoindex(devname);
> > + err = bnep_indextoname(ifindex, &devname[0]);
> > + if (err) {
> > + error("bnep: Can't delete interface %s with index %d from
> > the bridge %s: %s(%d)", + devname,
> > ifindex, bridge, strerror(-err), -err); + return -EINVAL;
> > + }
> >
> > sk = socket(AF_INET, SOCK_STREAM, 0);
> > if (sk < 0)
> >
> > @@ -483,7 +668,7 @@ static int bnep_del_from_bridge(const char *devname,
> > const char *bridge)>
> > memset(&ifr, 0, sizeof(ifr));
> > strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
> >
> > - ifr.ifr_ifindex = ifindex;
> > + ifr.ifr_ifindex = (int)ifindex;
> >
> > if (ioctl(sk, SIOCBRDELIF, &ifr) < 0) {
> >
> > err = -errno;
> >
> > @@ -606,6 +791,7 @@ static int bnep_server_add_legacy(int sk, uint16_t
> > dst, char *bridge,>
> > char *iface, const bdaddr_t *addr,
> > uint8_t *setup_data, int len)
> >
> > {
> >
> > + unsigned int ifindex;
> >
> > int err, n;
> > uint16_t rsp;
> >
> > @@ -616,27 +802,32 @@ static int bnep_server_add_legacy(int sk, uint16_t
> > dst, char *bridge,>
> > goto reply;
> >
> > }
> >
> > - err = bnep_connadd(sk, dst, iface);
> > + err = bnep_connadd(sk, dst, iface, addr, &ifindex);
> >
> > if (err < 0) {
> >
> > rsp = BNEP_CONN_NOT_ALLOWED;
> > goto reply;
> >
> > }
> >
> > - err = bnep_add_to_bridge(iface, bridge);
> > + err = bnep_add_to_bridge(ifindex, bridge);
> >
> > if (err < 0) {
> >
> > bnep_conndel(addr);
> > rsp = BNEP_CONN_NOT_ALLOWED;
> > goto reply;
> >
> > }
> >
> > - err = bnep_if_up(iface);
> > + err = bnep_if_up(ifindex);
> >
> > if (err < 0) {
> >
> > - bnep_del_from_bridge(iface, bridge);
> > + bnep_del_from_bridge(ifindex, bridge);
> >
> > bnep_conndel(addr);
> > rsp = BNEP_CONN_NOT_ALLOWED;
> > goto reply;
> >
> > }
> >
> > + /* Update interface name to current one only after interface is
> > up.
> > + * Only at that time the name should be stable (no udev rename).
> > + */
> > + bnep_indextoname(ifindex, iface);
> > +
> >
> > rsp = BNEP_SUCCESS;
> >
> > reply:
> > @@ -652,6 +843,7 @@ reply:
> > int bnep_server_add(int sk, char *bridge, char *iface, const bdaddr_t
> > *addr,>
> > uint8_t *setup_data, int
> > len)
> >
> > {
> >
> > + unsigned int ifindex;
> >
> > int err;
> > uint32_t feat;
> > uint16_t rsp, dst;
> >
> > @@ -691,24 +883,29 @@ int bnep_server_add(int sk, char *bridge, char
> > *iface, const bdaddr_t *addr,>
> > return bnep_server_add_legacy(sk, dst, bridge, iface,
> > addr,
> >
> > setup_data, len);
> >
> > - err = bnep_connadd(sk, dst, iface);
> > + err = bnep_connadd(sk, dst, iface, addr, &ifindex);
> >
> > if (err < 0) {
> >
> > rsp = BNEP_CONN_NOT_ALLOWED;
> > goto failed;
> >
> > }
> >
> > - err = bnep_add_to_bridge(iface, bridge);
> > + err = bnep_add_to_bridge(ifindex, bridge);
> >
> > if (err < 0)
> >
> > goto failed_conn;
> >
> > - err = bnep_if_up(iface);
> > + err = bnep_if_up(ifindex);
> >
> > if (err < 0)
> >
> > goto failed_bridge;
> >
> > + /* Update interface name to current one only after interface is
> > up.
> > + * Only at that time the name should be stable (no udev rename).
> > + */
> > + bnep_indextoname(ifindex, iface);
> > +
> >
> > return 0;
> >
> > failed_bridge:
> > - bnep_del_from_bridge(iface, bridge);
> > + bnep_del_from_bridge(ifindex, bridge);
> >
> > failed_conn:
> > bnep_conndel(addr);
> >
> > @@ -727,10 +924,22 @@ failed:
> > void bnep_server_delete(char *bridge, char *iface, const bdaddr_t *addr)
> > {
> >
> > + int err;
> > + unsigned int ifindex;
> > +
> >
> > if (!bridge || !iface || !addr)
> >
> > return;
> >
> > - bnep_del_from_bridge(iface, bridge);
> > - bnep_if_down(iface);
> > + err = bnep_nametoindex(iface, &ifindex);
> > + if (err) {
> > + error("bnep: Failed to delete device %s - interface not
> > available/ renamed: %s(%d)", +
> > iface, strerror(-err), -err); + goto failed;
> > + }
> > +
> > + bnep_del_from_bridge(ifindex, bridge);
> > + bnep_if_down(ifindex);
> >
> > +failed:
> > bnep_conndel(addr);
> >
> > }
> >
> > +
> > --
> > 2.7.4
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-bluetooth"
> > in the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
prev parent reply other threads:[~2016-09-19 20:28 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-18 16:35 [Patch BlueZ 0/1] Make network server interface handling more robust Bobby Noelte
2016-09-18 16:35 ` [Patch BlueZ 1/1] " Bobby Noelte
2016-09-19 12:16 ` Luiz Augusto von Dentz
2016-09-19 20:28 ` Bernhard Noelte [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=9969450.4Wx3dLe6K4@comitvend \
--to=bernhard@noelte-family.de \
--cc=linux-bluetooth@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
/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.