tc-hfsc

title: tc-hfsc(7)

summary: Hierarchical Fair Service Curve

text:
# tc-hfsc(7)

## NAME
tc-hfcs - Hierarchical Fair Service Curve

## HISTORY & INTRODUCTION
HFSC (Hierarchical Fair Service Curve) is a network packet scheduling algorithm that was first presented at SIGCOMM'97. Developed as a part of ALTQ (ALTernative Queuing) on NetBSD, found its way quickly to other BSD systems, and then a few years ago became part of the linux kernel. Still, it's not the most popular scheduling algorithm - especially if compared to HTB - and it's not well documented for the enduser. This introduction aims to explain how HFSC works without using too much math (although some math it will be inevitable).

In short HFSC aims to:

1)

guarantee precise bandwidth and delay allocation for all leaf classes (realtime criterion)

2)

allocate excess bandwidth fairly as specified by class hierarchy (linkshare & upperlimit criterion)

3)

minimize any discrepancy between the service curve and the actual amount of service provided during linksharing

The main "selling" point of HFSC is feature (1), which is achieved by using nonlinear service curves (more about what it actually is later). This is particularly useful in VoIP or games, where not only a guarantee of consistent bandwidth is important, but also limiting the initial delay of a data stream. Note that it matters only for leaf classes (where the actual queues are) - thus class hierarchy is ignored in the realtime case.

Feature (2) is well, obvious - any algorithm featuring class hierarchy (such as HTB) strives to achieve that. HFSC does that well, although you might end with unusual situations, if you define service curves carelessly - see section CORNER CASES for examples.

Feature (3) is mentioned due to the nature of the problem. There may be situations where it's either not possible to guarantee service of all curves at the same time, and/or it's impossible to do so fairly. Both will be explained later. Note that this is mainly related to interior (aka aggregate) classes, as the leafs are already handled by (1). Still, it's perfectly possible to create a leaf class without realtime service, and in such a case the caveats will naturally extend to leaf classes as well.

## ABBREVIATIONS
For the remaining part of the document, we'll use following shortcuts:

```
RT - realtime
LS - linkshare
UL - upperlimit
SC - service curve
```

```

```

## BASICS OF HFSC
To understand how HFSC works, we must first introduce a service curve. Overall, it's a nondecreasing function of some time unit, returning the amount of service (an allowed or allocated amount of bandwidth) at some specific point in time. The purpose of it should be subconsciously obvious: if a class was allowed to transfer not less than the amount specified by its service curve, then the service curve is not violated.

Still, we need more elaborate criterion than just the above (although in the most generic case it can be reduced to it). The criterion has to take two things into account:

- idling periods

- the ability to "look back", so if during current active period the service curve is violated, maybe it isn't if we count excess bandwidth received during earlier active period(s)

Let's define the criterion as follows:

(1)

```
For each t1, there must exist t0 in set B, so S(t1-t0) <= w(t0,t1)
```

Here 'w' denotes the amount of service received during some time period between t0 and t1. B is a set of all times, where a session becomes active after idling period (further denoted as 'becoming backlogged'). For a clearer picture, imagine two situations:

a)

our session was active during two periods, with a small time gap between them

b)

as in (a), but with a larger gap

Consider (a): if the service received during both periods meets (1), then all is well. But what if it doesn't do so during the 2nd period? If the amount of service received during the 1st period is larger than the service curve, then it might compensate for smaller service during the 2nd period and the gap - if the gap is small enough.

If the gap is larger (b) - then it's less likely to happen (unless the excess bandwidth allocated during the 1st part was really large). Still, the larger the gap - the less interesting is what happened in the past (e.g. 10 minutes ago) - what matters is the current traffic that just started.

From HFSC's perspective, more interesting is answering the following question: when should we start transferring packets, so a service curve of a class is not violated. Or rephrasing it: How much X() amount of service should a session receive by time t, so the service curve is not violated. Function X() defined as below is the basic building block of HFSC, used in: eligible, deadline, virtual-time and fit-time curves. Of course, X() is based on equation (1) and is defined recursively:

- At the 1st backlogged period beginning function X is initialized to generic service curve assigned to a class

- At any subsequent backlogged period, X() is:

```
min(X() from previous period ; w(t0)+S(t-t0) for t>=t0),
```

... where t0 denotes the beginning of the current backlogged period.

HFSC uses either linear, or two-piece linear service curves. In case of linear or two-piece linear convex functions (first slope < second slope), min() in X's definition reduces to the 2nd argument. But in case of two-piece concave functions, the 1st argument might quickly become lesser for some t>=t0. Note, that for some backlogged period, X() is defined only from that period's beginning. We also define X^(-1)(w) as smallest t>=t0, for which X(t) = w. We have to define it this way, as X() is usually not an injection.

The above generic X() can be one of the following:

E()

In realtime criterion, selects packets eligible for sending. If none are eligible, HFSC will use linkshare criterion. Eligible time 'et' is calculated with reference to packets' heads ( et = E^(-1)(w) ). It's based on RT service curve, but in case of a convex curve, uses its 2nd slope only.

D()

In realtime criterion, selects the most suitable packet from the ones chosen by E(). Deadline time 'dt' corresponds to packets' tails (dt = D^(-1)(w+l), where 'l' is packet's length). Based on RT service curve.

V()

In linkshare criterion, arbitrates which packet to send next. Note that V() is function of a virtual time - see LINKSHARE CRITERION section for details. Virtual time 'vt' corresponds to packets' heads (vt = V^(-1)(w)). Based on LS service curve.

F()

An extension to linkshare criterion, used to limit at which speed linkshare criterion is allowed to dequeue. Fit-time 'ft' corresponds to packets' heads as well (ft = F^(-1)(w)). Based on UL service curve.

Be sure to make clean distinction between session's RT, LS and UL service curves and the above "utility" functions.

## REALTIME CRITERION
RT criterion ignores class hierarchy and guarantees precise bandwidth and delay allocation. We say that a packet is eligible for sending, when the current real time is later than the eligible time of the packet. From all eligible packets, the one most suited for sending is the one with the shortest deadline time. This sounds simple, but consider the following example:

Interface 10Mbit, two classes, both with two-piece linear service curves:

- 1st class - 2Mbit for 100ms, then 7Mbit (convex - 1st slope < 2nd slope)

- 2nd class - 7Mbit for 100ms, then 2Mbit (concave - 1st slope > 2nd slope)

Assume for a moment, that we only use D() for both finding eligible packets, and choosing the most fitting one, thus eligible time would be computed as D^(-1)(w) and deadline time would be computed as D^(-1)(w+l). If the 2nd class starts sending packets 1 second after the 1st class, it's of course impossible to guarantee 14Mbit, as the interface capability is only 10Mbit. The only workaround in this scenario is to allow the 1st class to send the packets earlier that would normally be allowed. That's where separate E() comes to help. Putting all the math aside (see HFSC paper for details), E() for RT concave service curve is just like D(), but for the RT convex service curve - it's constructed using only RT service curve's 2nd slope (in our example

7Mbit).

The effect of such E() - packets will be sent earlier, and at the same time D() will be updated - so the current deadline time calculated from it will be later. Thus, when the 2nd class starts sending packets later, both the 1st and the 2nd class will be eligible, but the 2nd session's deadline time will be smaller and its packets will be sent first. When the 1st class becomes idle at some later point, the 2nd class will be able to "buffer" up again for later active period of the 1st class.

A short remark - in a situation, where the total amount of bandwidth available on the interface is larger than the allocated total realtime parts (imagine a 10 Mbit interface, but 1Mbit/2Mbit and 2Mbit/1Mbit classes), the sole speed of the interface could suffice to guarantee the times.

Important part of RT criterion is that apart from updating its D() and E(), also V() used by LS criterion is updated. Generally the RT criterion is secondary to LS one, and used only if there's a risk of violating precise realtime requirements. Still, the "participation" in bandwidth distributed by LS criterion is there, so V() has to be updated along the way. LS criterion can than properly compensate for non-ideal fair sharing situation, caused by RT scheduling. If you use UL service curve its F() will be updated as well (UL service curve is an extension to LS one - see UPPERLIMIT CRITERION section).

Anyway - careless specification of LS and RT service curves can lead to potentially undesired situations (see CORNER CASES for examples). This wasn't the case in HFSC paper where LS and RT service curves couldn't be specified separately.

## LINKSHARING CRITERION
LS criterion's task is to distribute bandwidth according to specified class hierarchy. Contrary to RT criterion, there're no comparisons between current real time and virtual time - the decision is based solely on direct comparison of virtual times of all active subclasses - the one with the smallest vt wins and gets scheduled. One immediate conclusion from this fact is that absolute values don't matter - only ratios between them (so for example, two children classes with simple linear 1Mbit service curves will get the same treatment from LS criterion's perspective, as if they were 5Mbit). The other conclusion is, that in perfectly fluid system with linear curves, all virtual times across whole class hierarchy would be equal.

Why is VC defined in term of virtual time (and what is it)?

