2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
4 * Internet Initiative Japan, Inc (IIJ)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/param.h>
34 #include <netinet/in.h>
53 #include "throughput.h"
56 #include "descriptor.h"
72 #define SIGNATURE 0x594e4f54
75 SendEchoReq(struct lcp *lcp)
77 struct hdlc *hdlc = &link2physical(lcp->fsm.link)->hdlc;
80 echo.magic = htonl(lcp->want_magic);
81 echo.signature = htonl(SIGNATURE);
82 echo.sequence = htonl(hdlc->lqm.echo.seq_sent);
83 fsm_Output(&lcp->fsm, CODE_ECHOREQ, hdlc->lqm.echo.seq_sent++,
84 (u_char *)&echo, sizeof echo, MB_ECHOOUT);
88 lqr_RecvEcho(struct fsm *fp, struct mbuf *bp)
90 struct hdlc *hdlc = &link2physical(fp->link)->hdlc;
91 struct lcp *lcp = fsm2lcp(fp);
94 if (m_length(bp) >= sizeof lqr) {
95 m_freem(mbuf_Read(bp, &lqr, sizeof lqr));
97 lqr.magic = ntohl(lqr.magic);
98 lqr.signature = ntohl(lqr.signature);
99 lqr.sequence = ntohl(lqr.sequence);
101 /* Tolerate echo replies with either magic number */
102 if (lqr.magic != 0 && lqr.magic != lcp->his_magic &&
103 lqr.magic != lcp->want_magic) {
104 log_Printf(LogWARN, "%s: lqr_RecvEcho: Bad magic: expected 0x%08x,"
105 " got 0x%08x\n", fp->link->name, lcp->his_magic, lqr.magic);
107 * XXX: We should send a terminate request. But poor implementations may
111 if (lqr.signature == SIGNATURE) {
112 /* careful not to update lqm.echo.seq_recv with older values */
113 if ((hdlc->lqm.echo.seq_recv > (u_int32_t)0 - 5 && lqr.sequence < 5) ||
114 (hdlc->lqm.echo.seq_recv <= (u_int32_t)0 - 5 &&
115 lqr.sequence > hdlc->lqm.echo.seq_recv))
116 hdlc->lqm.echo.seq_recv = lqr.sequence;
118 log_Printf(LogWARN, "lqr_RecvEcho: Got sig 0x%08lx, not 0x%08lx !\n",
119 (u_long)lqr.signature, (u_long)SIGNATURE);
121 log_Printf(LogWARN, "lqr_RecvEcho: Got packet size %d, expecting %ld !\n",
122 m_length(bp), (long)sizeof(struct echolqr));
127 lqr_ChangeOrder(struct lqrdata *src, struct lqrdata *dst)
132 sp = (u_int32_t *) src;
133 dp = (u_int32_t *) dst;
134 for (n = 0; n < sizeof(struct lqrdata) / sizeof(u_int32_t); n++, sp++, dp++)
139 SendLqrData(struct lcp *lcp)
144 extra = proto_WrapperOctets(lcp, PROTO_LQR) +
145 acf_WrapperOctets(lcp, PROTO_LQR);
146 bp = m_get(sizeof(struct lqrdata) + extra, MB_LQROUT);
148 bp->m_offset += extra;
149 link_PushPacket(lcp->fsm.link, bp, lcp->fsm.bundle,
150 LINK_QUEUES(lcp->fsm.link) - 1, PROTO_LQR);
154 SendLqrReport(void *v)
156 struct lcp *lcp = (struct lcp *)v;
157 struct physical *p = link2physical(lcp->fsm.link);
159 timer_Stop(&p->hdlc.lqm.timer);
161 if (p->hdlc.lqm.method & LQM_LQR) {
162 if (p->hdlc.lqm.lqr.resent > 5) {
163 /* XXX: Should implement LQM strategy */
164 log_Printf(LogPHASE, "%s: ** Too many LQR packets lost **\n",
165 lcp->fsm.link->name);
166 log_Printf(LogLQM, "%s: Too many LQR packets lost\n",
167 lcp->fsm.link->name);
168 p->hdlc.lqm.method = 0;
169 datalink_Down(p->dl, CLOSE_NORMAL);
172 p->hdlc.lqm.lqr.resent++;
174 } else if (p->hdlc.lqm.method & LQM_ECHO) {
175 if ((p->hdlc.lqm.echo.seq_sent > 5 &&
176 p->hdlc.lqm.echo.seq_sent - 5 > p->hdlc.lqm.echo.seq_recv) ||
177 (p->hdlc.lqm.echo.seq_sent <= 5 &&
178 p->hdlc.lqm.echo.seq_sent > p->hdlc.lqm.echo.seq_recv + 5)) {
179 log_Printf(LogPHASE, "%s: ** Too many ECHO LQR packets lost **\n",
180 lcp->fsm.link->name);
181 log_Printf(LogLQM, "%s: Too many ECHO LQR packets lost\n",
182 lcp->fsm.link->name);
183 p->hdlc.lqm.method = 0;
184 datalink_Down(p->dl, CLOSE_NORMAL);
188 if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load)
189 timer_Start(&p->hdlc.lqm.timer);
193 lqr_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
195 struct physical *p = link2physical(l);
196 struct lcp *lcp = p->hdlc.lqm.owner;
200 log_Printf(LogERROR, "lqr_Input: Not a physical link - dropped\n");
205 p->hdlc.lqm.lqr.SaveInLQRs++;
208 if (len != sizeof(struct lqrdata))
209 log_Printf(LogWARN, "lqr_Input: Got packet size %d, expecting %ld !\n",
210 len, (long)sizeof(struct lqrdata));
211 else if (!IsAccepted(l->lcp.cfg.lqr) && !(p->hdlc.lqm.method & LQM_LQR)) {
212 bp = m_pullup(proto_Prepend(bp, PROTO_LQR, 0, 0));
213 lcp_SendProtoRej(lcp, MBUF_CTOP(bp), bp->m_len);
219 lqr = (struct lqrdata *)MBUF_CTOP(bp);
220 if (ntohl(lqr->MagicNumber) != lcp->his_magic)
221 log_Printf(LogWARN, "lqr_Input: magic 0x%08lx is wrong,"
222 " expecting 0x%08lx\n",
223 (u_long)ntohl(lqr->MagicNumber), (u_long)lcp->his_magic);
226 * Remember our PeerInLQRs, then convert byte order and save
228 lastLQR = p->hdlc.lqm.lqr.peer.PeerInLQRs;
230 lqr_ChangeOrder(lqr, &p->hdlc.lqm.lqr.peer);
231 lqr_Dump(l->name, "Input", &p->hdlc.lqm.lqr.peer);
232 /* we have received an LQR from peer */
233 p->hdlc.lqm.lqr.resent = 0;
236 * Generate an LQR response if we're not running an LQR timer OR
237 * two successive LQR's PeerInLQRs are the same OR we're not going to
238 * send our next one before the peers max timeout.
240 if (p->hdlc.lqm.timer.load == 0 ||
241 !(p->hdlc.lqm.method & LQM_LQR) ||
242 (lastLQR && lastLQR == p->hdlc.lqm.lqr.peer.PeerInLQRs) ||
243 (p->hdlc.lqm.lqr.peer_timeout &&
244 p->hdlc.lqm.timer.rest * 100 / SECTICKS >
245 p->hdlc.lqm.lqr.peer_timeout))
254 * When LCP is reached to opened state, We'll start LQM activity.
258 lqr_Setup(struct lcp *lcp)
260 struct physical *physical = link2physical(lcp->fsm.link);
262 physical->hdlc.lqm.lqr.resent = 0;
263 physical->hdlc.lqm.echo.seq_sent = 0;
264 physical->hdlc.lqm.echo.seq_recv = 0;
265 memset(&physical->hdlc.lqm.lqr.peer, '\0',
266 sizeof physical->hdlc.lqm.lqr.peer);
268 physical->hdlc.lqm.method = LQM_ECHO;
269 if (IsEnabled(lcp->cfg.lqr) && !REJECTED(lcp, TY_QUALPROTO))
270 physical->hdlc.lqm.method |= LQM_LQR;
271 timer_Stop(&physical->hdlc.lqm.timer);
273 physical->hdlc.lqm.lqr.peer_timeout = lcp->his_lqrperiod;
274 if (lcp->his_lqrperiod)
275 log_Printf(LogLQM, "%s: Expecting LQR every %d.%02d secs\n",
276 physical->link.name, lcp->his_lqrperiod / 100,
277 lcp->his_lqrperiod % 100);
279 if (lcp->want_lqrperiod) {
280 log_Printf(LogLQM, "%s: Will send %s every %d.%02d secs\n",
282 physical->hdlc.lqm.method & LQM_LQR ? "LQR" : "ECHO LQR",
283 lcp->want_lqrperiod / 100, lcp->want_lqrperiod % 100);
284 physical->hdlc.lqm.timer.load = lcp->want_lqrperiod * SECTICKS / 100;
285 physical->hdlc.lqm.timer.func = SendLqrReport;
286 physical->hdlc.lqm.timer.name = "lqm";
287 physical->hdlc.lqm.timer.arg = lcp;
289 physical->hdlc.lqm.timer.load = 0;
290 if (!lcp->his_lqrperiod)
291 log_Printf(LogLQM, "%s: LQR/ECHO LQR not negotiated\n",
292 physical->link.name);
297 lqr_Start(struct lcp *lcp)
299 struct physical *p = link2physical(lcp->fsm.link);
302 if (p->hdlc.lqm.timer.load)
307 lqr_reStart(struct lcp *lcp)
309 struct physical *p = link2physical(lcp->fsm.link);
312 if (p->hdlc.lqm.timer.load)
313 timer_Start(&p->hdlc.lqm.timer);
317 lqr_StopTimer(struct physical *physical)
319 timer_Stop(&physical->hdlc.lqm.timer);
323 lqr_Stop(struct physical *physical, int method)
325 if (method == LQM_LQR)
326 log_Printf(LogLQM, "%s: Stop sending LQR, Use LCP ECHO instead.\n",
327 physical->link.name);
328 if (method == LQM_ECHO)
329 log_Printf(LogLQM, "%s: Stop sending LCP ECHO.\n",
330 physical->link.name);
331 physical->hdlc.lqm.method &= ~method;
332 if (physical->hdlc.lqm.method)
333 SendLqrReport(physical->hdlc.lqm.owner);
335 timer_Stop(&physical->hdlc.lqm.timer);
339 lqr_Dump(const char *link, const char *message, const struct lqrdata *lqr)
341 if (log_IsKept(LogLQM)) {
342 log_Printf(LogLQM, "%s: %s:\n", link, message);
343 log_Printf(LogLQM, " Magic: %08x LastOutLQRs: %08x\n",
344 lqr->MagicNumber, lqr->LastOutLQRs);
345 log_Printf(LogLQM, " LastOutPackets: %08x LastOutOctets: %08x\n",
346 lqr->LastOutPackets, lqr->LastOutOctets);
347 log_Printf(LogLQM, " PeerInLQRs: %08x PeerInPackets: %08x\n",
348 lqr->PeerInLQRs, lqr->PeerInPackets);
349 log_Printf(LogLQM, " PeerInDiscards: %08x PeerInErrors: %08x\n",
350 lqr->PeerInDiscards, lqr->PeerInErrors);
351 log_Printf(LogLQM, " PeerInOctets: %08x PeerOutLQRs: %08x\n",
352 lqr->PeerInOctets, lqr->PeerOutLQRs);
353 log_Printf(LogLQM, " PeerOutPackets: %08x PeerOutOctets: %08x\n",
354 lqr->PeerOutPackets, lqr->PeerOutOctets);
359 lqr_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp,
360 int pri, u_short *proto)
362 struct physical *p = link2physical(l);
366 /* Oops - can't happen :-] */
374 * All octets which are included in the FCS calculation MUST be counted,
375 * including the packet header, the information field, and any padding.
376 * The FCS octets MUST also be counted, and one flag octet per frame
377 * MUST be counted. All other octets (such as additional flag
378 * sequences, and escape bits or octets) MUST NOT be counted.
380 * As we're stacked before the HDLC layer (otherwise HDLC wouldn't be
381 * able to calculate the FCS), we must not forget about these additional
382 * bytes when we're asynchronous.
384 * We're also expecting to be stacked *before* the proto and acf layers.
385 * If we were after these, it makes alignment more of a pain, and we
386 * don't do LQR without these layers.
392 if (!physical_IsSync(p))
393 p->hdlc.lqm.OutOctets += hdlc_WrapperOctets(&l->lcp, *proto);
394 p->hdlc.lqm.OutOctets += acf_WrapperOctets(&l->lcp, *proto) +
395 proto_WrapperOctets(&l->lcp, *proto) + len + 1;
396 p->hdlc.lqm.OutPackets++;
398 if (*proto == PROTO_LQR) {
399 /* Overwrite the entire packet (created in SendLqrData()) */
402 lqr.MagicNumber = p->link.lcp.want_magic;
403 lqr.LastOutLQRs = p->hdlc.lqm.lqr.peer.PeerOutLQRs;
404 lqr.LastOutPackets = p->hdlc.lqm.lqr.peer.PeerOutPackets;
405 lqr.LastOutOctets = p->hdlc.lqm.lqr.peer.PeerOutOctets;
406 lqr.PeerInLQRs = p->hdlc.lqm.lqr.SaveInLQRs;
407 lqr.PeerInPackets = p->hdlc.lqm.SaveInPackets;
408 lqr.PeerInDiscards = p->hdlc.lqm.SaveInDiscards;
409 lqr.PeerInErrors = p->hdlc.lqm.SaveInErrors;
410 lqr.PeerInOctets = p->hdlc.lqm.SaveInOctets;
411 lqr.PeerOutPackets = p->hdlc.lqm.OutPackets;
412 lqr.PeerOutOctets = p->hdlc.lqm.OutOctets;
413 if (p->hdlc.lqm.lqr.peer.LastOutLQRs == p->hdlc.lqm.lqr.OutLQRs) {
415 * only increment if it's the first time or we've got a reply
418 lqr.PeerOutLQRs = ++p->hdlc.lqm.lqr.OutLQRs;
419 lqr_Dump(l->name, "Output", &lqr);
421 lqr.PeerOutLQRs = p->hdlc.lqm.lqr.OutLQRs;
422 lqr_Dump(l->name, "Output (again)", &lqr);
424 lqr_ChangeOrder(&lqr, (struct lqrdata *)MBUF_CTOP(bp));
431 lqr_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto)
434 * We mark the packet as ours but don't do anything 'till it's dispatched
437 if (*proto == PROTO_LQR)
438 m_settype(bp, MB_LQRIN);
443 * Statistics for pulled packets are recorded either in hdlc_PullPacket()
444 * or sync_PullPacket()
447 struct layer lqrlayer = { LAYER_LQR, "lqr", lqr_LayerPush, lqr_LayerPull };