← Documents Documentation/networking/ppp_generic.rst GitHub 원문 ↗

Linux 6.18.37 · Networking

PPP Generic Driver와 Channel Interface

Generic PPP unit·channel 구조, multilink, SMP 계약과 /dev/ppp ioctl interface를 설명합니다.

Source pathDocumentation/networking/ppp_generic.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

ppp_generic.rst:1-456

Generic PPP driver는 transport-specific channel과 network-facing PPP unit 사이에서 압축, filtering, demand·idle 감지와 multilink를 처리합니다. `/dev/ppp`의 각 open instance를 unit 또는 channel에 attach하여 pppd가 negotiation과 data path를 제어하며, 엄격한 object 수명과 SMP 호출 context 계약을 둡니다.

PPP 전체 데이터 경로
pppd / /dev/pppPPP unit bundleCompression·multilink·filterppp_channelAsync/Sync/PPPoE medium
Networking stackpppN interfacePPP unit bundle

Userspace 제어와 network packet 경로가 unit·channel에서 만납니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 ========================================
4 PPP Generic Driver and Channel Interface
5 ========================================
6
7 Paul Mackerras
8 paulus@samba.org
9
10 7 Feb 2002
11
12 The generic PPP driver in linux-2.4 provides an implementation of the
13 functionality which is of use in any PPP implementation, including:
14
15 * the network interface unit (ppp0 etc.)
16 * the interface to the networking code
17 * PPP multilink: splitting datagrams between multiple links, and
18 ordering and combining received fragments
19 * the interface to pppd, via a /dev/ppp character device
20 * packet compression and decompression
21 * TCP/IP header compression and decompression
22 * detecting network traffic for demand dialling and for idle timeouts
23 * simple packet filtering
24
25 For sending and receiving PPP frames, the generic PPP driver calls on
26 the services of PPP ``channels``. A PPP channel encapsulates a
27 mechanism for transporting PPP frames from one machine to another. A
28 PPP channel implementation can be arbitrarily complex internally but
29 has a very simple interface with the generic PPP code: it merely has
30 to be able to send PPP frames, receive PPP frames, and optionally
31 handle ioctl requests. Currently there are PPP channel
32 implementations for asynchronous serial ports, synchronous serial
33 ports, and for PPP over ethernet.
34
35 This architecture makes it possible to implement PPP multilink in a
36 natural and straightforward way, by allowing more than one channel to
37 be linked to each ppp network interface unit. The generic layer is
38 responsible for splitting datagrams on transmit and recombining them
39 on receive.
40
41
42 PPP channel API
43 ---------------
44
45 See include/linux/ppp_channel.h for the declaration of the types and
46 functions used to communicate between the generic PPP layer and PPP
47 channels.
48
49 Each channel has to provide two functions to the generic PPP layer,
50 via the ppp_channel.ops pointer:
51
52 * start_xmit() is called by the generic layer when it has a frame to
53 send. The channel has the option of rejecting the frame for
54 flow-control reasons. In this case, start_xmit() should return 0
55 and the channel should call the ppp_output_wakeup() function at a
56 later time when it can accept frames again, and the generic layer
57 will then attempt to retransmit the rejected frame(s). If the frame
58 is accepted, the start_xmit() function should return 1.
59
60 * ioctl() provides an interface which can be used by a user-space
61 program to control aspects of the channel's behaviour. This
62 procedure will be called when a user-space program does an ioctl
63 system call on an instance of /dev/ppp which is bound to the
64 channel. (Usually it would only be pppd which would do this.)
65
66 The generic PPP layer provides seven functions to channels:
67
68 * ppp_register_channel() is called when a channel has been created, to
69 notify the PPP generic layer of its presence. For example, setting
70 a serial port to the PPPDISC line discipline causes the ppp_async
71 channel code to call this function.
72
73 * ppp_unregister_channel() is called when a channel is to be
74 destroyed. For example, the ppp_async channel code calls this when
75 a hangup is detected on the serial port.
76
77 * ppp_output_wakeup() is called by a channel when it has previously
78 rejected a call to its start_xmit function, and can now accept more
79 packets.
80
81 * ppp_input() is called by a channel when it has received a complete
82 PPP frame.
83
84 * ppp_input_error() is called by a channel when it has detected that a
85 frame has been lost or dropped (for example, because of a FCS (frame
86 check sequence) error).
87
88 * ppp_channel_index() returns the channel index assigned by the PPP
89 generic layer to this channel. The channel should provide some way
90 (e.g. an ioctl) to transmit this back to user-space, as user-space
91 will need it to attach an instance of /dev/ppp to this channel.
92
93 * ppp_unit_number() returns the unit number of the ppp network
94 interface to which this channel is connected, or -1 if the channel
95 is not connected.
96
97 Connecting a channel to the ppp generic layer is initiated from the
98 channel code, rather than from the generic layer. The channel is
99 expected to have some way for a user-level process to control it
100 independently of the ppp generic layer. For example, with the
101 ppp_async channel, this is provided by the file descriptor to the
102 serial port.
103
104 Generally a user-level process will initialize the underlying
105 communications medium and prepare it to do PPP. For example, with an
106 async tty, this can involve setting the tty speed and modes, issuing
107 modem commands, and then going through some sort of dialog with the
108 remote system to invoke PPP service there. We refer to this process
109 as ``discovery``. Then the user-level process tells the medium to
110 become a PPP channel and register itself with the generic PPP layer.
111 The channel then has to report the channel number assigned to it back
112 to the user-level process. From that point, the PPP negotiation code
113 in the PPP daemon (pppd) can take over and perform the PPP
114 negotiation, accessing the channel through the /dev/ppp interface.
115
116 At the interface to the PPP generic layer, PPP frames are stored in
117 skbuff structures and start with the two-byte PPP protocol number.
118 The frame does *not* include the 0xff ``address`` byte or the 0x03
119 ``control`` byte that are optionally used in async PPP. Nor is there
120 any escaping of control characters, nor are there any FCS or framing
121 characters included. That is all the responsibility of the channel
122 code, if it is needed for the particular medium. That is, the skbuffs
123 presented to the start_xmit() function contain only the 2-byte
124 protocol number and the data, and the skbuffs presented to ppp_input()
125 must be in the same format.
126
127 The channel must provide an instance of a ppp_channel struct to
128 represent the channel. The channel is free to use the ``private`` field
129 however it wishes. The channel should initialize the ``mtu`` and
130 ``hdrlen`` fields before calling ppp_register_channel() and not change
131 them until after ppp_unregister_channel() returns. The ``mtu`` field
132 represents the maximum size of the data part of the PPP frames, that
133 is, it does not include the 2-byte protocol number.
134
135 If the channel needs some headroom in the skbuffs presented to it for
136 transmission (i.e., some space free in the skbuff data area before the
137 start of the PPP frame), it should set the ``hdrlen`` field of the
138 ppp_channel struct to the amount of headroom required. The generic
139 PPP layer will attempt to provide that much headroom but the channel
140 should still check if there is sufficient headroom and copy the skbuff
141 if there isn't.
142
143 On the input side, channels should ideally provide at least 2 bytes of
144 headroom in the skbuffs presented to ppp_input(). The generic PPP
145 code does not require this but will be more efficient if this is done.
146
147
148 Buffering and flow control
149 --------------------------
150
151 The generic PPP layer has been designed to minimize the amount of data
152 that it buffers in the transmit direction. It maintains a queue of
153 transmit packets for the PPP unit (network interface device) plus a
154 queue of transmit packets for each attached channel. Normally the
155 transmit queue for the unit will contain at most one packet; the
156 exceptions are when pppd sends packets by writing to /dev/ppp, and
157 when the core networking code calls the generic layer's start_xmit()
158 function with the queue stopped, i.e. when the generic layer has
159 called netif_stop_queue(), which only happens on a transmit timeout.
160 The start_xmit function always accepts and queues the packet which it
161 is asked to transmit.
162
163 Transmit packets are dequeued from the PPP unit transmit queue and
164 then subjected to TCP/IP header compression and packet compression
165 (Deflate or BSD-Compress compression), as appropriate. After this
166 point the packets can no longer be reordered, as the decompression
167 algorithms rely on receiving compressed packets in the same order that
168 they were generated.
169
170 If multilink is not in use, this packet is then passed to the attached
171 channel's start_xmit() function. If the channel refuses to take
172 the packet, the generic layer saves it for later transmission. The
173 generic layer will call the channel's start_xmit() function again
174 when the channel calls ppp_output_wakeup() or when the core
175 networking code calls the generic layer's start_xmit() function
176 again. The generic layer contains no timeout and retransmission
177 logic; it relies on the core networking code for that.
178
179 If multilink is in use, the generic layer divides the packet into one
180 or more fragments and puts a multilink header on each fragment. It
181 decides how many fragments to use based on the length of the packet
182 and the number of channels which are potentially able to accept a
183 fragment at the moment. A channel is potentially able to accept a
184 fragment if it doesn't have any fragments currently queued up for it
185 to transmit. The channel may still refuse a fragment; in this case
186 the fragment is queued up for the channel to transmit later. This
187 scheme has the effect that more fragments are given to higher-
188 bandwidth channels. It also means that under light load, the generic
189 layer will tend to fragment large packets across all the channels,
190 thus reducing latency, while under heavy load, packets will tend to be
191 transmitted as single fragments, thus reducing the overhead of
192 fragmentation.
193
194
195 SMP safety
196 ----------
197
198 The PPP generic layer has been designed to be SMP-safe. Locks are
199 used around accesses to the internal data structures where necessary
200 to ensure their integrity. As part of this, the generic layer
201 requires that the channels adhere to certain requirements and in turn
202 provides certain guarantees to the channels. Essentially the channels
203 are required to provide the appropriate locking on the ppp_channel
204 structures that form the basis of the communication between the
205 channel and the generic layer. This is because the channel provides
206 the storage for the ppp_channel structure, and so the channel is
207 required to provide the guarantee that this storage exists and is
208 valid at the appropriate times.
209
210 The generic layer requires these guarantees from the channel:
211
212 * The ppp_channel object must exist from the time that
213 ppp_register_channel() is called until after the call to
214 ppp_unregister_channel() returns.
215
216 * No thread may be in a call to any of ppp_input(), ppp_input_error(),
217 ppp_output_wakeup(), ppp_channel_index() or ppp_unit_number() for a
218 channel at the time that ppp_unregister_channel() is called for that
219 channel.
220
221 * ppp_register_channel() and ppp_unregister_channel() must be called
222 from process context, not interrupt or softirq/BH context.
223
224 * The remaining generic layer functions may be called at softirq/BH
225 level but must not be called from a hardware interrupt handler.
226
227 * The generic layer may call the channel start_xmit() function at
228 softirq/BH level but will not call it at interrupt level. Thus the
229 start_xmit() function may not block.
230
231 * The generic layer will only call the channel ioctl() function in
232 process context.
233
234 The generic layer provides these guarantees to the channels:
235
236 * The generic layer will not call the start_xmit() function for a
237 channel while any thread is already executing in that function for
238 that channel.
239
240 * The generic layer will not call the ioctl() function for a channel
241 while any thread is already executing in that function for that
242 channel.
243
244 * By the time a call to ppp_unregister_channel() returns, no thread
245 will be executing in a call from the generic layer to that channel's
246 start_xmit() or ioctl() function, and the generic layer will not
247 call either of those functions subsequently.
248
249
250 Interface to pppd
251 -----------------
252
253 The PPP generic layer exports a character device interface called
254 /dev/ppp. This is used by pppd to control PPP interface units and
255 channels. Although there is only one /dev/ppp, each open instance of
256 /dev/ppp acts independently and can be attached either to a PPP unit
257 or a PPP channel. This is achieved using the file->private_data field
258 to point to a separate object for each open instance of /dev/ppp. In
259 this way an effect similar to Solaris' clone open is obtained,
260 allowing us to control an arbitrary number of PPP interfaces and
261 channels without having to fill up /dev with hundreds of device names.
262
263 When /dev/ppp is opened, a new instance is created which is initially
264 unattached. Using an ioctl call, it can then be attached to an
265 existing unit, attached to a newly-created unit, or attached to an
266 existing channel. An instance attached to a unit can be used to send
267 and receive PPP control frames, using the read() and write() system
268 calls, along with poll() if necessary. Similarly, an instance
269 attached to a channel can be used to send and receive PPP frames on
270 that channel.
271
272 In multilink terms, the unit represents the bundle, while the channels
273 represent the individual physical links. Thus, a PPP frame sent by a
274 write to the unit (i.e., to an instance of /dev/ppp attached to the
275 unit) will be subject to bundle-level compression and to fragmentation
276 across the individual links (if multilink is in use). In contrast, a
277 PPP frame sent by a write to the channel will be sent as-is on that
278 channel, without any multilink header.
279
280 A channel is not initially attached to any unit. In this state it can
281 be used for PPP negotiation but not for the transfer of data packets.
282 It can then be connected to a PPP unit with an ioctl call, which
283 makes it available to send and receive data packets for that unit.
284
285 The ioctl calls which are available on an instance of /dev/ppp depend
286 on whether it is unattached, attached to a PPP interface, or attached
287 to a PPP channel. The ioctl calls which are available on an
288 unattached instance are:
289
290 * PPPIOCNEWUNIT creates a new PPP interface and makes this /dev/ppp
291 instance the "owner" of the interface. The argument should point to
292 an int which is the desired unit number if >= 0, or -1 to assign the
293 lowest unused unit number. Being the owner of the interface means
294 that the interface will be shut down if this instance of /dev/ppp is
295 closed.
296
297 * PPPIOCATTACH attaches this instance to an existing PPP interface.
298 The argument should point to an int containing the unit number.
299 This does not make this instance the owner of the PPP interface.
300
301 * PPPIOCATTCHAN attaches this instance to an existing PPP channel.
302 The argument should point to an int containing the channel number.
303
304 The ioctl calls available on an instance of /dev/ppp attached to a
305 channel are:
306
307 * PPPIOCCONNECT connects this channel to a PPP interface. The
308 argument should point to an int containing the interface unit
309 number. It will return an EINVAL error if the channel is already
310 connected to an interface, or ENXIO if the requested interface does
311 not exist.
312
313 * PPPIOCDISCONN disconnects this channel from the PPP interface that
314 it is connected to. It will return an EINVAL error if the channel
315 is not connected to an interface.
316
317 * PPPIOCBRIDGECHAN bridges a channel with another. The argument should
318 point to an int containing the channel number of the channel to bridge
319 to. Once two channels are bridged, frames presented to one channel by
320 ppp_input() are passed to the bridge instance for onward transmission.
321 This allows frames to be switched from one channel into another: for
322 example, to pass PPPoE frames into a PPPoL2TP session. Since channel
323 bridging interrupts the normal ppp_input() path, a given channel may
324 not be part of a bridge at the same time as being part of a unit.
325 This ioctl will return an EALREADY error if the channel is already
326 part of a bridge or unit, or ENXIO if the requested channel does not
327 exist.
328
329 * PPPIOCUNBRIDGECHAN performs the inverse of PPPIOCBRIDGECHAN, unbridging
330 a channel pair. This ioctl will return an EINVAL error if the channel
331 does not form part of a bridge.
332
333 * All other ioctl commands are passed to the channel ioctl() function.
334
335 The ioctl calls that are available on an instance that is attached to
336 an interface unit are:
337
338 * PPPIOCSMRU sets the MRU (maximum receive unit) for the interface.
339 The argument should point to an int containing the new MRU value.
340
341 * PPPIOCSFLAGS sets flags which control the operation of the
342 interface. The argument should be a pointer to an int containing
343 the new flags value. The bits in the flags value that can be set
344 are:
345
346 ================ ========================================
347 SC_COMP_TCP enable transmit TCP header compression
348 SC_NO_TCP_CCID disable connection-id compression for
349 TCP header compression
350 SC_REJ_COMP_TCP disable receive TCP header decompression
351 SC_CCP_OPEN Compression Control Protocol (CCP) is
352 open, so inspect CCP packets
353 SC_CCP_UP CCP is up, may (de)compress packets
354 SC_LOOP_TRAFFIC send IP traffic to pppd
355 SC_MULTILINK enable PPP multilink fragmentation on
356 transmitted packets
357 SC_MP_SHORTSEQ expect short multilink sequence
358 numbers on received multilink fragments
359 SC_MP_XSHORTSEQ transmit short multilink sequence nos.
360 ================ ========================================
361
362 The values of these flags are defined in <linux/ppp-ioctl.h>. Note
363 that the values of the SC_MULTILINK, SC_MP_SHORTSEQ and
364 SC_MP_XSHORTSEQ bits are ignored if the CONFIG_PPP_MULTILINK option
365 is not selected.
366
367 * PPPIOCGFLAGS returns the value of the status/control flags for the
368 interface unit. The argument should point to an int where the ioctl
369 will store the flags value. As well as the values listed above for
370 PPPIOCSFLAGS, the following bits may be set in the returned value:
371
372 ================ =========================================
373 SC_COMP_RUN CCP compressor is running
374 SC_DECOMP_RUN CCP decompressor is running
375 SC_DC_ERROR CCP decompressor detected non-fatal error
376 SC_DC_FERROR CCP decompressor detected fatal error
377 ================ =========================================
378
379 * PPPIOCSCOMPRESS sets the parameters for packet compression or
380 decompression. The argument should point to a ppp_option_data
381 structure (defined in <linux/ppp-ioctl.h>), which contains a
382 pointer/length pair which should describe a block of memory
383 containing a CCP option specifying a compression method and its
384 parameters. The ppp_option_data struct also contains a ``transmit``
385 field. If this is 0, the ioctl will affect the receive path,
386 otherwise the transmit path.
387
388 * PPPIOCGUNIT returns, in the int pointed to by the argument, the unit
389 number of this interface unit.
390
391 * PPPIOCSDEBUG sets the debug flags for the interface to the value in
392 the int pointed to by the argument. Only the least significant bit
393 is used; if this is 1 the generic layer will print some debug
394 messages during its operation. This is only intended for debugging
395 the generic PPP layer code; it is generally not helpful for working
396 out why a PPP connection is failing.
397
398 * PPPIOCGDEBUG returns the debug flags for the interface in the int
399 pointed to by the argument.
400
401 * PPPIOCGIDLE returns the time, in seconds, since the last data
402 packets were sent and received. The argument should point to a
403 ppp_idle structure (defined in <linux/ppp_defs.h>). If the
404 CONFIG_PPP_FILTER option is enabled, the set of packets which reset
405 the transmit and receive idle timers is restricted to those which
406 pass the ``active`` packet filter.
407 Two versions of this command exist, to deal with user space
408 expecting times as either 32-bit or 64-bit time_t seconds.
409
410 * PPPIOCSMAXCID sets the maximum connection-ID parameter (and thus the
411 number of connection slots) for the TCP header compressor and
412 decompressor. The lower 16 bits of the int pointed to by the
413 argument specify the maximum connection-ID for the compressor. If
414 the upper 16 bits of that int are non-zero, they specify the maximum
415 connection-ID for the decompressor, otherwise the decompressor's
416 maximum connection-ID is set to 15.
417
418 * PPPIOCSNPMODE sets the network-protocol mode for a given network
419 protocol. The argument should point to an npioctl struct (defined
420 in <linux/ppp-ioctl.h>). The ``protocol`` field gives the PPP protocol
421 number for the protocol to be affected, and the ``mode`` field
422 specifies what to do with packets for that protocol:
423
424 ============= ==============================================
425 NPMODE_PASS normal operation, transmit and receive packets
426 NPMODE_DROP silently drop packets for this protocol
427 NPMODE_ERROR drop packets and return an error on transmit
428 NPMODE_QUEUE queue up packets for transmit, drop received
429 packets
430 ============= ==============================================
431
432 At present NPMODE_ERROR and NPMODE_QUEUE have the same effect as
433 NPMODE_DROP.
434
435 * PPPIOCGNPMODE returns the network-protocol mode for a given
436 protocol. The argument should point to an npioctl struct with the
437 ``protocol`` field set to the PPP protocol number for the protocol of
438 interest. On return the ``mode`` field will be set to the network-
439 protocol mode for that protocol.
440
441 * PPPIOCSPASS and PPPIOCSACTIVE set the ``pass`` and ``active`` packet
442 filters. These ioctls are only available if the CONFIG_PPP_FILTER
443 option is selected. The argument should point to a sock_fprog
444 structure (defined in <linux/filter.h>) containing the compiled BPF
445 instructions for the filter. Packets are dropped if they fail the
446 ``pass`` filter; otherwise, if they fail the ``active`` filter they are
447 passed but they do not reset the transmit or receive idle timer.
448
449 * PPPIOCSMRRU enables or disables multilink processing for received
450 packets and sets the multilink MRRU (maximum reconstructed receive
451 unit). The argument should point to an int containing the new MRRU
452 value. If the MRRU value is 0, processing of received multilink
453 fragments is disabled. This ioctl is only available if the
454 CONFIG_PPP_MULTILINK option is selected.
455
456 Last modified: 7-feb-2002
457

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