Imagine an example: class A with two children - A1 and A2, both with let's say 10Mbit SCs. If A2 is idle, A1 receives all the bandwidth of A (and update its V() in the process). When A2 becomes active, A1's virtual time is already far later than A2's one. Considering the type of decision made by LS criterion, A1 would become idle for a long time. We can workaround this situation by adjusting virtual time of the class becoming active - we do that by getting such time "up to date". HFSC uses a mean of the smallest and the biggest virtual time of currently active children fit for sending. As it's not real time anymore (excluding trivial case of situation where all classes become active at the same time, and never become idle), it's called virtual time.

Such approach has its price though. The problem is analogous to what was presented in previous section and is caused by non-linearity of service curves:

1)

either it's impossible to guarantee service curves and satisfy fairness during certain time periods:

Recall the example from RT section, slightly modified (with 3Mbit slopes instead of 2Mbit ones):

- 1st class - 3Mbit for 100ms, then 7Mbit (convex - 1st slope < 2nd slope)

- 2nd class - 7Mbit for 100ms, then 3Mbit (concave - 1st slope > 2nd slope)

They sum up nicely to 10Mbit - the interface's capacity. But if we wanted to only use LS for guarantees and fairness - it simply won't work. In LS context, only V() is used for making decision which class to schedule. If the 2nd class becomes active when the 1st one is in its second slope, the fairness will be preserved - ratio will be 1:1 (7Mbit:7Mbit), but LS itself is of course unable to guarantee the absolute values themselves - as it would have to go beyond of what the interface is capable of.

2)

and/or it's impossible to guarantee service curves of all classes at the same time [fairly or not]:

This is similar to the above case, but a bit more subtle. We will consider two subtrees, arbitrated by their common (root here) parent:

```
R (root) - 10Mbit
A  - 7Mbit, then 3Mbit
A1 - 5Mbit, then 2Mbit
A2 - 2Mbit, then 1Mbit
B  - 3Mbit, then 7Mbit
```

R arbitrates between left subtree (A) and right (B). Assume that A2 and B are constantly backlogged, and at some later point A1 becomes backlogged (when all other classes are in their 2nd linear part).

What happens now? B (choice made by R) will always get 7 Mbit as R is only (obviously) concerned with the ratio between its direct children. Thus A subtree gets 3Mbit, but its children would want (at the point when A1 became backlogged) 5Mbit + 1Mbit. That's of course impossible, as they can only get 3Mbit due to interface limitation.

In the left subtree - we have the same situation as previously (fair split between A1 and A2, but violated guarantees), but in the whole tree - there's no fairness (B got 7Mbit, but A1 and A2 have to fit together in 3Mbit) and there's no guarantees for all classes (only B got what it wanted). Even if we violated fairness in the A subtree and set A2's service curve to 0, A1 would still not get the required bandwidth.

## UPPERLIMIT CRITERION
UL criterion is an extensions to LS one, that permits sending packets only if current real time is later than fit-time ('ft'). So the modified LS criterion becomes: choose the smallest virtual time from all active children, such that fit-time < current real time also holds. Fit-time is calculated from F(), which is based on UL service curve. As you can see, its role is kinda similar to E() used in RT criterion. Also, for obvious reasons - you can't specify UL service curve without LS one.

The main purpose of the UL service curve is to limit HFSC to bandwidth available on the upstream router (think adsl home modem/router, and linux server as NAT/firewall/etc. with 100Mbit+ connection to mentioned modem/router). Typically, it's used to create a single class directly under root, setting a linear UL service curve to available bandwidth - and then creating your class structure from that class downwards. Of course, you're free to add a UL service curve (linear or not) to any class with LS criterion.

An important part about the UL service curve is that whenever at some point in time a class doesn't qualify for linksharing due to its fit-time, the next time it does qualify it will update its virtual time to the smallest virtual time of all active children fit for linksharing. This way, one of the main things the LS criterion tries to achieve - equality of all virtual times across whole hierarchy - is preserved (in perfectly fluid system with only linear curves, all virtual times would be equal).

Without that, 'vt' would lag behind other virtual times, and could cause problems. Consider an interface with a capacity of 10Mbit, and the following leaf classes (just in case you're skipping this text quickly - this example shows behavior that doesn't happen):

```
A - ls 5.0Mbit
B - ls 2.5Mbit
C - ls 2.5Mbit, ul 2.5Mbit
```

If B was idle, while A and C were constantly backlogged, A and C would normally (as far as LS criterion is concerned) divide bandwidth in 2:1 ratio. But due to UL service curve in place, C would get at most 2.5Mbit, and A would get the remaining 7.5Mbit. The longer the backlogged period, the more the virtual times of A and C would drift apart. If B became backlogged at some later point in time, its virtual time would be set to (A's vt + C's vt)/2, thus blocking A from sending any traffic until B's virtual time catches up with A.

## SEPARATE LS / RT SCs
Another difference from the original HFSC paper is that RT and LS SCs can be specified separately. Moreover, leaf classes are allowed to have only either RT SC or LS SC. For interior classes, only LS SCs make sense: any RT SC will be ignored.

## CORNER CASES
Separate service curves for LS and RT criteria can lead to certain traps that come from "fighting" between ideal linksharing and enforced realtime guarantees. Those situations didn't exist in original HFSC paper, where specifying separate LS / RT service curves was not discussed.

Consider an interface with a 10Mbit capacity, with the following leaf classes:

```
A - ls 5.0Mbit, rt 8Mbit
B - ls 2.5Mbit
C - ls 2.5Mbit
```

Imagine A and C are constantly backlogged. As B is idle, A and C would divide bandwidth in 2:1 ratio, considering LS service curve (so in theory - 6.66 and 3.33). Alas RT criterion takes priority, so A will get 8Mbit and LS will be able to compensate class C for only 2 Mbit - this will cause discrepancy between virtual times of A and C.

Assume this situation lasts for a long time with no idle periods, and suddenly B becomes active. B's virtual time will be updated to (A's vt + C's vt)/2, effectively landing in the middle between A's and C's virtual time. The effect - B, having no RT guarantees, will be punished and will not be allowed to transfer until C's virtual time catches up.

If the interface had a higher capacity, for example 100Mbit, this example would behave perfectly fine though.

Let's look a bit closer at the above example - it "cleverly" invalidates one of the basic things LS criterion tries to achieve - equality of all virtual times across class hierarchy. Leaf classes without RT service curves are literally left to their own fate (governed by messed up virtual times).

Also, it doesn't make much sense. Class A will always be guaranteed up to 8Mbit, and this is more than any absolute bandwidth that could happen from its LS criterion (excluding trivial case of only A being active). If the bandwidth taken by A is smaller than absolute value from LS criterion, the unused part will be automatically assigned to other active classes (as A has idling periods in such case). The only "advantage" is, that even in case of low bandwidth on average, bursts would be handled at the speed defined by RT criterion. Still, if extra speed is needed (e.g. due to latency), non linear service curves should be used in such case.

In the other words: the LS criterion is meaningless in the above example.

You can quickly "workaround" it by making sure each leaf class has RT service curve assigned (thus guaranteeing all of them will get some bandwidth), but it doesn't make it any more valid.

Keep in mind - if you use nonlinear curves and irregularities explained above happen only in the first segment, then there's little wrong with "overusing" RT curve a bit:

```
A - ls 5.0Mbit, rt 9Mbit/30ms, then 1Mbit
B - ls 2.5Mbit
C - ls 2.5Mbit
```

Here, the vt of A will "spike" in the initial period, but then A will never get more than 1Mbit until B & C catch up. Then everything will be back to normal.

## LINUX AND TIMER RESOLUTION
In certain situations, the scheduler can throttle itself and setup so called watchdog to wakeup dequeue function at some time later. In case of HFSC it happens when for example no packet is eligible for scheduling, and UL service curve is used to limit the speed at which LS criterion is allowed to dequeue packets. It's called throttling, and accuracy of it is dependent on how the kernel is compiled.

There're 3 important options in modern kernels, as far as timers' resolution goes: 'tickless system', 'high resolution timer support' and 'timer frequency'.

If you have 'tickless system' enabled, then the timer interrupt will trigger as slowly as possible, but each time a scheduler throttles itself (or any other part of the kernel needs better accuracy), the rate will be increased as needed / possible. The ceiling is either 'timer frequency' if 'high resolution timer support' is not available or not compiled in, or it's hardware dependent and can go far beyond the highest 'timer frequency' setting available.

If 'tickless system' is not enabled, the timer will trigger at a fixed rate specified by 'timer frequency' - regardless if high resolution timers are or aren't available.

This is important to keep those settings in mind, as in scenario like: no tickless, no HR timers, frequency set to 100hz - throttling accuracy would be at 10ms. It doesn't automatically mean you would be limited to ~0.8Mbit/s (assuming packets at ~1KB) - as long as your queues are prepared to cover for timer inaccuracy. Of course, in case of e.g. locally generated UDP traffic - appropriate socket size is needed as well. Short example to make it more understandable (assume hardcore anti-schedule settings - HZ=100, no HR timers, no tickless):

```
tc qdisc add dev eth0 root handle 1:0 hfsc default 1
tc class add dev eth0 parent 1:0 classid 1:1 hfsc rt m2 10Mbit
```

