Пример #1
0
int g_pn_netlink_add_route(GIsiModem *idx, uint8_t remote)
{
	uint32_t ifindex = g_isi_modem_index(idx);

	if (ifindex == 0)
		return -ENODEV;

	if (remote != PN_DEV_SOS && remote != PN_DEV_HOST)
		return -EINVAL;

	return netlink_addroute(ifindex, remote);
}
Пример #2
0
GPhonetNetlink *g_pn_netlink_start(GIsiModem *idx,
				   GPhonetNetlinkFunc callback,
				   void *data)
{
	GIOChannel *chan;
	GPhonetNetlink *self;
	int fd;
	unsigned group = RTNLGRP_LINK;
	unsigned interface = g_isi_modem_index(idx);

	fd = netlink_socket();
	if (fd == -1)
		return NULL;

	self = calloc(1, sizeof(*self));
	if (self == NULL)
		goto error;

	fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL));

	if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
		       &group, sizeof(group)))
		goto error;

	if (interface)
		bring_up(interface);

	g_pn_netlink_getlink(fd);

	chan = g_io_channel_unix_new(fd);
	if (chan == NULL)
		goto error;
	g_io_channel_set_close_on_unref(chan, TRUE);
	g_io_channel_set_encoding(chan, NULL, NULL);
	g_io_channel_set_buffered(chan, FALSE);

	self->callback = callback;
	self->opaque = data;
	self->interface = interface;
	self->watch = g_io_add_watch(chan, G_IO_IN|G_IO_ERR|G_IO_HUP,
					g_pn_nl_process, self);
	g_io_channel_unref(chan);

	netlink_list = g_slist_prepend(netlink_list, self);

	return self;

error:
	close(fd);
	free(self);
	return NULL;
}
Пример #3
0
GPhonetNetlink *g_pn_netlink_by_modem(GIsiModem *idx)
{
	GSList *m;
	unsigned index = g_isi_modem_index(idx);

	for (m = netlink_list; m; m = m->next) {
		GPhonetNetlink *self = m->data;

		if (index == self->interface)
			return self;
	}

	return NULL;
}
Пример #4
0
GIsiPEP *g_isi_pep_create(GIsiModem *modem, GIsiPEPCallback cb, void *opaque)
{
    unsigned ifi = g_isi_modem_index(modem);
    GIsiPEP *pep = NULL;
    GIOChannel *channel;
    int fd;
    char buf[IF_NAMESIZE];

    fd = socket(PF_PHONET, SOCK_SEQPACKET, 0);
    if (fd == -1)
        return NULL;

    fcntl(fd, F_SETFD, FD_CLOEXEC);
    fcntl(fd, F_SETFL, O_NONBLOCK|fcntl(fd, F_GETFL));

    if (if_indextoname(ifi, buf) == NULL)
        goto error;

    if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, buf, IF_NAMESIZE) != 0)
        goto error;

    pep = g_try_malloc(sizeof(GIsiPEP));
    if (pep == NULL)
        goto error;

    pep->ready = cb;
    pep->opaque = opaque;
    pep->gprs_fd = -1;
    pep->handle = 0;

    if (listen(fd, 1) || ioctl(fd, SIOCPNGETOBJECT, &pep->handle))
        goto error;

    channel = g_io_channel_unix_new(fd);
    g_io_channel_set_close_on_unref(channel, TRUE);
    g_io_channel_set_encoding(channel, NULL, NULL);
    g_io_channel_set_buffered(channel, FALSE);
    pep->source = g_io_add_watch(channel,
                                 G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
                                 g_isi_pep_callback, pep);
    g_io_channel_unref(channel);

    return pep;

error:
    close(fd);
    g_free(pep);
    return NULL;
}
Пример #5
0
static void phonet_status_cb(GIsiModem *modem, enum GIsiPhonetLinkState st,
				char const *ifname, void *data)
{
	struct ofono_modem *om = data;
	struct isi_data *isi = ofono_modem_get_data(om);

	DBG("Link %s (%u) is %s", isi->ifname, g_isi_modem_index(isi->modem),
		st == PN_LINK_REMOVED ? "removed" :
		st == PN_LINK_DOWN ? "down" : "up");

	isi->linkstate = st;

	if (st == PN_LINK_UP)
		g_isi_client_verify(isi->client, reachable_cb, om, NULL);
	else if (st == PN_LINK_DOWN)
		set_power_by_mce_state(om, isi, MCE_POWER_OFF);
}
Пример #6
0
/*
 * Add or remove isimodems
 * when usbpn* phonet interfaces are added/removed
 */