Generic PPP 계층과 channel 구조

1-41

Paul Mackerras가 2002년 2월 7일 작성한 이 문서는 Linux 2.4의 generic PPP driver 구조를 설명합니다. Generic layer는 PPP 구현에 공통으로 필요한 기능을 제공합니다.

공통 기능에는 `ppp0` 같은 network interface unit, networking code interface, 여러 link에 datagram을 나누고 수신 fragment를 순서대로 결합하는 PPP multilink, `/dev/ppp` character device를 통한 pppd interface가 있습니다.

또한 packet compression/decompression, TCP/IP header compression/decompression, demand dialing과 idle timeout을 위한 network traffic 감지, 단순 packet filtering을 담당합니다.

PPP frame의 실제 송수신은 PPP `channel`이 수행합니다. Channel은 한 machine에서 다른 machine으로 PPP frame을 운반하는 mechanism을 캡슐화합니다. 내부 구현은 복잡해도 generic PPP와의 interface는 frame 송신·수신과 선택적인 ioctl 처리만 필요합니다. Async serial, sync serial, PPP over Ethernet channel 구현이 있습니다.

하나의 PPP network interface unit에 여러 channel을 연결할 수 있어 multilink가 자연스럽게 구현됩니다. Generic layer가 송신 datagram을 channel 사이에 분할하고 수신 시 재결합합니다.