Assuming packet of ~1KB size and HZ=100, that averages to ~0.8Mbit - anything beyond it (e.g. the above example with specified rate over 10x larger) will require appropriate queuing and cause bursts every ~10 ms. As you can imagine, any HFSC's RT guarantees will be seriously invalidated by that. Aforementioned example is mainly important if you deal with old hardware - as is particularly popular for home server chores. Even then, you can easily set HZ=1000 and have very accurate scheduling for typical adsl speeds.

Anything modern (apic or even hpet msi based timers + 'tickless system') will provide enough accuracy for superb 1Gbit scheduling. For example, on one of my cheap dual-core AMD boards I have the following settings:

```
tc qdisc add dev eth0 parent root handle 1:0 hfsc default 1
tc class add dev eth0 parent 1:0 classid 1:1 hfsc rt m2 300mbit
```

And a simple:

```
nc -u dst.host.com 54321 </dev/zero
nc -l -p 54321 >/dev/null
```

...will yield the following effects over a period of ~10 seconds (taken from /proc/interrupts):

```
319: 42124229   0  HPET_MSI-edge  hpet2 (before)
319: 42436214   0  HPET_MSI-edge  hpet2 (after 10s.)
```

That's roughly 31000/s. Now compare it with HZ=1000 setting. The obvious drawback of it is that cpu load can be rather high with servicing that many timer interrupts. The example with 300Mbit RT service curve on 1Gbit link is particularly ugly, as it requires a lot of throttling with minuscule delays.

Also note that it's just an example showing the capabilities of current hardware. The above example (essentially a 300Mbit TBF emulator) is pointless on an internal interface to begin with: you will pretty much always want a regular LS service curve there, and in such a scenario HFSC simply doesn't throttle at all.

300Mbit RT service curve (selected columns from mpstat -P ALL 1):

```
10:56:43 PM  CPU  %sys     %irq   %soft   %idle
10:56:44 PM  all  20.10    6.53   34.67   37.19
10:56:44 PM    0  35.00    0.00   63.00    0.00
10:56:44 PM    1   4.95   12.87    6.93   73.27
```

So, in the rare case you need those speeds with only a RT service curve, or with a UL service curve: remember the drawbacks.

## CAVEAT: RANDOM ONLINE EXAMPLES
For reasons unknown (though well guessed), many examples you can google love to overuse UL criterion and stuff it in every node possible. This makes no sense and works against what HFSC tries to do (and does pretty damn well). Use UL where it makes sense: on the uppermost node to match upstream router's uplink capacity. Or in special cases, such as testing (limit certain subtree to some speed), or customers that must never get more than certain speed. In the last case you can usually achieve the same by just using a RT criterion without LS+UL on leaf nodes.

As for the router case - remember it's good to differentiate between "traffic to router" (remote console, web config, etc.) and "outgoing traffic", so for example:

```
tc qdisc add dev eth0 root handle 1:0 hfsc default 0x8002
tc class add dev eth0 parent 1:0 classid 1:999 hfsc rt m2 50Mbit
tc class add dev eth0 parent 1:0 classid 1:1 hfsc ls m2 2Mbit ul m2 2Mbit
```

... so "internet" tree under 1:1 and "router itself" as 1:999

## LAYER2 ADAPTATION
Please refer to tc-stab(8)

## SEE ALSO
tc(8), tc-hfsc(8), tc-stab(8)

Please direct bugreports and patches to: <netdev@vger.kernel.org>

## AUTHOR
Manpage created by Michal Soltys (soltys@ziu.info)


irda

package: irda-utils

title: irda(7)

summary: The Linux-IrDA protocol stack

text:
# irda(7)

## NAME
irda - The Linux-IrDA protocol stack

## SYNOPSIS
\#include <linux/irda.h>

stream_s = socket(PF_INET, SOCK_STREAM, 0);

seqpkt_s = socket(PF_INET, SOCK_SEQPACKET, 0);

dgram_s = socket(PF_INET, SOCK_DGRAM, IRDAPROTO_UNITDATA);

ultra_s = socket(PF_INET, SOCK_DGRAM, IRDAPROTO_ULTRA);

## DESCRIPTION
Linux-IrDA is a complete implementation of the various IrDA protocols and IrDA drivers for Linux.

The configuration of the low level of the IrDA stack (IrDA ports) and the various IrDA drivers are described in irattach(8).

The usage of the higher layers of the IrDA stack (IrCOMM, IrLPT, IrNET, IrLAN, OBEX...) are described in their respective man pages.

The core of the Linux-IrDA protocol stack is composed of the IrLAP, IrLMP, IrTTP and IrIAS protocols and is implemented as a kernel module. The programmer's interface for the IrDA stack is socket based. For more information on sockets, see socket(7).

Note that higher level IrDA protocols may offer a different programmer's interface. For example IrCOMM offers a TTY based interface and OBEX is available through a user space library.

## SOCKETS TYPE
The Linux-IrDA socket interface offers 4 types of sockets:

Stream socket - SOCK_STREAM, 0

Stream sockets provides a reliable, stream oriented, full duplex connection between two sockets on top of IrTTP, similar to TCP sockets. IrTTP guarantees that the data arrives in order and manages flow contol, IrLAP retransmits lost packets.

Stream sockets does not preserve record boundaries.

SeqPacket socket - SOCK_SEQPACKET, 0

SeqPacket sockets provides a reliable, datagram oriented, full duplex connection between two sockets on top of IrTTP. IrTTP guarantees that the data arrives in order and manages flow contol, IrLAP retransmits lost packets.

SeqPacket sockets preserve record boundaries. Large datagrams will be fragmented as needed.

Datagram socket - SOCK_DGRAM, IRDAPROTO_UNITDATA

SeqPacket sockets provides a reliable, datagram oriented, full duplex connection between two sockets on top of IrLMP. There is no guarantees that the data arrives in order and there is no flow contol, however IrLAP retransmits lost packets.

Datagram sockets preserve record boundaries. No fragmentation is provided, datagrams larger than the IrDA link MTU are truncated or discarded.

Ultra socket - SOCK_DGRAM, IRDAPROTO_ULTRA

Ultra sockets provides a connectionless, unreliable datagram packet service on top of IrLAP-Ultra. Ultra datagrams are sent and receive only when no IrLAP connection is established and otherwise discarded. They are always transmitted at 9600 bauds. Datagrams may be lost, reordered, and there is no flow control.

Ultra sockets preserve record boundaries. No fragmentation is provided, datagrams larger than the Ultra MTU (382 bytes) are truncated or discarded.

## ADDRESS FORMAT
An IrDA socket address is defined as a combination of an IrDA interface address and a service name. Service names are automatically resolved to lsap through the IrIAP protocol.

```
    struct sockaddr_irda {

        sa_family_t sir_family;   /* AF_IRDA */

        __u8        sir_lsap_sel; /* LSAP selector */

        __u32       sir_addr;     /* Device address */

        char        sir_name[25]; /* Usually <service>:IrDA:TinyTP */

    };
```

sin_family is always set to AF_IRDA. sir_lsap_sel is usually not used. sir_addr is the address of the peer and optional (and that case the first peer discoverd will be used). sir_name is the service name of the socket.

## SOCKET OPTIONS
IrDA sockets supports some protocol specific socket options that can be set with setsockopt(2) and read with getsockopt(2). The socket option level for IrDA is SOL_IRLMP.

Options that can be set:

IRLMP_IAS_SET

Set an entry in the local IAS database.

IRLMP_IAS_DEL

Delete an entry from the local IAS database.

IRLMP_MAX_SDU_SIZE

Set maximum receive MTU for SeqPacket sockets.

IRLMP_HINTS_SET

Set IrDA hint bits to be advertised to peers.

IRLMP_HINT_MASK_SET

Set IrDA hint bits filter to be used when performing discovery.

Options that can be get:

IRLMP_ENUMDEVICES

Perform link level discovery and return the content of the discovery log.

IRLMP_MAX_SDU_SIZE

Get maximum receive MTU.

IRLMP_IAS_GET

Get an entry from the local IAS database.

IRLMP_IAS_QUERY

Query an entry in IAS database of a peer using IrIAP.

IRLMP_WAITDEVICE

Block until a new device is discovered. Experimental feature, use with caution.

## AUTHOR
Jean Tourrilhes - jt@hpl.hp.com

## SEE ALSO
irattach(8), irdadump(8), irnet(4), irnetd(8).


package: jurand

title: java_remove_annotations(7)

text:
# java_remove_annotations(7)

## NAME
java_remove_annotations - remove imports and annotations from Java source files

## SYNOPSIS
%java_remove_annotations [optional flags] <matcher>... [file path]...

## DESCRIPTION
This macro removes import statements as well as usage of annotations from Java source files. This does the same as java_remove_imports and on top of that finds all uses of annotations and matches the content between the '@' symbol and either ending with whitespace or with an opening parethesis '(' (the annotation arguments).

In case of match, the script also removes the block of paretheses that follows the matched annotation, if it is present.

File path arguments are handled the following way:

•Symlinks are ignored.

•Regular files are handled regardless of the file name.

•Directories are traversed recursively and all .java files are handled.

Arguments can be specified in arbitrary order.

Matcher is one of:

-n <name>

Simple class name to be matched against the simple names of imported symbols. Names are matched for exact equality. Can be specified multiple times.

-p <pattern>

Regex patterns to be matched against imported symbols. Each imported symbol found in the code is matched against each pattern. Can be specified multiple times.

