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@xxxxxxxxx> wrote: > > From: "b0661n0e71e@xxxxxxxxx" <b0661.n0e17e@xxxxxxxxx> > > > > 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@xxxxxxxxxxxxxxx > > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html