Generic PPP object model
Networking stack / ppp unitGeneric PPP compression·multilinkChannel A: async serial
Generic PPP bundleChannel B: sync serial
Generic PPP bundleChannel C: PPPoE

하나의 unit이 여러 transport channel을 bundle로 묶습니다.

Generic PPP 공통 기능
영역기능
InterfacepppN network device와 networking code 연결
MultilinkFragment 분할·정렬·재조립
Userspace/dev/ppp를 통한 pppd 제어
TransformPacket 및 TCP/IP header 압축
PolicyDemand/idle 감지와 filtering

Transport와 독립적인 처리를 unit 계층에 모읍니다.

.. SPDX-License-Identifier: GPL-2.0

========================================
PPP Generic Driver and Channel Interface
========================================

                           Paul Mackerras
                           paulus@samba.org

                              7 Feb 2002

The generic PPP driver in linux-2.4 provides an implementation of the
functionality which is of use in any PPP implementation, including:

* the network interface unit (ppp0 etc.)
* the interface to the networking code
* PPP multilink: splitting datagrams between multiple links, and
  ordering and combining received fragments
* the interface to pppd, via a /dev/ppp character device
* packet compression and decompression
* TCP/IP header compression and decompression
* detecting network traffic for demand dialling and for idle timeouts
* simple packet filtering