Optional flags:

-s, --strict

Fail if any of the user provided arguments were redundant.

## EXAMPLES
Example of usage in a .spec file:

%java_remove_annotations src -n Nullable

Examples of patterns:

•Annotations present in Java source file:

```
1) @SuppressWarnings
2) @SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
3) @org.junit.Test
4) @org.junit.jupiter.api.Test
```

•Names used to match:

```
Name 'SuppressWarnings' matches 1)
Name 'Test' matches 3), 4).
```

```
Name 'junit' does not match anything.
```

•Patterns used to match:

```
Pattern 'SuppressWarnings' matches 1).
Pattern 'Suppress' matches 1), 2).
Pattern 'org[.]junit[.]Test' matches 3).
Pattern 'junit' matches 3), 4).
```

```
Pattern '@SuppressWarnings' does not match anything.
Pattern 'EI_EXPOSE_REP' does not match anything.
```

## REPORTING BUGS
Bugs should be reported through the issue tracker at GitHub: <https://github.com/fedora-java/jurand/issues>.

## AUTHOR
Written by Marián Konček.

## SEE ALSO
java_remove_imports(7).


title: java_remove_imports(7)

text:
# java_remove_imports(7)

## NAME
java_remove_imports - remove import statements from Java source files

## SYNOPSIS
%java_remove_imports [optional flags] <matcher>... [file path]...

## DESCRIPTION
This macro removes import statements from Java source files. The script matches all non-whitespace content following the 'import [static]' statement against all patterns provided via the -p flag and all simple class names against names provided by the -n flag.

File path arguments are handled the following way:

•Symlinks are ignored.

•Regular files are handled regardless of the file name.

•Directories are traversed recursively and all .java files are handled.

Arguments can be specified in arbitrary order.

Matcher is one of:

-n <name>

Simple class name to be matched against the simple names of imported symbols. Names are matched for exact equality. Can be specified multiple times.

-p <pattern>

Regex patterns to be matched against imported symbols. Each imported symbol found in the code is matched against each pattern. Can be specified multiple times.

Optional flags:

-s, --strict

Fail if any of the user provided arguments were redundant.

## EXAMPLES
Example of usage in a .spec file:

%java_remove_imports src -n Nullable

Examples of patterns:

•Import statements present in Java source file:

```
1) import java.lang.Runnable;
2) import java.util.List;
3) import static java.util.*;
4) import static java.lang.String.valueOf;
5) import com.google.common.util.concurrent.Service;
```

•Names used to match:

```
Name 'Runnable' matches 1)
Name 'String' matches 4)
```

```
Name 'util' does not match anything.
Name '*' does not match anything.
Name 'valueOf' does not match anything.
```

•Patterns used to match:

```
Pattern 'Runnable' matches 1).
Pattern '[*]' matches 3).
Pattern 'java[.]util' matches 2), 3).
Pattern 'util' matches 2), 3), 5).
Patterns 'java', 'java.*' match 1) - 4).
```

```
Pattern 'static' does not match anything.
```

## REPORTING BUGS
Bugs should be reported through the issue tracker at GitHub: <https://github.com/fedora-java/jurand/issues>.

## AUTHOR
Written by Marián Konček.

## SEE ALSO
java_remove_annotations(7).


asymmetric-key

package: keyutils

title: asymmetric-key(7)

text:
# asymmetric-key(7)

## NAME
asymmetric - Kernel key type for holding asymmetric keys

## OVERVIEW
A kernel key of asymmetric type acts as a handle to an asymmetric key as used for public-key cryptography. The key material itself may be held inside the kernel or it may be held in hardware with operations being offloaded. This prevents direct user access to the cryptographic material.

Keys may be any asymmetric type (RSA, ECDSA, ...) and may have both private and public components present or just the public component.

Asymmetric keys can be made use of by both the kernel and userspace. The kernel can make use of them for module signature verification and kexec image verification for example. Userspace is provided with a set of keyctl(KEYCTL_PKEY_*) calls for querying and using the key. These are wrapped by libkeyutils as functions named keyctl_pkey_*().

An asymmetric-type key can be loaded by the keyctl utility using a command line like:

```
openssl x509 -in key.x509 -outform DER |
keyctl padd asymmetric foo @s
```

## DESCRIPTION
The asymmetric-type key can be viewed as a container that comprises of a number of components:

Parsers

The asymmetric key parsers attempt to identify the content of the payload blob and extract useful data from it with which to instantiate the key. The parser is only used when adding, instantiating or updating a key and isn't thereafter associated with the key.

Available parsers include ones that can deal with DER-encoded X.509, DER-encoded PKCS#8 and DER-encoded TPM-wrapped blobs.

Public and private keys

These are the cryptographic components of the key pair. The public half should always be available, but the private half might not be. What operations are available can be queried, as can the size of the key. The key material may or may not actually reside in the kernel.

Identifiers

In addition to the normal key description (which can be generated by the parser), a number of supplementary identifiers may be available that can be searched for. These may be obtained, for example, by hashing the public key material or from the subjectKeyIdentifier in an X.509 certificate.

Identifier-based searches are selected by passing as the description to keyctl_search() a string constructed of hex characters prefixed with either "id:" or "ex:". The "id:" prefix indicates that a partial tail match is permissible whereas "ex:" requires an exact match on the full string. The hex characters indicate the data to match.

Subtype

This is the driver inside the kernel that accesses the key material and performs operations on it. It might be entirely software-based or it may offload the operations to a hardware key store, such as a TPM.

Note that expiry times from the payload are ignored as these patches may be used during boot before the system clock is set.

## PARSERS
The asymmetric key parsers can handle keys in a number of forms:

X.509

DER-encoded X.509 certificates can be accepted. Two identifiers are constructed: one from from the certificate issuer and serial number and the other from the subjectKeyIdentifier, if present. If left blank, the key description will be filled in from the subject field plus either the subjectKeyIdentifier or the serialNumber. Only the public key is filled in and only the encrypt and verify operations are supported.

The signature on the X.509 certificate may be checked by the keyring it is being added to and it may also be rejected if the key is blacklisted.

PKCS#8

Unencrypted DER-encoded PKCS#8 key data containers can be accepted. Currently no identifiers are constructed. The private key and the public key are loaded from the PKCS#8 blobs. Encrypted PKCS#8 is not currently supported.

TPM-Wrapped keys

DER-encoded TPM-wrapped TSS key blobs can be accepted. Currently no identifiers are constructed. The public key is extracted from the blob but the private key is expected to be resident in the TPM. Encryption and signature verification is done in software, but decryption and signing are offloaded to the TPM so as not to expose the private key.

This parser only supports TPM-1.2 wrappings and enc=pkcs1 encoding type. It also uses a hard-coded null SRK password; password-protected SRKs are not yet supported.

## USERSPACE API
In addition to the standard keyutils library functions, such as keyctl_update(), there are five calls specific to the asymmetric key type (though they are open to being used by other key types also):

keyctl_pkey_query()

keyctl_pkey_encrypt()

keyctl_pkey_decrypt()

keyctl_pkey_sign()

keyctl_pkey_verify()

The query function can be used to retrieve information about an asymmetric key, such as the key size, the amount of space required by buffers for the other operations and which operations are actually supported.

The other operations form two pairs: encrypt/decrypt and create/verify signature. Not all of these operations will necessarily be available; typically, encrypt and verify only require the public key to be available whereas decrypt and sign require the private key as well.

All of these operations take an information string parameter that supplies additional information such as encoding type/form and the password(s) needed to unlock/unwrap the key. This takes the form of a comma-separated list of "key[=value]" pairs, the exact set of which depends on the subtype driver used by a particular key.

Available parameters include:

enc=<type>

The encoding type for use in an encrypted blob or a signature. An example might be "enc=pkcs1".

hash=<name>

The name of the hash algorithm that was used to digest the data to be signed. Note that this is only used to construct any encoding that is used in a signature. The data to be signed or verified must have been parsed by the caller and the hash passed to keyctl_pkey_sign() or keyctl_pkey_verify() beforehand. An example might be "hash=sha256".

Note that not all parameters are used by all subtypes.

## RESTRICTED KEYRINGS
An additional keyutils function, keyctl_restrict_keyring(), can be used to gate a keyring so that a new key can only be added to the affected keyring if (a) it's an asymmetric key, (b) it's validly signed by a key in some appropriate keyring and (c) it's not blacklisted.

```
 keyctl_restrict_keyring(keyring, "asymmetric",

                         "key_or_keyring:<signing-key>[:chain]");
```

Where <signing-key> is the ID of a key or a ring of keys that act as the authority to permit a new key to be added to the keyring. The chain flag indicates that keys that have been added to the keyring may also be used to verify new keys. Authorising keys must themselves be asymmetric-type keys that can be used to do a signature verification on the key being added.

Note that there are various system keyrings visible to the root user that may permit additional keys to be added. These are typically gated by keys that already exist, preventing unauthorised keys from being used for such things as module verification.

## BLACKLISTING
When the attempt is made to add a key to the kernel, a hash of the public key is checked against the blacklist. This is a system keyring named .blacklist and contains keys of type blacklist. If the blacklist contains a key whose description matches the hash of the new key, that new key will be rejected with error EKEYREJECTED.

