Example #1
0
static void
server_register(void)
{
	sdp_nap_profile_t p;
	int rv;

	if (server_ss == NULL) {
		server_ss = sdp_open_local(control_path);
		if (server_ss == NULL || sdp_error(server_ss) != 0) {
			log_err("failed to contact SDP server");
			return;
		}
	}

	memset(&p, 0, sizeof(p));
	p.psm = l2cap_psm;
	p.load_factor = server_avail;
	p.security_description = (l2cap_mode == 0 ? 0x0000 : 0x0001);

	if (server_handle)
		rv = sdp_change_service(server_ss, server_handle,
		    (uint8_t *)&p, sizeof(p));
	else
		rv = sdp_register_service(server_ss, service_class,
		    &local_bdaddr, (uint8_t *)&p, sizeof(p), &server_handle);

	if (rv != 0) {
		errno = sdp_error(server_ss);
		log_err("%s: %m", service_name);
		exit(EXIT_FAILURE);
	}
}
Example #2
0
/* Execute commands */
static int
do_sdp_command(bdaddr_p bdaddr, char const *control, int local,
		int argc, char **argv)
{
	char			*cmd = argv[0];
	struct sdp_command	*c = NULL;
	void			*xs = NULL;
	int			 e, help;

	help = 0;
	if (strcasecmp(cmd, "help") == 0) {
		argc --;
		argv ++;

		if (argc <= 0) {
			fprintf(stdout, "Supported commands:\n");
			print_sdp_command(sdp_commands);
			fprintf(stdout, "\nFor more information use " \
				"'help command'\n");

			return (OK);
		}

		help = 1;
		cmd = argv[0];
	}

	c = find_sdp_command(cmd, sdp_commands);
	if (c == NULL) {
		fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
		return (ERROR);
	}

	if (!help) {
		if (!local) {
			if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0)
				usage();

			xs = sdp_open(NG_HCI_BDADDR_ANY, bdaddr);
		} else
			xs = sdp_open_local(control);

		if (xs == NULL)
			errx(1, "Could not create SDP session object");
		if (sdp_error(xs) == 0)
			e = (c->handler)(xs, -- argc, ++ argv);
		else
			e = ERROR;
	} else
		e = USAGE;

	switch (e) {
	case OK:
	case FAILED:
		break;

	case ERROR:
		fprintf(stdout, "Could not execute command \"%s\". %s\n",
			cmd, strerror(sdp_error(xs)));
		break;

	case USAGE:
		fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
		break;

	default: assert(0); break;
	}

	sdp_close(xs);

	return (e);
} /* do_sdp_command */
Example #3
0
/* Main */
int
main(int argc, char *argv[])
{
	struct sockaddr_rfcomm   sock_addr;
	char			*label = NULL, *unit = NULL, *ep = NULL;
	bdaddr_t		 addr;
	int			 s, channel, detach, server, service,
				 regdun, regsp;
	pid_t			 pid;

	memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));
	channel = 0;
	detach = 1;
	server = 0;
	service = 0;
	regdun = 0;
	regsp = 0;

	/* Parse command line arguments */
	while ((s = getopt(argc, argv, "a:cC:dDhl:sSu:")) != -1) {
		switch (s) {
		case 'a': /* BDADDR */
			if (!bt_aton(optarg, &addr)) {
				struct hostent	*he = NULL;

				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(1, "%s: %s", optarg, hstrerror(h_errno));

				memcpy(&addr, he->h_addr, sizeof(addr));
			}
			break;

		case 'c': /* client */
			server = 0;
			break;

		case 'C': /* RFCOMM channel */
			channel = strtoul(optarg, &ep, 10);
			if (*ep != '\0') {
				channel = 0;
				switch (tolower(optarg[0])) {
				case 'd': /* DialUp Networking */
					service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
					break;

				case 'l': /* LAN Access Using PPP */
					service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
					break;
				}
			}
			break;

		case 'd': /* do not detach */
			detach = 0;
			break;

		case 'D': /* Register DUN service as well as LAN service */
			regdun = 1;
			break;

		case 'l': /* PPP label */
			label = optarg;
			break;

		case 's': /* server */
			server = 1;
			break;

		case 'S': /* Register SP service as well as LAN service */
			regsp = 1;
			break;

		case 'u': /* PPP -unit option */
			strtoul(optarg, &ep, 10);
			if (*ep != '\0')
				usage();
				/* NOT REACHED */

			unit = optarg;
			break;

		case 'h':
		default:
			usage();
			/* NOT REACHED */
		}
	}

	/* Check if we got everything we wanted */
	if (label == NULL)
                errx(1, "Must specify PPP label");

	if (!server) {
		if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)
                	errx(1, "Must specify server BD_ADDR");

		/* Check channel, if was not set then obtain it via SDP */
		if (channel == 0 && service != 0)
			if (rfcomm_channel_lookup(NULL, &addr, service,
							&channel, &s) != 0)
				errc(1, s, "Could not obtain RFCOMM channel");
	}

        if (channel <= 0 || channel > 30)
                errx(1, "Invalid RFCOMM channel number %d", channel);

	openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER);

	if (detach && daemon(0, 0) < 0) {
		syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
			strerror(errno), errno);
		exit(1);
	}

	s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
	if (s < 0) {
		syslog(LOG_ERR, "Could not create socket. %s (%d)",
			strerror(errno), errno);
		exit(1);
	}

	if (server) {
		struct sigaction	 sa;
		void			*ss = NULL;
		sdp_lan_profile_t	 lan;

		/* Install signal handler */
		memset(&sa, 0, sizeof(sa));
		sa.sa_handler = sighandler;

		if (sigaction(SIGTERM, &sa, NULL) < 0) {
			syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		if (sigaction(SIGHUP, &sa, NULL) < 0) {
			syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		if (sigaction(SIGINT, &sa, NULL) < 0) {
			syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		sa.sa_handler = SIG_IGN;
		sa.sa_flags = SA_NOCLDWAIT;

		if (sigaction(SIGCHLD, &sa, NULL) < 0) {
			syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		/* bind socket and listen for incoming connections */
		sock_addr.rfcomm_len = sizeof(sock_addr);
		sock_addr.rfcomm_family = AF_BLUETOOTH;
		memcpy(&sock_addr.rfcomm_bdaddr, &addr,
			sizeof(sock_addr.rfcomm_bdaddr));
		sock_addr.rfcomm_channel = channel;

		if (bind(s, (struct sockaddr *) &sock_addr,
				sizeof(sock_addr)) < 0) {
			syslog(LOG_ERR, "Could not bind socket. %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		if (listen(s, 10) < 0) {
			syslog(LOG_ERR, "Could not listen on socket. %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		ss = sdp_open_local(NULL);
		if (ss == NULL) {
			syslog(LOG_ERR, "Unable to create local SDP session");
			exit(1);
		}

		if (sdp_error(ss) != 0) {
			syslog(LOG_ERR, "Unable to open local SDP session. " \
				"%s (%d)", strerror(sdp_error(ss)),
				sdp_error(ss));
			exit(1);
		}

		memset(&lan, 0, sizeof(lan));
		lan.server_channel = channel;

		if (sdp_register_service(ss,
				SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
				&addr, (void *) &lan, sizeof(lan), NULL) != 0) {
			syslog(LOG_ERR, "Unable to register LAN service with " \
				"local SDP daemon. %s (%d)",
				strerror(sdp_error(ss)), sdp_error(ss));
			exit(1);
		}

		/*
		 * Register DUN (Dial-Up Networking) service on the same
		 * RFCOMM channel if requested. There is really no good reason
		 * to not to support this. AT-command exchange can be faked
		 * with chat script in ppp.conf
		 */

		if (regdun) {
			sdp_dun_profile_t	dun;

			memset(&dun, 0, sizeof(dun));
			dun.server_channel = channel;

			if (sdp_register_service(ss,
					SDP_SERVICE_CLASS_DIALUP_NETWORKING,
					&addr, (void *) &dun, sizeof(dun),
					NULL) != 0) {
				syslog(LOG_ERR, "Unable to register DUN " \
					"service with local SDP daemon. " \
					"%s (%d)", strerror(sdp_error(ss)),
					sdp_error(ss));
				exit(1);
			}
		}

		/*
		 * Register SP (Serial Port) service on the same RFCOMM channel
		 * if requested. It appears that some cell phones are using so
		 * called "callback mechanism". In this scenario user is trying
		 * to connect his cell phone to the Internet, and, user's host
		 * computer is acting as the gateway server. It seems that it
		 * is not possible to tell the phone to just connect and start
		 * using the LAN service. Instead the user's host computer must
		 * "jump start" the phone by connecting to the phone's SP
		 * service. What happens next is the phone kills the existing
		 * connection and opens another connection back to the user's
		 * host computer. The phone really wants to use LAN service,
		 * but for whatever reason it looks for SP service on the
		 * user's host computer. This brain damaged behavior was
		 * reported for Nokia 6600 and Sony/Ericsson P900. Both phones
		 * are Symbian-based phones. Perhaps this is a Symbian problem?
		 */

		if (regsp) {
			sdp_sp_profile_t	sp;

			memset(&sp, 0, sizeof(sp));
			sp.server_channel = channel;

			if (sdp_register_service(ss,
					SDP_SERVICE_CLASS_SERIAL_PORT,
					&addr, (void *) &sp, sizeof(sp),
					NULL) != 0) {
				syslog(LOG_ERR, "Unable to register SP " \
					"service with local SDP daemon. " \
					"%s (%d)", strerror(sdp_error(ss)),
					sdp_error(ss));
				exit(1);
			}
		}
		
		for (done = 0; !done; ) {
			socklen_t	len = sizeof(sock_addr);
			int		s1 = accept(s, (struct sockaddr *) &sock_addr, &len);

			if (s1 < 0) {
				syslog(LOG_ERR, "Could not accept connection " \
					"on socket. %s (%d)", strerror(errno),
					errno);
				exit(1);
			}
				
			pid = fork();
			if (pid == (pid_t) -1) {
				syslog(LOG_ERR, "Could not fork(). %s (%d)",
					strerror(errno), errno);
				exit(1);
			}

			if (pid == 0) {
				sdp_close(ss);
				close(s);

				/* Reset signal handler */
				memset(&sa, 0, sizeof(sa));
				sa.sa_handler = SIG_DFL;

				sigaction(SIGTERM, &sa, NULL);
				sigaction(SIGHUP, &sa, NULL);
				sigaction(SIGINT, &sa, NULL);
				sigaction(SIGCHLD, &sa, NULL);

				/* Become daemon */
				daemon(0, 0);

				/*
				 * XXX Make sure user does not shoot himself
				 * in the foot. Do not pass unit option to the
				 * PPP when operating in the server mode.
				 */

				exec_ppp(s1, NULL, label);
			} else
				close(s1);
		}
	} else {
		sock_addr.rfcomm_len = sizeof(sock_addr);
		sock_addr.rfcomm_family = AF_BLUETOOTH;
		memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY,
			sizeof(sock_addr.rfcomm_bdaddr));
		sock_addr.rfcomm_channel = 0;

		if (bind(s, (struct sockaddr *) &sock_addr,
				sizeof(sock_addr)) < 0) {
			syslog(LOG_ERR, "Could not bind socket. %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		memcpy(&sock_addr.rfcomm_bdaddr, &addr,
			sizeof(sock_addr.rfcomm_bdaddr));
		sock_addr.rfcomm_channel = channel;

		if (connect(s, (struct sockaddr *) &sock_addr,
				sizeof(sock_addr)) < 0) {
			syslog(LOG_ERR, "Could not connect socket. %s (%d)",
				strerror(errno), errno);
			exit(1);
		}

		exec_ppp(s, unit, label);
	}

	exit(0);
} /* main */
Example #4
0
/* Main */
int
main(int argc, char *argv[]) 
{
	struct sigaction	 sa;
	struct sockaddr_rfcomm	 ra;
	bdaddr_t		 addr;
	int			 n, background, channel, service,
				 s, amaster, aslave, fd, doserver,
				 dopty;
	fd_set			 rfd;
	char			*tty = NULL, *ep = NULL, buf[SPPD_BUFFER_SIZE];

	memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));
	background = channel = 0;
	service = SDP_SERVICE_CLASS_SERIAL_PORT;
	doserver = 0;
	dopty = 0;

	/* Parse command line options */
	while ((n = getopt(argc, argv, "a:bc:thS")) != -1) {
		switch (n) { 
		case 'a': /* BDADDR */
			if (!bt_aton(optarg, &addr)) {
				struct hostent	*he = NULL;

				if ((he = bt_gethostbyname(optarg)) == NULL)
					errx(1, "%s: %s", optarg, hstrerror(h_errno));

				memcpy(&addr, he->h_addr, sizeof(addr));
			}
			break;

		case 'c': /* RFCOMM channel */
			channel = strtoul(optarg, &ep, 10);
			if (*ep != '\0') {
				channel = 0;
				switch (tolower(optarg[0])) {
				case 'd': /* DialUp Networking */
					service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
					break;

				case 'f': /* Fax */
					service = SDP_SERVICE_CLASS_FAX;
					break;

				case 'l': /* LAN */
					service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
					break;

				case 's': /* Serial Port */
					service = SDP_SERVICE_CLASS_SERIAL_PORT;
					break;

				default:
					errx(1, "Unknown service name: %s",
						optarg);
					/* NOT REACHED */
				}
			}
			break;

		case 'b': /* Run in background */
			background = 1;
			break;

		case 't': /* Open pseudo TTY */
			dopty = 1;
			break;

		case 'S':
			doserver = 1;
			break;

		case 'h':
		default:
			usage();
			/* NOT REACHED */
		}
	}

	/* Check if we have everything we need */
	if (!doserver && memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)
		usage();
		/* NOT REACHED */

	/* Set signal handlers */
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = sppd_sighandler;

	if (sigaction(SIGTERM, &sa, NULL) < 0)
		err(1, "Could not sigaction(SIGTERM)");
 
	if (sigaction(SIGHUP, &sa, NULL) < 0)
		err(1, "Could not sigaction(SIGHUP)");
 
	if (sigaction(SIGINT, &sa, NULL) < 0)
		err(1, "Could not sigaction(SIGINT)");

	sa.sa_handler = SIG_IGN;
	sa.sa_flags = SA_NOCLDWAIT;

	if (sigaction(SIGCHLD, &sa, NULL) < 0)
		err(1, "Could not sigaction(SIGCHLD)");

	/* Open TTYs */
	if (dopty) {
		if (sppd_ttys_open(&tty, &amaster, &aslave) < 0)
			exit(1);

		fd = amaster;
	} else {
		if (background)
			usage();

		amaster = STDIN_FILENO;
		fd = STDOUT_FILENO;
	}

	/* Open RFCOMM connection */

	if (doserver) {
		struct sockaddr_rfcomm	 ma;
		bdaddr_t		 bt_addr_any;
		sdp_sp_profile_t	 sp;
		void			*ss;
		uint32_t		 sdp_handle;
		int			 acceptsock, aaddrlen;

		acceptsock = socket(PF_BLUETOOTH, SOCK_STREAM,
					BLUETOOTH_PROTO_RFCOMM);
		if (acceptsock < 0)
			err(1, "Could not create socket");

		memcpy(&bt_addr_any, NG_HCI_BDADDR_ANY, sizeof(bt_addr_any));

		memset(&ma, 0, sizeof(ma));
		ma.rfcomm_len = sizeof(ma);
		ma.rfcomm_family = AF_BLUETOOTH;
		memcpy(&ma.rfcomm_bdaddr, &bt_addr_any, sizeof(bt_addr_any));
		ma.rfcomm_channel = channel;

		if (bind(acceptsock, (struct sockaddr *)&ma, sizeof(ma)) < 0)
			err(1, "Could not bind socket on channel %d", channel);
		if (listen(acceptsock, 10) != 0)
			err(1, "Could not listen on socket");

		aaddrlen = sizeof(ma);
		if (getsockname(acceptsock, (struct sockaddr *)&ma, &aaddrlen) < 0)
			err(1, "Could not get socket name");
		channel = ma.rfcomm_channel;

		ss = sdp_open_local(NULL);
		if (ss == NULL)
			errx(1, "Unable to create local SDP session");
		if (sdp_error(ss) != 0)
			errx(1, "Unable to open local SDP session. %s (%d)",
			    strerror(sdp_error(ss)), sdp_error(ss));
		memset(&sp, 0, sizeof(sp));
		sp.server_channel = channel;

		if (sdp_register_service(ss, SDP_SERVICE_CLASS_SERIAL_PORT,
				&bt_addr_any, (void *)&sp, sizeof(sp),
				&sdp_handle) != 0) {
			errx(1, "Unable to register LAN service with "
			    "local SDP daemon. %s (%d)",
			    strerror(sdp_error(ss)), sdp_error(ss));
		}

		s = -1;
		while (s < 0) {
			aaddrlen = sizeof(ra);
			s = accept(acceptsock, (struct sockaddr *)&ra,
			    &aaddrlen);
			if (s < 0)
				err(1, "Unable to accept()");
			if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) &&
			    memcmp(&addr, &ra.rfcomm_bdaddr, sizeof(addr))) {
				warnx("Connect from wrong client");
				close(s);
				s = -1;
			}
		}
		sdp_unregister_service(ss, sdp_handle);
		sdp_close(ss);
		close(acceptsock);
	} else {
		/* Check channel, if was not set then obtain it via SDP */
		if (channel == 0 && service != 0)
			if (rfcomm_channel_lookup(NULL, &addr,
				    service, &channel, &n) != 0)
				errc(1, n, "Could not obtain RFCOMM channel");
		if (channel <= 0 || channel > 30)
			errx(1, "Invalid RFCOMM channel number %d", channel);

		s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
		if (s < 0)
			err(1, "Could not create socket");

		memset(&ra, 0, sizeof(ra));
		ra.rfcomm_len = sizeof(ra);
		ra.rfcomm_family = AF_BLUETOOTH;

		if (bind(s, (struct sockaddr *) &ra, sizeof(ra)) < 0)
			err(1, "Could not bind socket");

		memcpy(&ra.rfcomm_bdaddr, &addr, sizeof(ra.rfcomm_bdaddr));
		ra.rfcomm_channel = channel;

		if (connect(s, (struct sockaddr *) &ra, sizeof(ra)) < 0)
			err(1, "Could not connect socket");
	}

	/* Became daemon if required */
	if (background && daemon(0, 0) < 0)
		err(1, "Could not daemon()");

	openlog(SPPD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON);
	syslog(LOG_INFO, "Starting on %s...", (tty != NULL)? tty : "stdin/stdout");

	/* Print used tty on stdout for wrappers to pick up */
	if (!background)
		fprintf(stdout, "%s\n", tty);

	for (done = 0; !done; ) {
		FD_ZERO(&rfd);
		FD_SET(amaster, &rfd);
		FD_SET(s, &rfd);

		n = select(max(amaster, s) + 1, &rfd, NULL, NULL, NULL);
		if (n < 0) {
			if (errno == EINTR)
				continue;

			syslog(LOG_ERR, "Could not select(). %s",
					strerror(errno));
			exit(1);
		}

		if (n == 0)
			continue;

		if (FD_ISSET(amaster, &rfd)) {
			n = sppd_read(amaster, buf, sizeof(buf));
			if (n < 0) {
				syslog(LOG_ERR, "Could not read master pty, " \
					"fd=%d. %s", amaster, strerror(errno));
				exit(1);
			}

			if (n == 0)
				break; /* XXX */

			if (sppd_write(s, buf, n) < 0) {
				syslog(LOG_ERR, "Could not write to socket, " \
					"fd=%d, size=%d. %s",
					s, n, strerror(errno));
				exit(1);
			}
		}

		if (FD_ISSET(s, &rfd)) {
			n = sppd_read(s, buf, sizeof(buf));
			if (n < 0) {
				syslog(LOG_ERR, "Could not read socket, " \
					"fd=%d. %s", s, strerror(errno));
				exit(1);
			}

			if (n == 0)
				break;

			if (sppd_write(fd, buf, n) < 0) {
				syslog(LOG_ERR, "Could not write to master " \
					"pty, fd=%d, size=%d. %s",
					fd, n, strerror(errno));
				exit(1);
			}
		}
	}

	syslog(LOG_INFO, "Completed on %s", (tty != NULL)? tty : "stdin/stdout");
	closelog();

	close(s);

	if (tty != NULL) {
		close(aslave);
		close(amaster);
	}	

	return (0);
}