For sending and receiving PPP frames, the generic PPP driver calls on
the services of PPP ``channels``.  A PPP channel encapsulates a
mechanism for transporting PPP frames from one machine to another.  A
PPP channel implementation can be arbitrarily complex internally but
has a very simple interface with the generic PPP code: it merely has
to be able to send PPP frames, receive PPP frames, and optionally
handle ioctl requests.  Currently there are PPP channel
implementations for asynchronous serial ports, synchronous serial
ports, and for PPP over ethernet.

This architecture makes it possible to implement PPP multilink in a
natural and straightforward way, by allowing more than one channel to
be linked to each ppp network interface unit.  The generic layer is
responsible for splitting datagrams on transmit and recombining them
on receive.

PPP channel callback과 generic API

42-96

Generic PPP layer와 channel 사이 type과 function 선언은 `include/linux/ppp_channel.h`에 있습니다. 각 channel은 `ppp_channel.ops`를 통해 두 function을 제공합니다.

`start_xmit()`은 generic layer가 frame을 보낼 때 호출합니다. Flow control 때문에 거부할 수 있으며 그때는 0을 반환하고, 다시 받을 수 있게 되면 `ppp_output_wakeup()`을 호출해야 합니다. Generic layer가 거부된 frame의 전송을 다시 시도합니다. Frame을 수락하면 1을 반환합니다.

`ioctl()`은 `/dev/ppp` instance가 channel에 bind된 상태에서 userspace가 ioctl system call을 할 때 channel 동작을 제어합니다. 일반적으로 pppd가 사용합니다.

Generic layer가 channel에 제공하는 함수는 일곱 개입니다. `ppp_register_channel()`은 channel 생성과 존재를 알리고, `ppp_unregister_channel()`은 제거를 알립니다. 예를 들어 serial port에 `PPPDISC` line discipline을 지정하면 `ppp_async`가 등록하고 hangup을 감지하면 해제합니다.

`ppp_output_wakeup()`은 이전에 `start_xmit()`을 거부한 channel이 다시 packet을 받을 수 있을 때 호출합니다. `ppp_input()`은 완전한 PPP frame을 수신했을 때, `ppp_input_error()`는 FCS error 등으로 frame 손실·drop을 감지했을 때 호출합니다.

`ppp_channel_index()`는 generic layer가 할당한 channel index를 반환합니다. Userspace가 `/dev/ppp` instance를 channel에 attach할 때 필요하므로 channel은 ioctl 같은 방법으로 index를 userspace에 전달해야 합니다. `ppp_unit_number()`는 연결된 PPP interface unit 번호를 반환하며 연결되지 않았으면 -1입니다.

Channel API 계약
방향Function의미
Channel → genericops.start_xmit수락 1, flow-control 거부 0
Channel → genericops.ioctlChannel-specific userspace 제어
Generic APIppp_register_channel / unregisterChannel 수명 주기
Generic APIppp_output_wakeup송신 재개 알림
Generic APIppp_input / ppp_input_errorFrame 수신 / 손실 통지
Generic APIppp_channel_index / ppp_unit_numberChannel·unit 식별

Channel 제공 callback과 generic 제공 function을 구분합니다.

Flow-control 재시도
Generic start_xmit(frame)Channel이 0 반환Frame 보관Channel ppp_output_wakeupstart_xmit 재시도

Generic layer 자체에는 timeout·retransmission logic이 없습니다.

PPP channel API
---------------

See include/linux/ppp_channel.h for the declaration of the types and
functions used to communicate between the generic PPP layer and PPP
channels.

Each channel has to provide two functions to the generic PPP layer,
via the ppp_channel.ops pointer:

* start_xmit() is called by the generic layer when it has a frame to
  send.  The channel has the option of rejecting the frame for
  flow-control reasons.  In this case, start_xmit() should return 0
  and the channel should call the ppp_output_wakeup() function at a
  later time when it can accept frames again, and the generic layer
  will then attempt to retransmit the rejected frame(s).  If the frame
  is accepted, the start_xmit() function should return 1.

* ioctl() provides an interface which can be used by a user-space
  program to control aspects of the channel's behaviour.  This
  procedure will be called when a user-space program does an ioctl
  system call on an instance of /dev/ppp which is bound to the
  channel.  (Usually it would only be pppd which would do this.)

The generic PPP layer provides seven functions to channels:

* ppp_register_channel() is called when a channel has been created, to
  notify the PPP generic layer of its presence.  For example, setting
  a serial port to the PPPDISC line discipline causes the ppp_async
  channel code to call this function.

* ppp_unregister_channel() is called when a channel is to be
  destroyed.  For example, the ppp_async channel code calls this when
  a hangup is detected on the serial port.

* ppp_output_wakeup() is called by a channel when it has previously
  rejected a call to its start_xmit function, and can now accept more
  packets.

* ppp_input() is called by a channel when it has received a complete
  PPP frame.

* ppp_input_error() is called by a channel when it has detected that a
  frame has been lost or dropped (for example, because of a FCS (frame
  check sequence) error).

* ppp_channel_index() returns the channel index assigned by the PPP
  generic layer to this channel.  The channel should provide some way
  (e.g. an ioctl) to transmit this back to user-space, as user-space
  will need it to attach an instance of /dev/ppp to this channel.

* ppp_unit_number() returns the unit number of the ppp network
  interface to which this channel is connected, or -1 if the channel
  is not connected.

Discovery, frame 형식과 ppp_channel

97-147

Channel을 generic layer에 연결하는 과정은 generic layer가 아니라 channel code가 시작합니다. Channel은 generic PPP와 독립적으로 userspace process가 제어할 방법을 가져야 합니다. `ppp_async`에서는 serial port file descriptor가 그 역할을 합니다.