The blacklist keyring may be loaded from multiple sources, including a list compiled into the kernel and the UEFI dbx variable. Further hashes may also be blacklisted by the administrator. Note that blacklisting is not retroactive, so an asymmetric key that is already on the system cannot be blacklisted by adding a matching blacklist entry later.

## VERSIONS
The asymmetric key type first appeared in v3.7 of the Linux kernel, the restriction function in v4.11 and the public key operations in v4.20.

## SEE ALSO
keyctl(1), add_key(2), keyctl(3), keyctl_pkey_encrypt(3), keyctl_pkey_query(3), keyctl_pkey_sign(3), keyrings(7), keyutils(7)


keyutils

title: keyutils(7)

summary: in-kernel key management utilities

text:
# keyutils(7)

## NAME
keyutils - in-kernel key management utilities

## DESCRIPTION
The keyutils package is a library and a set of utilities for accessing the kernel keyrings facility.

A header file is supplied to provide the definitions and declarations required to access the library:

\#include <keyutils.h>

To link with the library, the following:

-lkeyutils

should be specified to the linker.

Three system calls are provided:

add_key(2)

Supply a new key to the kernel.

request_key(2)

Find an existing key for use, or, optionally, create one if one does not exist.

keyctl(2)

Control a key in various ways. The library provides a variety of wrappers around this system call and those should be used rather than calling it directly.

See the add_key(2), request_key(2), and keyctl(2) manual pages for more information.

The keyctl() wrappers are listed on the keyctl(3) manual page.

## UTILITIES
A program is provided to interact with the kernel facility by a number of subcommands, e.g.:

keyctl add user foo bar @s

See the keyctl(1) manual page for information on that.

The kernel has the ability to upcall to userspace to fabricate new keys. This can be triggered by request_key(), but userspace is better off using add_key() instead if it possibly can.

The upcalling mechanism is usually routed via the request-key(8) program. What this does with any particular key is configurable in:

/etc/request-key.conf

/etc/request-key.d/

See the request-key.conf(5) and the request-key(8) manual pages for more information.

## SEE ALSO
keyctl(1), keyctl(3), keyrings(7), persistent-keyring(7), process-keyring(7), session-keyring(7), thread-keyring(7), user-keyring(7), user-session-keyring(7), pam_keyinit(8)


tls-session-tags

package: ktls-utils

title: tls-session-tags(7)

summary: TLS session tags

text:
# tls-session-tags(7)

## NAME
tls-session-tags - TLS session tags

## SYNOPSIS
/etc/tlshd/tags.d/

## DESCRIPTION
The tlshd program implements a user agent that services TLS handshake requests on behalf of kernel TLS consumers. Its configuration files, found under the /etc/tlshd directory, contain information that the tlshd program reads when it starts up. The configuration files direct the tlshd program to information about which trust store and signing and encryption algorithms are to be used. The configuration files are considered a trusted source of information.

When a peer presents an X.509 certificate during a TLS handshake, the tlshd program is responsible for verifying that the certificate was issued by a certificate authority that the receiver recognizes and trusts. Once that verification is successful, the receiver can trust the content of that certificate, including information about the peer identity presented in that certificate (e.g., a DNS hostname or IP address, and so on).

Once a peer's certificate is trusted, the tlshd program can be configured to scan the fields in the peer's certificate. Based on the scan, the tlshd program can assign tags to the new TLS session that indicate that the server recognizes the peer's identity. For example, the tlshd program can be configured to look for a specific string in subject fields, and assign tags to TLS sessions where the peer presented a certificate with matching content in that field. Kernel consumers can use those tags to authorize or deny access to resources based on the identity presented in peer certificates.

The following sections describe how to configure this facility.

## FORMAT
TLS session tag definitions are YAML documents stored in files in the /etc/tlshd/tags.d directory. When it launches, the tlshd program reads all files in that directory with either the .yml or .yaml extension. Modifications to the content of these files take effect only when the tlshd program is restarted.

The tlshd program populates two dictionaries from the contents of these files:

filters

Each filter defined in this dictionary specifies the name of a field in an X.509 certificate, and the conditions under which the contents of that field are to be considered a match.

tags

Each tag is a list of one or more filters (defined in the filters dictionary) that all must be matched in order for the tag to be assigned to a new TLS session.

### Filter types
A filter's type determines the part of the incoming authentication material that the tlshd program examines to determine if there is a match. For example, for the x509.tbs.subject filter type, a string argument specifies a simple wildcard pattern that is matched against an incoming X.509 certificate's subject field. A complete list of filter types appears in the FILTER TYPE REFERENCE section below.

## FILTER TYPE REFERENCE
The tlshd program currently implements the following filter types:

x509.cert.signatureAlgorithm

Filters of this type examine an incoming X.509 certificate's signatureAlgorithm field, as defined in RFC 5280, Section 4.1.1.2. The filter takes an additional string wildcard pattern that can be an algorithm name or an algorithm OID.

x509.tbs.version

Filters of this type examine an incoming X.509 certificate's version field, part of the To-Be-Signed section of the certificate, as defined in RFC 5280, Section 4.1.2.1. The filter takes an additional numeric value that is matched against the certificate's version.

x509.tbs.serialNumber

Filters of this type examine an incoming X.509 certificate's serialNumber field, part of the To-Be-Signed section of the certificate, as defined in RFC 5280, Section 4.1.2.2. The filter takes an additional string wildcard pattern that matches a hexadecimal number.

x509.tbs.issuer

Filters of this type examine an incoming X.509 certificate's issuer field, part of the To-Be-Signed section of the certificate, as defined in RFC 5280, Section 4.1.2.4. The filter takes an additional string wildcard pattern that matches the distinguished name part of the certificate's issuer field.

x509.tbs.validity.notBefore

Filters of this type examine an incoming X.509 certificate's activation time field, part of the To-Be-Signed section of the certificate, as defined in RFC 5280, Section 4.1.2.5. The filter takes a date and time string. The filter matches when the certificate's activation time is equal to or later than the specified threshold. Use this filter to accept only certificates issued on or after a particular date.

x509.tbs.validity.notAfter

Filters of this type examine an incoming X.509 certificate's expiration time field, part of the To-Be-Signed section of the certificate, as defined in RFC 5280, Section 4.1.2.5. The filter takes a date and time string. The filter matches when the certificate's expiration time is equal to or earlier than the specified threshold. Use this filter to accept only certificates that expire on or before a particular date.

x509.tbs.subject

Filters of this type examine an incoming X.509 certificate's subject field, part of the To-Be-Signed section of the certificate, as defined in RFC 5280, Section 4.1.2.6. The filter takes an additional string wildcard pattern that matches the distinguished name part of the certificate's subject field.

x509.extension.keyUsage

Filters of this type examine an incoming X.509 certificate's keyUsage field, one of the standard certificate extensions. The filter takes a list of bit names that must be set in the field in order for the filter to match. This list contains zero or more of the following bit names: digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign, encipherOnly, or decipherOnly.

x509.extension.extendedKeyUsage

Filters of this type examine an incoming X.509 certificate's extendedKeyUsage field, one of the standard certificate extensions. This filter type is not yet implemented.

x509.derived.fingerprint

Filters of this type locally compute an incoming X.509 certificate's SHA1 and SHA256 fingerprint. The filter takes an additional string wildcard pattern that matches the hexadecimal value of either the derived SHA1 or derived SHA256 fingerprint.

x509.derived.selfSigned

Filters of this type match when an incoming X.509 certificate's issuer and subject distinguished names are exactly equal.

### Filters
The definition of each filter is YAML mapping that specifies the unique name of the filter, its filter type, and zero or more specific match arguments to be used. For example:

```
filters:

  ...

  monsters-university:

    type: "x509.tbs.issuer"

    pattern: "*,O=Monsters University,*"

  ...
```

This example defines a filter named "monsters-university". The filter performs a wildcard match for "O=Monsters University" in the issuer field of each incoming X.509 certificate.

### Tags
The definition of each tag is a YAML mapping that specifies the unique name of the tag and a list of filters, as defined in the Filters mapping, that all must match for the tag to be assigned to a TLS session.

A filter name can be prefixed with "not " to invert its matching behavior. When a filter is negated, the tag matches only if that filter does not match. A tag matches when all non-negated filters match and all negated filters do not match.

For example:

```
tags:

  ...

  ror-mu-chapter:

    filter:

      - monsters-university

      - not fear-tech

      - fraternity-ror

  ...
```

This example defines a tag named "ror-mu-chapter". The peer's certificate must satisfy both the "monsters-university" and "fraternity-ror" filter conditions, and must fail to satisfy the "fear-tech" filter condition, in order for the tlshd program to assign the ror-mu-chapter tag to an incoming TLS session.

### Handshake completion
Once a TLS handshake is successful, the tlshd program scans the peer's certificate using the configured filter and tag definitions. For each tag whose filter conditions the certificate satisfies, the tlshd program attaches that tag's name to the new TLS session. The kernel consumer receives only the list of matching tag names; the session's authentication material, filter types, and filter names remain private to the tlshd program.

## STANDARDS
X.509

RFC 5280, RFC 6125

## SEE ALSO
tlshd(8), tlshd.conf(5)

## AUTHOR
Chuck Lever


hci

