Affix in a Nutshell: Affix - Open Source Bluetooth Protocol Stack for Linux | ||
---|---|---|
Prev | Chapter 3. Application Programming Interface | Next |
The Socket interface provides a standard, well-documented approach to access kernel network resources. The Affix brings to the system new protocol family PF_AFFIX and new socket address family "struct sockaddr_affix":
<affix/bluetooth.h> must be included to the source file.
Standard "socket" system call is used to create a socket of PF_AFFIX family:
where type parameter depends on the protocol parameter, which accepts following values:BTPROTO_HCIACL. Creates HCI ACL socket. Valid type: SOCK_SEQPACKET.
BTPROTO_HCISCO. Creates HCI SCO socket. Valid type: SOCK_SEQPACKET.
BTPROTO_L2CAP. Creates L2CAP socket. Valid type: SOCK_STREAM, SOCK_SEQPACKET.
BTPROTO_RFCOMM. Creates RFCOMM socket. Valid type: SOCK_STREAM.
The Socket interface has only one data structure as any protocol family in Unix - cousin of sockaddr. The structure has a name "sockaddr_affix" and has the following prototype:
struct sockaddr_affix { sa_family_t family; BD_ADDR bda; uint16_t port; BD_ADDR local; };All fields except port has the same meaning for all protocols inside PF_AFFIX family. The "port" field has different meaning in for different protocols:
BTPROTO_L2CAP: "port" defines PSM value.
BTPROTO_RFCOMM: "port" defines server channel number.
BTPROTO_HCIACL and BTPROTO_HCISCO: "port" field is unused.
The PF_AFFIX socket family allows to use standard socket functions like connect(), bind(), listen(), accept(), send(), recv() and has additional Bluetooth and Affix specific extension. More details about socket call can be found in the UNIX manual pages.
The PF_AFFIX extension practically is implemented as ioctl() and set(get)sockopt() system calls, but for more convenient it is wrapped into the well-named functions.
Table 3-4. PF_AFFIX extra API
Function | Applicability | Purpose |
---|---|---|
int l2cap_setmtu(int fd, int mtu); | BTPROTO_L2CAP | Sets a maximum packet size that can be received on this socket. This function is used before calling connect() or bind(). |
int l2cap_getmtu(int fd); | BTPROTO_L2CAP | Gets a maximum packet size that can be sent through this socket. |
int hci_getmtu(int fd); | BTPROTO_HCIACL, BTPROTO_HCISCO | Gets a maximum packet size that can be sent through this socket. |
int l2cap_ping(int fd, char *data, int size); | BTPROTO_L2CAP | Sends a *ping* packet and wait for response. |
The RFCOMM socket has additional feature: it can be bound to TTY line. The Affix uses "/dev/btyXX" names for that, where XX is a registered line. Special functions are used to do it:
Table 3-5. RFCOMM TTY API
Function | Purpose |
---|---|
int rfcomm_open_tty(int fd, int line); | Attaches an RFCOMM connection to a TTY line *line*. If the *line* is -1 then it allocates a unused tty line and returns its number. |
int rfcomm_close_tty(int line); | Detaches an RFCOMM connection from a TTY line *line* and close it. |
int rfcomm_set_type(int fd, int type); | Changes the RFCOMM socket type to: RFCOMM_SOCKET (default) or RFCOMM_BTY. This function has to be called right after *socket()*.. |
Practical examples can be found in the Affix source code. Here are examples showing how to use PF_AFFIX sockets on a client and a server sides.
The following example illustrates usage of the Affix socket interface on the client side.
#include <stdio.h> /* Affix includes */ #include <affix/bluetooth.h> int main(int argc, char *argv[]) { struct sockaddr_affix sa; int fd, err; fd = socket(PF_AFFIX, SOCK_SEQPACKET, BTPROTO_L2CAP); if (fd < 0) { perror("socket() failed"); return 1; } sa.family = PF_AFFIX; str2bda(&sa.bda, "00:11:22:33:44:55"); /* connect to that device */ /* or sa.bda = other_bda; */ sa.port = 1; /* connect to that port (PSM) */ sa.local = BDADDR_ANY; /* to connect through certain device use: sa.local = <local device bda> */ err = connect(fd, (struct sockaddr*)&sa, sizeof(sa)); if (err) { perror("connect() failed"); return 2; } /* here is socket is ready for communication any of the standard connection oriented transmission/receiving system calls can be used. - send(), sendmsg(), write() - recv(), recvmsg(), read() */ close(fd); return 0; }The next example illustrates usage of the socket interface on the server side.
#include <stdio.h> /* Affix includes */ #include <affix/bluetooth.h> int main(int argc, char *argv[]) { struct sockaddr_affix sa, csa; int fd, cfd, err; socklen_t csa_len; /* create server socket */ fd = socket(PF_AFFIX, SOCK_SEQPACKET, BTPROTO_L2CAP); if (fd < 0) { perror("socket() failed"); return 1; } sa.family = PF_AFFIX; sa.bda = BDADDR_ANY sa.port = 1; /* accept connection to that port (PSM) */ /* to connect through certain device use: sa.local = <local device bda> */ /* bind socket to address specified by "sa" parameter */ err = bind(fd, (struct sockaddr*)&sa, sizeof(sa)); if (err) { perror("bind() failed"); return 2; } /* start listen for connection - kernel will accept connection requests */ err = listen(fd, 5) if (err) { perror("listen() failed"); return 3; } /* accept new connection and get its connection descriptor "cfd" */ csalen = sizeof(csa); cfd = accept(fd, (struct sockaddr*)&csa, &csa_len); if (cfd < 0) { perror("accept() failed"); return 4; } /* here is socket "cfd" is ready for communication any of the standard connection oriented transmission/receiving system calls can be used. - send(), sendmsg(), write() - recv(), recvmsg(), read() */ close(fd); /* close server socket */ close(cfd); /* close client socket */ return 0; }
All services operate above sockets, or at least connection establishment process is done above it. The Service Level security mode allows service to set its security level. It's done through a special security API.
Table 3-6. Socket security API
Function | Purpose |
---|---|
int setsockopt(int fd, SOL_AFFIX, BTSO_SECURITY, int *level, sizeof(int)); | Sets security level: HCI_SECURITY_OPEN, HCI_SECURITY_AUTH, HCI_SECURITY_ENCRYPT, HCI_SECURITY_AUTHOR. Modes can bitwise-or'd |