Userspace process는 먼저 하위 communication medium을 초기화하고 PPP를 사용할 준비를 합니다. Async tty라면 speed와 mode 설정, modem command, remote system에서 PPP service를 시작하기 위한 대화가 포함될 수 있습니다. 이 과정을 `discovery`라고 합니다.

Discovery 뒤 userspace가 medium을 PPP channel로 전환하고 generic layer에 등록하게 합니다. Channel은 할당받은 channel number를 userspace에 보고합니다. 이후 pppd의 PPP negotiation code가 `/dev/ppp`를 통해 channel에 접근하여 협상을 수행합니다.

Generic layer 경계에서 PPP frame은 skbuff에 저장되고 2-byte PPP protocol number로 시작합니다. Async PPP에서 선택적으로 쓰는 `0xff` address byte와 `0x03` control byte는 포함하지 않습니다. Control character escaping, FCS, framing character도 포함하지 않으며 medium에 필요하면 channel code가 처리합니다.

따라서 `start_xmit()`에 전달되는 skbuff와 `ppp_input()`에 넘기는 skbuff는 2-byte protocol number와 data만 가져야 합니다.

Channel은 자신을 나타내는 `struct ppp_channel` instance를 제공하며 `private` field는 자유롭게 쓸 수 있습니다. `ppp_register_channel()` 전에 `mtu`와 `hdrlen`을 초기화하고 `ppp_unregister_channel()`이 반환할 때까지 바꾸지 않습니다. `mtu`는 2-byte protocol number를 제외한 data 부분의 최대 크기입니다.

송신 skbuff 앞쪽에 여유 공간이 필요하면 `hdrlen`을 필요한 headroom으로 설정합니다. Generic layer가 이를 제공하려고 하지만 channel도 충분한지 확인하고 부족하면 skbuff를 복사해야 합니다. 수신 시 `ppp_input()`에 넘기는 skbuff에 최소 2byte headroom을 주면 필수는 아니지만 더 효율적입니다.

Channel discovery와 pppd 인계
Userspace가 tty/modem 준비Remote PPP service discoveryMedium을 PPP channel로 전환ppp_register_channelChannel index 보고pppd가 /dev/ppp로 negotiation

하위 medium 준비부터 PPP negotiation까지의 순서입니다.

Generic 경계의 PPP skbuff
포함제외
2-byte PPP protocol number0xff address byte
PPP data0x03 control byte
Channel이 확보한 hdrlen headroomEscaping, FCS, framing character

Medium-specific framing은 channel 책임입니다.

Connecting a channel to the ppp generic layer is initiated from the
channel code, rather than from the generic layer.  The channel is
expected to have some way for a user-level process to control it
independently of the ppp generic layer.  For example, with the
ppp_async channel, this is provided by the file descriptor to the
serial port.

Generally a user-level process will initialize the underlying
communications medium and prepare it to do PPP.  For example, with an
async tty, this can involve setting the tty speed and modes, issuing
modem commands, and then going through some sort of dialog with the
remote system to invoke PPP service there.  We refer to this process
as ``discovery``.  Then the user-level process tells the medium to
become a PPP channel and register itself with the generic PPP layer.
The channel then has to report the channel number assigned to it back
to the user-level process.  From that point, the PPP negotiation code
in the PPP daemon (pppd) can take over and perform the PPP
negotiation, accessing the channel through the /dev/ppp interface.

At the interface to the PPP generic layer, PPP frames are stored in
skbuff structures and start with the two-byte PPP protocol number.
The frame does *not* include the 0xff ``address`` byte or the 0x03
``control`` byte that are optionally used in async PPP.  Nor is there
any escaping of control characters, nor are there any FCS or framing
characters included.  That is all the responsibility of the channel
code, if it is needed for the particular medium.  That is, the skbuffs
presented to the start_xmit() function contain only the 2-byte
protocol number and the data, and the skbuffs presented to ppp_input()
must be in the same format.

The channel must provide an instance of a ppp_channel struct to
represent the channel.  The channel is free to use the ``private`` field
however it wishes.  The channel should initialize the ``mtu`` and
``hdrlen`` fields before calling ppp_register_channel() and not change
them until after ppp_unregister_channel() returns.  The ``mtu`` field
represents the maximum size of the data part of the PPP frames, that
is, it does not include the 2-byte protocol number.

If the channel needs some headroom in the skbuffs presented to it for
transmission (i.e., some space free in the skbuff data area before the
start of the PPP frame), it should set the ``hdrlen`` field of the
ppp_channel struct to the amount of headroom required.  The generic
PPP layer will attempt to provide that much headroom but the channel
should still check if there is sufficient headroom and copy the skbuff
if there isn't.

On the input side, channels should ideally provide at least 2 bytes of
headroom in the skbuffs presented to ppp_input().  The generic PPP
code does not require this but will be more efficient if this is done.

SMP locking과 호출 context 보장

195-249

Generic PPP layer는 SMP-safe하게 설계되었고 internal data structure 접근에 필요한 lock을 사용합니다. `ppp_channel` storage는 channel이 제공하므로 channel 쪽에서 storage의 존재와 유효성을 보장하는 locking을 제공해야 합니다.

`ppp_channel` object는 `ppp_register_channel()` 호출 시점부터 `ppp_unregister_channel()`이 반환한 뒤까지 존재해야 합니다. Unregister를 호출할 때 해당 channel의 `ppp_input`, `ppp_input_error`, `ppp_output_wakeup`, `ppp_channel_index`, `ppp_unit_number` 안에 실행 중인 thread가 없어야 합니다.

Register와 unregister는 process context에서 호출해야 하며 interrupt 또는 softirq/BH context에서는 호출할 수 없습니다. 나머지 generic function은 softirq/BH level에서 호출할 수 있지만 hardware interrupt handler에서는 호출하면 안 됩니다.

Generic layer는 channel `start_xmit()`을 softirq/BH level에서 호출할 수 있지만 interrupt level에서는 호출하지 않습니다. 따라서 `start_xmit()`은 block할 수 없습니다. Channel `ioctl()`은 process context에서만 호출합니다.

Generic layer는 같은 channel의 `start_xmit()` 또는 `ioctl()`이 이미 실행 중일 때 같은 function을 다시 호출하지 않습니다. `ppp_unregister_channel()`이 반환할 때에는 generic layer가 호출한 해당 channel의 `start_xmit()`·`ioctl()`을 실행 중인 thread가 없으며 이후에도 두 function을 호출하지 않습니다.

SMP 호출 context
Function / 단계허용 context동시성 규칙
register / unregisterProcess onlyObject 수명과 active generic API call 정리
ppp_input 등Process 또는 softirq/BHHardware IRQ 금지
channel start_xmitGeneric이 softirq/BH에서 호출 가능Block 금지, 같은 channel 재진입 없음
channel ioctlProcess only같은 channel 재진입 없음
unregister 반환 후N/Astart_xmit·ioctl 실행/후속 호출 없음

Channel이 지켜야 할 규칙과 generic layer의 보장입니다.

SMP safety
----------

The PPP generic layer has been designed to be SMP-safe.  Locks are
used around accesses to the internal data structures where necessary
to ensure their integrity.  As part of this, the generic layer
requires that the channels adhere to certain requirements and in turn
provides certain guarantees to the channels.  Essentially the channels
are required to provide the appropriate locking on the ppp_channel
structures that form the basis of the communication between the
channel and the generic layer.  This is because the channel provides
the storage for the ppp_channel structure, and so the channel is
required to provide the guarantee that this storage exists and is
valid at the appropriate times.