package: libbluez-devel

title: hci(7)

summary: Bluetooth HCI protocol

text:
# hci(7)

## NAME
hci - Bluetooth HCI protocol

## SYNOPSIS

```
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
hci_socket = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
```

## DESCRIPTION
Bluetooth Host Controller Interface (HCI) is the standard protocol to communicate with Bluetooth adapters. HCI protocol provides a uniform command method for the Host to access Controller capabilities and to control connections to other Controllers.

## SOCKET ADDRESS

```
struct sockaddr_hci {

    sa_family_t    hci_family;

    unsigned short hci_dev;

    unsigned short hci_channel;
};
```

Possible values for hci_channel:

Define

Value

Description

HCI_CHANNEL_RAW

0x00

Raw channel - Used for raw HCI communication

HCI_CHANNEL_USER

0x01

User channel - Used for userspace HCI communication (disables kernel processing)

HCI_CHANNEL_MONITOR

0x02

Monitor channel - Used for monitoring HCI traffic (btmon(1))

HCI_CHANNEL_CONTROL

0x03

Control channel - Used to manage local adapters (bluetoothd(7))

HCI_CHANNEL_LOGGING

0x04

Logging channel - Used to inject logging messages (bluetoothd(7))

Example:

```
struct sockaddr_hci addr;
memset(&addr, 0, sizeof(addr));
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = HCI_DEV_NONE;
addr.hci_channel = HCI_CHANNEL_CONTROL;
```

## SOCKET OPTIONS
The socket options listed below can be set by using setsockopt(2) and read with getsockopt(2) with the socket level set to SOL_BLUETOOTH or SOL_HCI (HCI_FILTER).

### HCI_FILTER (since Linux 2.6)
Filter by HCI events, requires hci_channel to be set to HCI_CHANNEL_RAW, possible values:

```
struct hci_filter {

    uint32_t type_mask;

    uint32_t event_mask[2];

    uint16_t opcode;
};
```

Example:

```
struct hci_filter flt;
memset(&flt, 0, sizeof(flt));
flt.type_mask = 1 << BT_H4_EVT_PKT;
flt.event_mask[0] = 0xffffffff;
flt.event_mask[1] = 0xffffffff;
setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt));
```

### BT_SNDBUF (since Linux 5.16)
Set send buffer size, requires hci_channel to be set to HCI_CHANNEL_MONITOR, HCI_CHANNEL_CONTROL or HCI_CHANNEL_LOGGING.

Default value is 1028.

Example:

```
uint16_t mtu = UINT16_MAX;
int err;
err = setsockopt(fd, SOL_BLUETOOTH, BT_SNDMTU, &mtu, sizeof(mtu));
```

### BT_RCVBUF (since Linux 5.16)
Set receive buffer size, requires hci_channel to be set to HCI_CHANNEL_MONITOR, HCI_CHANNEL_CONTROL or HCI_CHANNEL_LOGGING.

Default value is 1028.

Example:

```
uint16_t mtu;
socklen_t len;
int err;
len = sizeof(mtu);
err = getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, mtu, &len);
```

## RESOURCES
http://www.bluez.org

## REPORTING BUGS
linux-bluetooth@vger.kernel.org

## SEE ALSO
socket(7)

## COPYRIGHT
Free use of this software is granted under the terms of the GNU Lesser General Public Licenses (LGPL).


iso

title: iso(7)

summary: ISO transport

text:
# iso(7)

## NAME
iso - ISO transport

## SYNOPSIS (SINCE LINUX 6.0 [EXPERIMENTAL])

```
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/iso.h>
iso_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
```

## DESCRIPTION
Bluetooth Isochronous Channels is a feature introduced in Bluetooth 5.2 that allow for the transmission of multiple, synchronized audio streams between devices.

For unicast/multi-stream audio, connected isochronous group (CIG), and connected isochronous stream (CIS) are used. A CIG is created by the central and it can include one or more CISs. A CIS is a point-to-point data transportation stream between a central and a certain peripheral, and is a bidirectional communication protocol with acknowledgment.

For broadcast audio, broadcast isochronous group (BIG) and broadcast isochronous stream (BIS) are used. There are two types of devices: isochronous broadcaster and synchronized receiver. A BIG is created by an isochronous broadcaster, and it can include one or more BISs. A BIS is a one-to-many data transportation stream.

## SOCKET ADDRESS

```
struct sockaddr_iso_bc {

    bdaddr_t        bc_bdaddr;

    uint8_t         bc_bdaddr_type;

    uint8_t         bc_sid;

    uint8_t         bc_num_bis;

    uint8_t         bc_bis[ISO_MAX_NUM_BIS];
};
struct sockaddr_iso {

    sa_family_t     iso_family;

    bdaddr_t        iso_bdaddr;

    uint8_t         iso_bdaddr_type;

    struct sockaddr_iso_bc iso_bc[];
};
```

Unicast example:

```
struct sockaddr_iso addr;
memset(&addr, 0, sizeof(addr));
addr.iso_family = AF_BLUETOOTH;
bacpy(&addr.iso_bdaddr, bdaddr);
addr.iso_bdaddr_type = BDADDR_LE_PUBLIC;
```

Broadcast example:

```
struct sockaddr_iso *addr;
size_t addr_len;
addr_len = sizeof(*addr) + sizeof(*addr->iso_bc);
memset(addr, 0, addr_len);
addr->iso_family = AF_BLUETOOTH;
bacpy(&addr->iso_bdaddr, bdaddr);
addr->iso_bdaddr_type = BDADDR_LE_PUBLIC;
```

Broadcast Source (Broadcaster) example:

```
struct sockaddr_iso *addr;
size_t addr_len;
addr_len = sizeof(*addr) + sizeof(*addr->iso_bc);
memset(addr, 0, addr_len);
addr->iso_family = AF_BLUETOOTH;
/* Set address to BDADR_ANY(00:00:00:00:00:00) */
bacpy(&addr->iso_bdaddr, BADDR_ANY);
addr->iso_bdaddr_type = BDADDR_LE_PUBLIC;
/* Connect to Broadcast address */
connect(iso_socket, (struct sockaddr *)addr, addr_len);
```

Broadcast Sink (Receiver) example:

```
struct sockaddr_iso *addr;
size_t addr_len;
addr_len = sizeof(*addr) + sizeof(*addr->iso_bc);
memset(addr, 0, addr_len);
addr->iso_family = AF_BLUETOOTH;
/* Set destination to Broadcaster address */
bacpy(&addr->iso_bdaddr, bdaddr);
addr->iso_bdaddr_type = BDADDR_LE_PUBLIC;
/* Bind to Broadcaster address */
bind(iso_socket, (struct sockaddr *)addr, addr_len);
```

Broadcast Source (Broadcaster) or Broadcast Sink (Receiver) Periodic Advertising Sync Transfer (PAST):

```
struct sockaddr_iso *addr;
size_t addr_len;
addr_len = sizeof(*addr) + sizeof(*addr->iso_bc);
memset(addr, 0, addr_len);
addr->iso_family = AF_BLUETOOTH;
/* Set destination address to PAST destination address */
bacpy(&addr->iso_bc->bc_bdaddr, (void *) bdaddr);
addr->iso_bc->bc_bdaddr_type = bdaddr_type;
/* Rebind already connected socket to PAST address */
bind(iso_socket, (struct sockaddr *)addr, addr_len);
```

## SOCKET OPTIONS (SOL_BLUETOOTH)
The socket options listed below can be set by using setsockopt(2) and read with getsockopt(2) with the socket level set to SOL_BLUETOOTH.

### BT_SECURITY
Channel security level, possible values:

Value

Security Level

Link Key Type

Encryption

BT_SECURITY_SDP

0 (SDP Only)

None

Not required

BT_SECURITY_LOW

1 (Low)

Unauthenticated

Not required

BT_SECURITY_MEDIUM

2 (Medium - default)

Unauthenticated

Desired

BT_SECURITY_HIGH

3 (High)

Authenticated

Required

BT_SECURITY_FIPS (since Linux 3.15)

4 (Secure Only)

Authenticated (P-256 based Secure Simple Pairing and Secure Authentication)

Required

Example:

```
int level = BT_SECURITY_HIGH;
int err = setsockopt(iso_socket, SOL_BLUETOOTH, BT_SECURITY, &level,

                     sizeof(level));
if (err == -1) {

    perror("setsockopt");

    return 1;
}
```

### BT_DEFER_SETUP
Channel defer connection setup, this control if the connection procedure needs to be authorized by userspace before responding which allows authorization at profile level, possible values:

Value

Description

Authorization

0

Disable (default)

Not required

1

Enable

Required

Example:

```
int defer_setup = 1;
int err = setsockopt(iso_socket, SOL_BLUETOOTH, BT_DEFER_SETUP,

                     &defer_setup, sizeof(defer_setup));
if (err == -1) {

    perror("setsockopt");

    return err;
}
err = listen(iso_socket, 5);
if (err) {

    perror("listen");

    return err;
}
struct sockaddr_iso remote_addr = {0};
socklen_t addr_len = sizeof(remote_addr);
int new_socket = accept(iso_socket, (struct sockaddr*)&remote_addr,

                        &addr_len);
if (new_socket < 0) {

    perror("accept");

    return new_socket;
}
/* To complete the connection setup of new_socket read 1 byte */
char c;
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = new_socket;
pfd.events = POLLOUT;
err = poll(&pfd, 1, 0);
if (err) {

    perror("poll");

    return err;
}
if (!(pfd.revents & POLLOUT)) {

    err = read(sk, &c, 1);

    if (err < 0) {

        perror("read");

        return err;

    }
}
```