static void usbpn_status_cb(GIsiModem *idx,
				GPhonetLinkState st,
				char const ifname[],
				void *data)
{
	struct ofono_modem *modem;
	int error;

	DBG("Phonet link %s (%u) is %s",
		ifname, g_isi_modem_index(idx),
		st == PN_LINK_REMOVED ? "removed" :
		st == PN_LINK_DOWN ? "down" : "up");

	/* Expect phonet interface name usbpn<idx> */
	if (strncmp(ifname, "usbpn", 5) ||
		ifname[5 + strspn(ifname + 5, "0123456789")])
		return;

	if (st == PN_LINK_REMOVED)
		return;

	if (g_pn_netlink_by_modem(idx)) {
		DBG("Modem for interface %s already exists", ifname);
		return;
	}

	error = g_pn_netlink_set_address(idx, PN_DEV_PC);
	if (error && error != -EEXIST) {
		DBG("g_pn_netlink_set_address: %s\n", strerror(-error));
		return;
	}

	modem = ofono_modem_create(NULL, "isimodem");
	if (!modem)
		return;

	ofono_modem_set_string(modem, "Interface", ifname);

	if (ofono_modem_register(modem) == 0)
		DBG("Done regging modem %s", ofono_modem_get_path(modem));
	else
		ofono_modem_remove(modem);
}
Пример #7
0
static int netlink_getack(int fd)
{
	struct {
		struct nlmsghdr nlh;
		char buf[SIZE_NLMSG];
	} resp;
	struct iovec iov = { &resp, sizeof(resp), };
	struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, };
	ssize_t ret;
	struct nlmsghdr *nlh = &resp.nlh;

	ret = recvmsg(fd, &msg, 0);
	if (ret == -1)
		return -errno;

	if (msg.msg_flags & MSG_TRUNC)
		return -EIO;

	for (; NLMSG_OK(nlh, (size_t)ret); nlh = NLMSG_NEXT(nlh, ret)) {

		if (nlh->nlmsg_type == NLMSG_DONE)
			return 0;

		if (nlh->nlmsg_type == NLMSG_ERROR) {
			struct nlmsgerr *err = NLMSG_DATA(nlh);
			return err->error;
		}
	}

	return -EIO;
}

/* Set local address */
static int netlink_setaddr(uint32_t ifa_index, uint8_t ifa_local)
{
	struct ifaddrmsg *ifa;
	struct rtattr *rta;
	uint32_t reqlen = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(*ifa))
				+ RTA_SPACE(1));
	struct req {
		struct nlmsghdr nlh;
		char buf[512];
	} req = {
		.nlh = {
			.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
			.nlmsg_type = RTM_NEWADDR,
			.nlmsg_pid = getpid(),
			.nlmsg_len = reqlen,
		},
	};
	int fd;
	int error;
	struct sockaddr_nl addr = { .nl_family = AF_NETLINK, };

	ifa = NLMSG_DATA(&req.nlh);
	ifa->ifa_family = AF_PHONET;
	ifa->ifa_prefixlen = 0;
	ifa->ifa_index = ifa_index;

	rta = IFA_RTA(ifa);
	rta->rta_type = IFA_LOCAL;
	rta->rta_len = RTA_LENGTH(1);
	*(uint8_t *)RTA_DATA(rta) = ifa_local;

	fd = netlink_socket();
	if (fd == -1)
		return -errno;

	if (sendto(fd, &req, reqlen, 0, (void *)&addr, sizeof(addr)) == -1)
		error = -errno;
	else
		error = netlink_getack(fd);

	close(fd);

	return error;
}

int g_pn_netlink_set_address(GIsiModem *idx, uint8_t local)
{
	uint32_t ifindex = g_isi_modem_index(idx);

	if (ifindex == 0)
		return -ENODEV;

	if (local != PN_DEV_PC && local != PN_DEV_SOS)
		return -EINVAL;

	return netlink_setaddr(ifindex, local);
}