The generic layer requires these guarantees from the channel:

* The ppp_channel object must exist from the time that
  ppp_register_channel() is called until after the call to
  ppp_unregister_channel() returns.

* No thread may be in a call to any of ppp_input(), ppp_input_error(),
  ppp_output_wakeup(), ppp_channel_index() or ppp_unit_number() for a
  channel at the time that ppp_unregister_channel() is called for that
  channel.

* ppp_register_channel() and ppp_unregister_channel() must be called
  from process context, not interrupt or softirq/BH context.

* The remaining generic layer functions may be called at softirq/BH
  level but must not be called from a hardware interrupt handler.

* The generic layer may call the channel start_xmit() function at
  softirq/BH level but will not call it at interrupt level.  Thus the
  start_xmit() function may not block.

* The generic layer will only call the channel ioctl() function in
  process context.

The generic layer provides these guarantees to the channels:

* The generic layer will not call the start_xmit() function for a
  channel while any thread is already executing in that function for
  that channel.

* The generic layer will not call the ioctl() function for a channel
  while any thread is already executing in that function for that
  channel.

* By the time a call to ppp_unregister_channel() returns, no thread
  will be executing in a call from the generic layer to that channel's
  start_xmit() or ioctl() function, and the generic layer will not
  call either of those functions subsequently.

/dev/ppp instance와 unit·channel

250-284

Generic PPP layer는 pppd가 PPP interface unit과 channel을 제어하는 `/dev/ppp` character device를 제공합니다. Device node는 하나지만 open instance는 각각 독립적으로 동작하며 PPP unit 또는 PPP channel에 attach할 수 있습니다.

각 open instance의 `file->private_data`가 별도 object를 가리켜 Solaris clone open과 비슷한 효과를 냅니다. `/dev`에 수백 개 device 이름을 만들지 않고도 임의 개수의 PPP interface와 channel을 제어할 수 있습니다.

`/dev/ppp`를 열면 처음에는 unattached인 새 instance가 생깁니다. Ioctl로 기존 unit, 새로 만든 unit 또는 기존 channel에 attach합니다. Unit에 attach된 instance는 `read()`, `write()`, 필요하면 `poll()`로 PPP control frame을 주고받습니다. Channel에 attach된 instance도 그 channel에서 PPP frame을 주고받을 수 있습니다.

Multilink에서 unit은 bundle이고 channel은 개별 physical link입니다. Unit에 write한 PPP frame은 bundle-level compression과 link 사이 fragmentation을 거칩니다. Channel에 직접 write한 frame은 multilink header 없이 그대로 그 channel에 전송됩니다.

Channel은 처음에는 어떤 unit에도 attach되지 않습니다. 이 상태에서는 PPP negotiation에는 쓸 수 있지만 data packet 전송에는 쓸 수 없습니다. Ioctl로 PPP unit에 연결하면 그 unit의 data packet 송수신에 참여합니다.

/dev/ppp open instance 상태
open /dev/pppUnattached instance새 unit 또는 기존 unit attachBundle control·data
Unattached instanceExisting channel attachPPP negotiationUnit에 connectData link 참여

하나의 device node에서 instance별 attach 대상을 분리합니다.

Unit write와 channel write
Write 대상처리
PPP unitBundle compression + multilink fragmentation
PPP channel해당 link로 그대로 전송, multilink header 없음

Multilink 처리 경계가 다릅니다.

Interface to pppd
-----------------

The PPP generic layer exports a character device interface called
/dev/ppp.  This is used by pppd to control PPP interface units and
channels.  Although there is only one /dev/ppp, each open instance of
/dev/ppp acts independently and can be attached either to a PPP unit
or a PPP channel.  This is achieved using the file->private_data field
to point to a separate object for each open instance of /dev/ppp.  In
this way an effect similar to Solaris' clone open is obtained,
allowing us to control an arbitrary number of PPP interfaces and
channels without having to fill up /dev with hundreds of device names.

When /dev/ppp is opened, a new instance is created which is initially
unattached.  Using an ioctl call, it can then be attached to an
existing unit, attached to a newly-created unit, or attached to an
existing channel.  An instance attached to a unit can be used to send
and receive PPP control frames, using the read() and write() system
calls, along with poll() if necessary.  Similarly, an instance
attached to a channel can be used to send and receive PPP frames on
that channel.

In multilink terms, the unit represents the bundle, while the channels
represent the individual physical links.  Thus, a PPP frame sent by a
write to the unit (i.e., to an instance of /dev/ppp attached to the
unit) will be subject to bundle-level compression and to fragmentation
across the individual links (if multilink is in use).  In contrast, a
PPP frame sent by a write to the channel will be sent as-is on that
channel, without any multilink header.

A channel is not initially attached to any unit.  In this state it can
be used for PPP negotiation but not for the transfer of data packets.
It can then be connected to a PPP unit with an ioctl call, which
makes it available to send and receive data packets for that unit.

Unattached·channel ioctl과 bridging

285-334

사용 가능한 `/dev/ppp` ioctl은 instance가 unattached인지, PPP interface에 attach되었는지, PPP channel에 attach되었는지에 따라 달라집니다.

Unattached instance의 `PPPIOCNEWUNIT`은 새 PPP interface를 만들고 이 instance를 owner로 지정합니다. Argument는 원하는 unit 번호를 담은 int를 가리키며 0 이상이면 그 번호, -1이면 가장 낮은 미사용 번호를 할당합니다. Owner instance를 닫으면 interface도 종료됩니다.

`PPPIOCATTACH`는 기존 PPP interface unit 번호에 attach하지만 owner가 되지는 않습니다. `PPPIOCATTCHAN`은 channel 번호로 기존 PPP channel에 attach합니다.

Channel-attached instance의 `PPPIOCCONNECT`는 channel을 PPP interface에 연결합니다. 이미 연결되어 있으면 `EINVAL`, 요청 unit이 없으면 `ENXIO`입니다. `PPPIOCDISCONN`은 unit에서 분리하며 연결되어 있지 않으면 `EINVAL`입니다.

`PPPIOCBRIDGECHAN`은 두 channel을 bridge합니다. 한 channel에서 `ppp_input()`으로 들어온 frame이 bridge 상대에게 전달되어, 예를 들어 PPPoE frame을 PPPoL2TP session으로 넘길 수 있습니다. Bridging은 정상 `ppp_input()` 경로를 끊으므로 channel은 동시에 bridge와 unit 양쪽에 속할 수 없습니다. 이미 bridge 또는 unit에 속하면 `EALREADY`, 대상 channel이 없으면 `ENXIO`입니다.

`PPPIOCUNBRIDGECHAN`은 channel pair bridge를 해제하며 bridge 구성원이 아니면 `EINVAL`입니다. 그 밖의 ioctl command는 channel의 `ioctl()` function으로 전달됩니다.

Attach 상태별 ioctl
상태Ioctl결과
UnattachedPPPIOCNEWUNIT새 unit 생성 및 owner
UnattachedPPPIOCATTACH기존 unit attach, owner 아님
UnattachedPPPIOCATTCHAN기존 channel attach
ChannelPPPIOCCONNECT / DISCONNUnit 연결 / 분리
ChannelPPPIOCBRIDGECHAN / UNBRIDGECHANChannel pair bridge / 해제

Instance state가 허용 command를 결정합니다.

Channel bridge
Channel A ppp_inputBridgeChannel B onward transmission
Channel in bridge동시에 PPP unit 참여 불가