### BT_PKT_STATUS
Enable reporting packet status via BT_SCM_PKT_STATUS CMSG on received packets. Possible values:

Value

Description

0

Disable (default)

1

Enable

BT_SCM_PKT_STATUS

Level SOL_BLUETOOTH CMSG with data:

```
uint8_t pkt_status;
```

The values are equal to the "Packet_Status_Flag" defined in Core Specification v6.1, 5.4.5. HCI ISO Data packets:

https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-61/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-9b5fb085-278b-5084-ac33-bee2839abe6b

pkt_status

Description

0x0

Valid data. The complete SDU was received correctly.

0x1

Possibly invalid data. The contents of the ISO_SDU_Fragment, may contain errors or part of the SDU may be missing. This is reported as 'data with possible errors'.

0x2

Part(s) of the SDU were not received correctly. This is reported as 'lost data'.

### BT_PKT_SEQNUM (since Linux 6.17-rc1)
Enable reporting packet ISO sequence number via BT_SCM_PKT_SEQNUM CMSG on received packets. Possible values:

Value

Description

0

Disable (default)

1

Enable

BT_SCM_PKT_SEQNUM

Level SOL_BLUETOOTH CMSG with data:

```
uint16_t pkt_seqnum;
```

The values are equal to the "Packet_Sequence_Number" defined in Core Specification v6.1, 5.4.5. HCI ISO Data packets:

https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-61/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-9b5fb085-278b-5084-ac33-bee2839abe6b

Example (Enable sequence numbers):

```
uint32_t opt = 1;
if (setsockopt(fd, SOL_BLUETOOTH, BT_PKT_SEQNUM, &opt, sizeof(opt)) < 0)

    goto error;
```

Example (Read packet and its sequence number):

```
char data_buf[256];
uint16_t seqnum;
union {

    char buf[CMSG_SPACE(sizeof(uint16_t))];

    struct cmsghdr align;
} control;
struct iovec data = {

    .iov_base = data_buf,

    .iov_len = sizeof(data_buf),
};
struct msghdr msg = {

    .msg_iov = &data,

    .msg_iovlen = 1,

    .msg_control = control.buf,

    .msg_controllen = sizeof(control.buf),
};
struct scm_timestamping tss;
res = recvmsg(fd, &msg, 0);
if (res < 0)

    goto error;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {

    if (cmsg->cmsg_level == SOL_BLUETOOTH && cmsg->cmsg_type == BT_PKT_SEQNUM)

        memcpy(&seqnum, CMSG_DATA(cmsg), sizeof(seqnum));
}
```

## SOCKET OPTIONS (SOL_SOCKET)
SOL_SOCKET level socket options that modify generic socket features (SO_SNDBUF, SO_RCVBUF, etc.) have their usual meaning, see socket(7).

The SOL_SOCKET level ISO socket options that have Bluetooth-specific handling in kernel are listed below.

### SO_TIMESTAMPING, SO_TIMESTAMP, SO_TIMESTAMPNS
See https://docs.kernel.org/networking/timestamping.html

For ISO sockets, software RX timestamps are supported. Software TX timestamps (SOF_TIMESTAMPING_TX_SOFTWARE) are supported since Linux 6.15.

The software RX timestamp is the time when the kernel received the packet from the controller driver.

The SCM_TSTAMP_SND timestamp is emitted when packet is sent to the controller driver.

The SCM_TSTAMP_COMPLETION timestamp is emitted when controller reports the packet completed. Completion timestamps are only supported on controllers that have ISO flow control. Other TX timestamp types are not supported.

You can use SIOCETHTOOL to query supported flags.

The timestamps are in CLOCK_REALTIME time.

Example (Enable RX timestamping):

```
int flags = SOF_TIMESTAMPING_SOFTWARE |

    SOF_TIMESTAMPING_RX_SOFTWARE;
setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof(flags));
```

Example (Read packet and its RX timestamp):

```
char data_buf[256];
union {

    char buf[CMSG_SPACE(sizeof(struct scm_timestamping))];

    struct cmsghdr align;
} control;
struct iovec data = {

    .iov_base = data_buf,

    .iov_len = sizeof(data_buf),
};
struct msghdr msg = {

    .msg_iov = &data,

    .msg_iovlen = 1,

    .msg_control = control.buf,

    .msg_controllen = sizeof(control.buf),
};
struct scm_timestamping tss;
res = recvmsg(fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT);
if (res < 0)

    goto error;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {

    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING)

        memcpy(&tss, CMSG_DATA(cmsg), sizeof(tss));
}
tstamp_clock_realtime = tss.ts[0];
```

Example (Enable TX timestamping):

```
int flags = SOF_TIMESTAMPING_SOFTWARE |

    SOF_TIMESTAMPING_TX_SOFTWARE |

    SOF_TIMESTAMPING_OPT_ID;
setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof(flags));
```

Example (Read TX timestamps):

```
union {

    char buf[CMSG_SPACE(sizeof(struct scm_timestamping))];

    struct cmsghdr align;
} control;
struct iovec data = {

    .iov_base = NULL,

    .iov_len = 0
};
struct msghdr msg = {

    .msg_iov = &data,

    .msg_iovlen = 1,

    .msg_control = control.buf,

    .msg_controllen = sizeof(control.buf),
};
struct cmsghdr *cmsg;
struct scm_timestamping tss;
struct sock_extended_err serr;
int res;
res = recvmsg(fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT);
if (res < 0)

    goto error;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {

    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING)

        memcpy(&tss, CMSG_DATA(cmsg), sizeof(tss));

    else if (cmsg->cmsg_level == SOL_BLUETOOTH && cmsg->cmsg_type == BT_SCM_ERROR)

        memcpy(&serr, CMSG_DATA(cmsg), sizeof(serr));
}
tstamp_clock_realtime = tss.ts[0];
tstamp_type = serr->ee_info;      /* SCM_TSTAMP_SND or SCM_TSTAMP_COMPLETION */
tstamp_seqnum = serr->ee_data;
```

## IOCTLS
The following ioctls with operation specific for ISO sockets are available.

### SIOCETHTOOL (since Linux 6.16-rc1)
Supports only command ETHTOOL_GET_TS_INFO, which may be used to query supported SOF_TIMESTAMPING_* flags. The SOF_TIMESTAMPING_OPT_* flags are always available as applicable.

Example:

```
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
...
struct ifreq ifr = {};
struct ethtool_ts_info cmd = {};
int sk;
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "hci0");
ifr.ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GET_TS_INFO;
sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
if (sk < 0)

    goto error;
if (ioctl(sk, SIOCETHTOOL, &ifr))

    goto error;
sof_available = cmd.so_timestamping;
```

## RESOURCES
http://www.bluez.org

## REPORTING BUGS
linux-bluetooth@vger.kernel.org

## SEE ALSO
socket(7), isotest(1)

## COPYRIGHT
Free use of this software is granted under the terms of the GNU Lesser General Public Licenses (LGPL).


title: l2cap(7)

summary: L2CAP protocol

text:
# l2cap(7)

## NAME
l2cap - L2CAP protocol

## SYNOPSIS

```
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
l2cap_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
```

## DESCRIPTION
L2CAP is a protocol that provides an interface for higher-level protocols to send and receive data over a Bluetooth connection. L2CAP sits on top of the Bluetooth Host Controller Interface (HCI) and provides a set of channels that can be used by higher-level protocols to transmit data.

L2CAP provides a number of services to higher-level protocols, including segmentation and reassembly of large data packets and flow control to prevent overloading of the receiver. L2CAP also supports multiple channels per connection, allowing for concurrent data transmission using different protocols.

## SOCKET ADDRESS

```
struct sockaddr_l2 {

    sa_family_t     l2_family;

    unsigned short  l2_psm;

    bdaddr_t        l2_bdaddr;

    unsigned short  l2_cid;

    uint8_t         l2_bdaddr_type;
};
```

Example:

```
struct sockaddr_l2 addr;
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
bacpy(&addr.l2_bdaddr, bdaddr);
if (cid)

    addr.l2_cid = htobs(cid);
else

    addr.l2_psm = htobs(psm);
addr.l2_bdaddr_type = bdaddr_type;
```

## SOCKET OPTIONS (SOL_BLUETOOTH)
The socket options listed below can be set by using setsockopt(2) and read with getsockopt(2) with the socket level set to SOL_BLUETOOTH.

### BT_SECURITY (since Linux 2.6.30)
Channel security level, possible values:

Value

Security Level

Link Key Type

Encryption

BT_SECURITY_SDP

0 (SDP Only)

None

Not required

BT_SECURITY_LOW

1 (Low)

Unauthenticated

Not required

BT_SECURITY_MEDIUM

2 (Medium - default)

Unauthenticated

Desired

BT_SECURITY_HIGH

3 (High)

Authenticated

Required

BT_SECURITY_FIPS (since Linux 3.15)