Unit data path 대신 두 transport channel 사이에서 frame을 전환합니다.

The ioctl calls which are available on an instance of /dev/ppp depend
on whether it is unattached, attached to a PPP interface, or attached
to a PPP channel.  The ioctl calls which are available on an
unattached instance are:

* PPPIOCNEWUNIT creates a new PPP interface and makes this /dev/ppp
  instance the "owner" of the interface.  The argument should point to
  an int which is the desired unit number if >= 0, or -1 to assign the
  lowest unused unit number.  Being the owner of the interface means
  that the interface will be shut down if this instance of /dev/ppp is
  closed.

* PPPIOCATTACH attaches this instance to an existing PPP interface.
  The argument should point to an int containing the unit number.
  This does not make this instance the owner of the PPP interface.

* PPPIOCATTCHAN attaches this instance to an existing PPP channel.
  The argument should point to an int containing the channel number.

The ioctl calls available on an instance of /dev/ppp attached to a
channel are:

* PPPIOCCONNECT connects this channel to a PPP interface.  The
  argument should point to an int containing the interface unit
  number.  It will return an EINVAL error if the channel is already
  connected to an interface, or ENXIO if the requested interface does
  not exist.

* PPPIOCDISCONN disconnects this channel from the PPP interface that
  it is connected to.  It will return an EINVAL error if the channel
  is not connected to an interface.

* PPPIOCBRIDGECHAN bridges a channel with another. The argument should
  point to an int containing the channel number of the channel to bridge
  to. Once two channels are bridged, frames presented to one channel by
  ppp_input() are passed to the bridge instance for onward transmission.
  This allows frames to be switched from one channel into another: for
  example, to pass PPPoE frames into a PPPoL2TP session. Since channel
  bridging interrupts the normal ppp_input() path, a given channel may
  not be part of a bridge at the same time as being part of a unit.
  This ioctl will return an EALREADY error if the channel is already
  part of a bridge or unit, or ENXIO if the requested channel does not
  exist.

* PPPIOCUNBRIDGECHAN performs the inverse of PPPIOCBRIDGECHAN, unbridging
  a channel pair.  This ioctl will return an EINVAL error if the channel
  does not form part of a bridge.

* All other ioctl commands are passed to the channel ioctl() function.

Interface unit MRU와 control flag

335-378

Interface unit에 attach된 instance에서 `PPPIOCSMRU`는 새 MRU(maximum receive unit)를 int로 설정합니다. `PPPIOCSFLAGS`는 interface 동작을 제어하는 flag를 설정하며 정의는 `<linux/ppp-ioctl.h>`에 있습니다.

`SC_COMP_TCP`는 송신 TCP header compression, `SC_NO_TCP_CCID`는 TCP header compression의 connection-ID compression 비활성화, `SC_REJ_COMP_TCP`는 수신 TCP header decompression 비활성화입니다.

`SC_CCP_OPEN`은 CCP가 열려 있으므로 CCP packet을 검사한다는 뜻이고, `SC_CCP_UP`은 CCP가 올라와 packet을 압축·해제할 수 있다는 뜻입니다. `SC_LOOP_TRAFFIC`은 IP traffic을 pppd로 보냅니다.

`SC_MULTILINK`는 송신 packet에 PPP multilink fragmentation을 켭니다. `SC_MP_SHORTSEQ`는 수신 fragment에서 짧은 multilink sequence number를 기대하고, `SC_MP_XSHORTSEQ`는 짧은 sequence number를 송신합니다. `CONFIG_PPP_MULTILINK`가 선택되지 않으면 이 세 bit는 무시됩니다.

`PPPIOCGFLAGS`는 status/control flag를 반환합니다. 설정 가능한 flag 외에 `SC_COMP_RUN`과 `SC_DECOMP_RUN`은 CCP compressor/decompressor 실행 상태, `SC_DC_ERROR`와 `SC_DC_FERROR`는 decompressor가 감지한 non-fatal/fatal error를 뜻할 수 있습니다.

PPP unit flag
Flag의미
SC_COMP_TCP / SC_REJ_COMP_TCP송신 TCP header 압축 / 수신 해제 거부
SC_NO_TCP_CCIDConnection-ID 압축 비활성화
SC_CCP_OPEN / SC_CCP_UPCCP 검사 / 압축 동작 가능
SC_LOOP_TRAFFICIP traffic을 pppd로 전달
SC_MULTILINK송신 multilink fragmentation
SC_MP_SHORTSEQ / SC_MP_XSHORTSEQ수신 / 송신 short sequence
SC_COMP_RUN / SC_DECOMP_RUNCompressor / decompressor 실행 상태
SC_DC_ERROR / SC_DC_FERRORNon-fatal / fatal decompression error

Compression·CCP·multilink 제어와 상태입니다.

The ioctl calls that are available on an instance that is attached to
an interface unit are:

* PPPIOCSMRU sets the MRU (maximum receive unit) for the interface.
  The argument should point to an int containing the new MRU value.

* PPPIOCSFLAGS sets flags which control the operation of the
  interface.  The argument should be a pointer to an int containing
  the new flags value.  The bits in the flags value that can be set
  are:

        ================        ========================================
        SC_COMP_TCP                enable transmit TCP header compression
        SC_NO_TCP_CCID                disable connection-id compression for
                                TCP header compression
        SC_REJ_COMP_TCP                disable receive TCP header decompression
        SC_CCP_OPEN                Compression Control Protocol (CCP) is
                                open, so inspect CCP packets
        SC_CCP_UP                CCP is up, may (de)compress packets
        SC_LOOP_TRAFFIC                send IP traffic to pppd
        SC_MULTILINK                enable PPP multilink fragmentation on
                                transmitted packets
        SC_MP_SHORTSEQ                expect short multilink sequence
                                numbers on received multilink fragments
        SC_MP_XSHORTSEQ                transmit short multilink sequence nos.
        ================        ========================================

  The values of these flags are defined in <linux/ppp-ioctl.h>.  Note
  that the values of the SC_MULTILINK, SC_MP_SHORTSEQ and
  SC_MP_XSHORTSEQ bits are ignored if the CONFIG_PPP_MULTILINK option
  is not selected.

* PPPIOCGFLAGS returns the value of the status/control flags for the
  interface unit.  The argument should point to an int where the ioctl
  will store the flags value.  As well as the values listed above for
  PPPIOCSFLAGS, the following bits may be set in the returned value:

        ================        =========================================
        SC_COMP_RUN                CCP compressor is running
        SC_DECOMP_RUN                CCP decompressor is running
        SC_DC_ERROR                CCP decompressor detected non-fatal error
        SC_DC_FERROR                CCP decompressor detected fatal error
        ================        =========================================

Compression, idle, NPMODE와 debug ioctl

379-440

`PPPIOCSCOMPRESS`는 packet compression 또는 decompression parameter를 설정합니다. `<linux/ppp-ioctl.h>`의 `ppp_option_data`가 compression method와 parameter를 담은 CCP option memory block의 pointer/length pair를 가집니다. `transmit`이 0이면 receive path, 그 밖의 값이면 transmit path에 적용됩니다.

`PPPIOCGUNIT`은 interface unit 번호를 반환합니다. `PPPIOCSDEBUG`는 debug flag의 최하위 bit만 사용하며 1이면 generic layer가 일부 debug message를 출력합니다. Generic PPP code 자체를 debugging하기 위한 것으로 PPP 연결 실패 원인 분석에는 대체로 도움이 되지 않습니다. `PPPIOCGDEBUG`는 debug flag를 반환합니다.

`PPPIOCGIDLE`은 마지막 data packet 송신·수신 이후의 시간을 초 단위로 `<linux/ppp_defs.h>`의 `ppp_idle`에 반환합니다. `CONFIG_PPP_FILTER`가 활성화되면 `active` filter를 통과하는 packet만 idle timer를 reset합니다. Userspace가 32-bit 또는 64-bit `time_t` second를 기대하는 경우를 위해 두 command version이 있습니다.

`PPPIOCSMAXCID`는 TCP header compressor와 decompressor의 최대 connection-ID와 slot 수를 설정합니다. Argument int의 하위 16bit가 compressor 최대 ID이고, 상위 16bit가 0이 아니면 decompressor 최대 ID입니다. 상위가 0이면 decompressor 최대 ID는 15입니다.

`PPPIOCSNPMODE`는 `<linux/ppp-ioctl.h>`의 `npioctl`로 특정 PPP network protocol의 mode를 설정합니다. `protocol`은 대상 PPP protocol number이고 `mode`는 packet 처리 방식입니다.

`NPMODE_PASS`는 정상 송수신, `NPMODE_DROP`은 조용히 drop, `NPMODE_ERROR`는 drop 후 송신 error 반환, `NPMODE_QUEUE`는 송신 packet을 queue하고 수신 packet을 drop합니다. 현재 구현에서 ERROR와 QUEUE는 DROP과 같은 효과입니다. `PPPIOCGNPMODE`는 지정 protocol의 현재 mode를 반환합니다.

Interface unit ioctl
Ioctl역할
PPPIOCSCOMPRESSCCP compression/decompression option
PPPIOCGUNITUnit number 조회
PPPIOCSDEBUG / PPPIOCGDEBUGGeneric layer debug flag 설정·조회
PPPIOCGIDLE마지막 active data 이후 idle seconds
PPPIOCSMAXCIDTCP header compressor/decompressor slot
PPPIOCSNPMODE / PPPIOCGNPMODEProtocol별 PASS·DROP·ERROR·QUEUE mode

Compression과 상태·protocol policy를 설정합니다.

Network protocol mode
Mode동작
NPMODE_PASS정상 송신·수신
NPMODE_DROP조용히 drop
NPMODE_ERRORDrop하고 송신 error 반환
NPMODE_QUEUE송신 queue, 수신 drop

현재 ERROR와 QUEUE는 DROP과 같은 동작입니다.

* PPPIOCSCOMPRESS sets the parameters for packet compression or
  decompression.  The argument should point to a ppp_option_data
  structure (defined in <linux/ppp-ioctl.h>), which contains a
  pointer/length pair which should describe a block of memory
  containing a CCP option specifying a compression method and its
  parameters.  The ppp_option_data struct also contains a ``transmit``
  field.  If this is 0, the ioctl will affect the receive path,
  otherwise the transmit path.

* PPPIOCGUNIT returns, in the int pointed to by the argument, the unit
  number of this interface unit.

* PPPIOCSDEBUG sets the debug flags for the interface to the value in
  the int pointed to by the argument.  Only the least significant bit
  is used; if this is 1 the generic layer will print some debug
  messages during its operation.  This is only intended for debugging
  the generic PPP layer code; it is generally not helpful for working
  out why a PPP connection is failing.

* PPPIOCGDEBUG returns the debug flags for the interface in the int
  pointed to by the argument.

* PPPIOCGIDLE returns the time, in seconds, since the last data
  packets were sent and received.  The argument should point to a
  ppp_idle structure (defined in <linux/ppp_defs.h>).  If the
  CONFIG_PPP_FILTER option is enabled, the set of packets which reset
  the transmit and receive idle timers is restricted to those which
  pass the ``active`` packet filter.
  Two versions of this command exist, to deal with user space
  expecting times as either 32-bit or 64-bit time_t seconds.

* PPPIOCSMAXCID sets the maximum connection-ID parameter (and thus the
  number of connection slots) for the TCP header compressor and
  decompressor.  The lower 16 bits of the int pointed to by the
  argument specify the maximum connection-ID for the compressor.  If
  the upper 16 bits of that int are non-zero, they specify the maximum
  connection-ID for the decompressor, otherwise the decompressor's
  maximum connection-ID is set to 15.

* PPPIOCSNPMODE sets the network-protocol mode for a given network
  protocol.  The argument should point to an npioctl struct (defined
  in <linux/ppp-ioctl.h>).  The ``protocol`` field gives the PPP protocol
  number for the protocol to be affected, and the ``mode`` field
  specifies what to do with packets for that protocol:

        =============        ==============================================
        NPMODE_PASS        normal operation, transmit and receive packets
        NPMODE_DROP        silently drop packets for this protocol
        NPMODE_ERROR        drop packets and return an error on transmit
        NPMODE_QUEUE        queue up packets for transmit, drop received
                        packets
        =============        ==============================================

  At present NPMODE_ERROR and NPMODE_QUEUE have the same effect as
  NPMODE_DROP.

* PPPIOCGNPMODE returns the network-protocol mode for a given
  protocol.  The argument should point to an npioctl struct with the
  ``protocol`` field set to the PPP protocol number for the protocol of
  interest.  On return the ``mode`` field will be set to the network-
  protocol mode for that protocol.

BPF filter와 multilink MRRU

441-456

`PPPIOCSPASS`와 `PPPIOCSACTIVE`는 각각 `pass`와 `active` packet filter를 설정하며 `CONFIG_PPP_FILTER`가 선택된 경우에만 사용할 수 있습니다. Argument는 `<linux/filter.h>`의 `sock_fprog`이며 compiled BPF instruction을 담습니다.

`pass` filter를 통과하지 못한 packet은 drop됩니다. `pass`는 통과했지만 `active` filter를 통과하지 못한 packet은 전달되지만 transmit 또는 receive idle timer를 reset하지 않습니다.

`PPPIOCSMRRU`는 수신 multilink 처리의 활성 여부와 MRRU(maximum reconstructed receive unit)를 설정합니다. 값이 0이면 수신 multilink fragment 처리를 비활성화합니다. `CONFIG_PPP_MULTILINK`가 선택된 경우에만 사용할 수 있습니다.

문서의 마지막 수정일은 2002년 2월 7일입니다.

PPP filter 판정
Packetpass filter 실패Drop
Packetpass 성공active 실패전달, idle timer 유지
Packetpass·active 성공전달, idle timer reset

Pass 여부와 active 여부가 전달과 idle timer 갱신을 나눕니다.

* PPPIOCSPASS and PPPIOCSACTIVE set the ``pass`` and ``active`` packet
  filters.  These ioctls are only available if the CONFIG_PPP_FILTER
  option is selected.  The argument should point to a sock_fprog
  structure (defined in <linux/filter.h>) containing the compiled BPF
  instructions for the filter.  Packets are dropped if they fail the
  ``pass`` filter; otherwise, if they fail the ``active`` filter they are
  passed but they do not reset the transmit or receive idle timer.

* PPPIOCSMRRU enables or disables multilink processing for received
  packets and sets the multilink MRRU (maximum reconstructed receive
  unit).  The argument should point to an int containing the new MRRU
  value.  If the MRRU value is 0, processing of received multilink
  fragments is disabled.  This ioctl is only available if the
  CONFIG_PPP_MULTILINK option is selected.

Last modified: 7-feb-2002