4 (Secure Only)

Authenticated (P-256 based Secure Simple Pairing and Secure Authentication)

Required

Example:

```
int level = BT_SECURITY_HIGH;
int err = setsockopt(l2cap_socket, SOL_BLUETOOTH, BT_SECURITY, &level,

                     sizeof(level));
if (err == -1) {

    perror("setsockopt");

    return 1;
}
```

### BT_DEFER_SETUP (since Linux 2.6.30)
Channel defer connection setup, this control if the connection procedure needs to be authorized by userspace before responding which allows authorization at profile level, possible values:

Value

Description

Authorization

0

Disable (default)

Not required

1

Enable

Required

Example:

```
int defer_setup = 1;
int err = setsockopt(l2cap_socket, SOL_BLUETOOTH, BT_DEFER_SETUP,

                     &defer_setup, sizeof(defer_setup));
if (err == -1) {

    perror("setsockopt");

    return err;
}
err = listen(l2cap_socket, 5);
if (err) {

    perror("listen");

    return err;
}
struct sockaddr_l2 remote_addr = {0};
socklen_t addr_len = sizeof(remote_addr);
int new_socket = accept(l2cap_socket, (struct sockaddr*)&remote_addr,

                        &addr_len);
if (new_socket < 0) {

    perror("accept");

    return new_socket;
}
/* To complete the connection setup of new_socket read 1 byte */
char c;
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = new_socket;
pfd.events = POLLOUT;
err = poll(&pfd, 1, 0);
if (err) {

    perror("poll");

    return err;
}
if (!(pfd.revents & POLLOUT)) {

    err = read(sk, &c, 1);

    if (err < 0) {

        perror("read");

        return err;

    }
}
```

### BT_FLUSHABLE (since Linux 2.6.39)
Channel flushable flag, this control if the channel data can be flushed or not, possible values:

Define

Value

Description

BT_FLUSHABLE_OFF

0x00 (default)

Do not flush data

BT_FLUSHABLE_ON

0x01

Flush data

### BT_POWER (since Linux 3.1)
Channel power policy, this control if the channel shall force exit of sniff mode or not, possible values:

Define

Value

Description

BT_POWER_FORCE_ACTIVE_OFF

0x00

Don't force exit of sniff mode

BT_POWER_FORCE_ACTIVE_ON

0x01 (default)

Force exit of sniff mode

### BT_CHANNEL_POLICY (since Linux 3.10)
High-speed (AMP) channel policy, possible values:

Define

Value

Description

BT_CHANNEL_POLICY_BREDR_ONLY

0 (default)

BR/EDR only

BT_CHANNEL_POLICY_BREDR_PREFERRED

1

BR/EDR Preferred

BT_CHANNEL_POLICY_BREDR_PREFERRED

2

AMP Preferred

### BT_PHY (since Linux 5.10)
Channel supported PHY(s), possible values:

Define

Value

Description

BT_PHY_BR_1M_1SLOT

BIT 0

BR 1Mbps 1SLOT

BT_PHY_BR_1M_3SLOT

BIT 1

BR 1Mbps 3SLOT

BT_PHY_BR_1M_5SLOT

BIT 2

BR 1Mbps 5SLOT

BT_PHY_BR_2M_1SLOT

BIT 3

EDR 2Mbps 1SLOT

BT_PHY_BR_2M_3SLOT

BIT 4

EDR 2Mbps 3SLOT

BT_PHY_BR_2M_5SLOT

BIT 5

EDR 2Mbps 5SLOT

BT_PHY_BR_3M_1SLOT

BIT 6

EDR 3Mbps 1SLOT

BT_PHY_BR_3M_3SLOT

BIT 7

EDR 3Mbps 3SLOT

BT_PHY_BR_3M_5SLOT

BIT 8

EDR 3Mbps 5SLOT

BT_PHY_LE_1M_TX

BIT 9

LE 1Mbps TX

BT_PHY_LE_1M_RX

BIT 10

LE 1Mbps RX

BT_PHY_LE_2M_TX

BIT 11

LE 2Mbps TX

BT_PHY_LE_2M_RX

BIT 12

LE 2Mbps RX

BT_PHY_LE_CODED_TX

BIT 13

LE Coded TX

BT_PHY_LE_CODED_RX

BIT 14

LE Coded RX

### BT_MODE (since Linux 5.10)
Channel Mode, possible values:

Define

Value

Description

Link

BT_MODE_BASIC

0x00 (default)

Basic mode

Any

BT_MODE_ERTM

0x01

Enhanced Retransmission mode

BR/EDR

BT_MODE_STREAM

0x02

Stream mode

BR/EDR

BT_MODE_LE_FLOWCTL

0x03

Credit based flow control mode

LE

BT_MODE_EXT_FLOWCTL

0x04

Extended Credit based flow control mode

Any

## SOCKET OPTIONS (SOL_SOCKET)
SOL_SOCKET level socket options that modify generic socket features (SO_SNDBUF, SO_RCVBUF, etc.) have their usual meaning, see socket(7).

The SOL_SOCKET level L2CAP socket options that have Bluetooth-specific handling in kernel are listed below.

### SO_TIMESTAMPING, SO_TIMESTAMP, SO_TIMESTAMPNS
See https://docs.kernel.org/networking/timestamping.html

For L2CAP sockets, software RX timestamps are supported. Software TX timestamps (SOF_TIMESTAMPING_TX_SOFTWARE, SOF_TIMESTAMPING_TX_COMPLETION) are supported since Linux 6.15.

The software RX timestamp is the time when the kernel received the packet from the controller driver.

The SCM_TSTAMP_SND timestamp is emitted when packet is sent to the controller driver. The SCM_TSTAMP_COMPLETION timestamp is emitted when controller reports the packet completed. Other TX timestamp types are not supported.

You can use SIOCETHTOOL to query supported flags.

The timestamps are in CLOCK_REALTIME time.

Example (Enable RX timestamping):

```
int flags = SOF_TIMESTAMPING_SOFTWARE |

    SOF_TIMESTAMPING_RX_SOFTWARE;
setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof(flags));
```

Example (Read packet and its RX timestamp):

```
char data_buf[256];
union {

    char buf[CMSG_SPACE(sizeof(struct scm_timestamping))];

    struct cmsghdr align;
} control;
struct iovec data = {

    .iov_base = data_buf,

    .iov_len = sizeof(data_buf),
};
struct msghdr msg = {

    .msg_iov = &data,

    .msg_iovlen = 1,

    .msg_control = control.buf,

    .msg_controllen = sizeof(control.buf),
};
struct scm_timestamping tss;
res = recvmsg(fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT);
if (res < 0)

    goto error;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {

    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING)

        memcpy(&tss, CMSG_DATA(cmsg), sizeof(tss));
}
tstamp_clock_realtime = tss.ts[0];
```

Example (Enable TX timestamping):

```
int flags = SOF_TIMESTAMPING_SOFTWARE |

    SOF_TIMESTAMPING_TX_SOFTWARE |

    SOF_TIMESTAMPING_TX_COMPLETION |

    SOF_TIMESTAMPING_OPT_ID;
setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof(flags));
```

Example (Read TX timestamps):

```
union {

    char buf[2 * CMSG_SPACE(sizeof(struct scm_timestamping))];

    struct cmsghdr align;
} control;
struct iovec data = {

    .iov_base = NULL,

    .iov_len = 0
};
struct msghdr msg = {

    .msg_iov = &data,

    .msg_iovlen = 1,

    .msg_control = control.buf,

    .msg_controllen = sizeof(control.buf),
};
struct cmsghdr *cmsg;
struct scm_timestamping tss;
struct sock_extended_err serr;
int res;
res = recvmsg(fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT);
if (res < 0)

    goto error;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {

    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING)

        memcpy(&tss, CMSG_DATA(cmsg), sizeof(tss));

    else if (cmsg->cmsg_level == SOL_BLUETOOTH && cmsg->cmsg_type == BT_SCM_ERROR)

        memcpy(&serr, CMSG_DATA(cmsg), sizeof(serr));
}
tstamp_clock_realtime = tss.ts[0];
tstamp_type = serr->ee_info;      /* SCM_TSTAMP_SND or SCM_TSTAMP_COMPLETION */
tstamp_seqnum = serr->ee_data;
```

## IOCTLS
The following ioctls with operation specific for L2CAP sockets are available.

### SIOCETHTOOL (since Linux 6.16-rc1)
Supports only command ETHTOOL_GET_TS_INFO, which may be used to query supported SOF_TIMESTAMPING_* flags. The SOF_TIMESTAMPING_OPT_* flags are always available as applicable.

Example:

```
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
...
struct ifreq ifr = {};
struct ethtool_ts_info cmd = {};
int sk;
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "hci0");
ifr.ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GET_TS_INFO;
sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (sk < 0)

    goto error;
if (ioctl(sk, SIOCETHTOOL, &ifr))

    goto error;
sof_available = cmd.so_timestamping;
```

## RESOURCES
http://www.bluez.org

## REPORTING BUGS
linux-bluetooth@vger.kernel.org

## SEE ALSO
socket(7), l2test(1)

## COPYRIGHT
Free use of this software is granted under the terms of the GNU Lesser General Public Licenses (LGPL).