1 /* 2 * PPP Line Quality Monitoring (LQM) Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: lqr.c,v 1.29 1998/06/27 23:48:49 brian Exp $ 21 * 22 * o LQR based on RFC1333 23 * 24 * TODO: 25 * o LQM policy 26 * o Allow user to configure LQM method and interval. 27 */ 28 29 #include <sys/types.h> 30 #include <sys/un.h> 31 32 #include <string.h> 33 #include <termios.h> 34 35 #include "mbuf.h" 36 #include "log.h" 37 #include "defs.h" 38 #include "timer.h" 39 #include "fsm.h" 40 #include "lcpproto.h" 41 #include "lcp.h" 42 #include "lqr.h" 43 #include "hdlc.h" 44 #include "async.h" 45 #include "throughput.h" 46 #include "ccp.h" 47 #include "link.h" 48 #include "descriptor.h" 49 #include "physical.h" 50 #include "mp.h" 51 #include "chat.h" 52 #include "auth.h" 53 #include "chap.h" 54 #include "command.h" 55 #include "cbcp.h" 56 #include "datalink.h" 57 58 struct echolqr { 59 u_int32_t magic; 60 u_int32_t signature; 61 u_int32_t sequence; 62 }; 63 64 #define SIGNATURE 0x594e4f54 65 66 static void 67 SendEchoReq(struct lcp *lcp) 68 { 69 struct hdlc *hdlc = &link2physical(lcp->fsm.link)->hdlc; 70 struct echolqr echo; 71 72 echo.magic = htonl(lcp->want_magic); 73 echo.signature = htonl(SIGNATURE); 74 echo.sequence = htonl(hdlc->lqm.echo.seq_sent); 75 fsm_Output(&lcp->fsm, CODE_ECHOREQ, hdlc->lqm.echo.seq_sent++, 76 (u_char *)&echo, sizeof echo); 77 } 78 79 void 80 lqr_RecvEcho(struct fsm *fp, struct mbuf * bp) 81 { 82 struct hdlc *hdlc = &link2physical(fp->link)->hdlc; 83 struct echolqr *lqr; 84 u_int32_t seq; 85 86 if (mbuf_Length(bp) == sizeof(struct echolqr)) { 87 lqr = (struct echolqr *) MBUF_CTOP(bp); 88 if (ntohl(lqr->signature) == SIGNATURE) { 89 seq = ntohl(lqr->sequence); 90 /* careful not to update lqm.echo.seq_recv with older values */ 91 if ((hdlc->lqm.echo.seq_recv > (u_int32_t)0 - 5 && seq < 5) || 92 (hdlc->lqm.echo.seq_recv <= (u_int32_t)0 - 5 && 93 seq > hdlc->lqm.echo.seq_recv)) 94 hdlc->lqm.echo.seq_recv = seq; 95 } else 96 log_Printf(LogWARN, "lqr_RecvEcho: Got sig 0x%08lx, not 0x%08lx !\n", 97 (u_long)ntohl(lqr->signature), (u_long)SIGNATURE); 98 } else 99 log_Printf(LogWARN, "lqr_RecvEcho: Got packet size %d, expecting %ld !\n", 100 mbuf_Length(bp), (long)sizeof(struct echolqr)); 101 } 102 103 void 104 lqr_ChangeOrder(struct lqrdata * src, struct lqrdata * dst) 105 { 106 u_int32_t *sp, *dp; 107 int n; 108 109 sp = (u_int32_t *) src; 110 dp = (u_int32_t *) dst; 111 for (n = 0; n < sizeof(struct lqrdata) / sizeof(u_int32_t); n++) 112 *dp++ = ntohl(*sp++); 113 } 114 115 static void 116 SendLqrData(struct lcp *lcp) 117 { 118 struct mbuf *bp; 119 120 bp = mbuf_Alloc(sizeof(struct lqrdata), MB_LQR); 121 hdlc_Output(lcp->fsm.link, PRI_LINK, PROTO_LQR, bp); 122 } 123 124 static void 125 SendLqrReport(void *v) 126 { 127 struct lcp *lcp = (struct lcp *)v; 128 struct physical *p = link2physical(lcp->fsm.link); 129 130 timer_Stop(&p->hdlc.lqm.timer); 131 132 if (p->hdlc.lqm.method & LQM_LQR) { 133 if (p->hdlc.lqm.lqr.resent > 5) { 134 /* XXX: Should implement LQM strategy */ 135 log_Printf(LogPHASE, "%s: ** Too many LQR packets lost **\n", 136 lcp->fsm.link->name); 137 log_Printf(LogLQM, "%s: Too many LQR packets lost\n", 138 lcp->fsm.link->name); 139 p->hdlc.lqm.method = 0; 140 datalink_Down(p->dl, CLOSE_NORMAL); 141 } else { 142 SendLqrData(lcp); 143 p->hdlc.lqm.lqr.resent++; 144 } 145 } else if (p->hdlc.lqm.method & LQM_ECHO) { 146 if ((p->hdlc.lqm.echo.seq_sent > 5 && 147 p->hdlc.lqm.echo.seq_sent - 5 > p->hdlc.lqm.echo.seq_recv) || 148 (p->hdlc.lqm.echo.seq_sent <= 5 && 149 p->hdlc.lqm.echo.seq_sent > p->hdlc.lqm.echo.seq_recv + 5)) { 150 log_Printf(LogPHASE, "%s: ** Too many ECHO LQR packets lost **\n", 151 lcp->fsm.link->name); 152 log_Printf(LogLQM, "%s: Too many ECHO LQR packets lost\n", 153 lcp->fsm.link->name); 154 p->hdlc.lqm.method = 0; 155 datalink_Down(p->dl, CLOSE_NORMAL); 156 } else 157 SendEchoReq(lcp); 158 } 159 if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load) 160 timer_Start(&p->hdlc.lqm.timer); 161 } 162 163 void 164 lqr_Input(struct physical *physical, struct mbuf *bp) 165 { 166 int len; 167 168 len = mbuf_Length(bp); 169 if (len != sizeof(struct lqrdata)) 170 log_Printf(LogWARN, "lqr_Input: Got packet size %d, expecting %ld !\n", 171 len, (long)sizeof(struct lqrdata)); 172 else if (!IsAccepted(physical->link.lcp.cfg.lqr) && 173 !(physical->hdlc.lqm.method & LQM_LQR)) { 174 bp->offset -= 2; 175 bp->cnt += 2; 176 lcp_SendProtoRej(physical->hdlc.lqm.owner, MBUF_CTOP(bp), bp->cnt); 177 } else { 178 struct lqrdata *lqr; 179 struct lcp *lcp; 180 u_int32_t lastLQR; 181 182 lqr = (struct lqrdata *)MBUF_CTOP(bp); 183 lcp = physical->hdlc.lqm.owner; 184 if (ntohl(lqr->MagicNumber) != physical->hdlc.lqm.owner->his_magic) 185 log_Printf(LogWARN, "lqr_Input: magic 0x%08lx is wrong," 186 " expecting 0x%08lx\n", 187 (u_long)ntohl(lqr->MagicNumber), 188 (u_long)physical->hdlc.lqm.owner->his_magic); 189 else { 190 /* 191 * Remember our PeerInLQRs, then convert byte order and save 192 */ 193 lastLQR = physical->hdlc.lqm.lqr.peer.PeerInLQRs; 194 195 lqr_ChangeOrder(lqr, &physical->hdlc.lqm.lqr.peer); 196 lqr_Dump(physical->link.name, "Input", &physical->hdlc.lqm.lqr.peer); 197 /* we have received an LQR from peer */ 198 physical->hdlc.lqm.lqr.resent = 0; 199 200 /* 201 * Generate an LQR response if we're not running an LQR timer OR 202 * two successive LQR's PeerInLQRs are the same OR we're not going to 203 * send our next one before the peers max timeout. 204 */ 205 if (physical->hdlc.lqm.timer.load == 0 || 206 !(physical->hdlc.lqm.method & LQM_LQR) || 207 (lastLQR && lastLQR == physical->hdlc.lqm.lqr.peer.PeerInLQRs) || 208 (physical->hdlc.lqm.lqr.peer_timeout && 209 physical->hdlc.lqm.timer.rest * 100 / SECTICKS > 210 physical->hdlc.lqm.lqr.peer_timeout)) 211 SendLqrData(physical->hdlc.lqm.owner); 212 } 213 } 214 mbuf_Free(bp); 215 } 216 217 /* 218 * When LCP is reached to opened state, We'll start LQM activity. 219 */ 220 221 static void 222 lqr_Setup(struct lcp *lcp) 223 { 224 struct physical *physical = link2physical(lcp->fsm.link); 225 226 physical->hdlc.lqm.lqr.resent = 0; 227 physical->hdlc.lqm.echo.seq_sent = 0; 228 physical->hdlc.lqm.echo.seq_recv = 0; 229 memset(&physical->hdlc.lqm.lqr.peer, '\0', 230 sizeof physical->hdlc.lqm.lqr.peer); 231 232 physical->hdlc.lqm.method = LQM_ECHO; 233 if (IsEnabled(lcp->cfg.lqr) && !REJECTED(lcp, TY_QUALPROTO)) 234 physical->hdlc.lqm.method |= LQM_LQR; 235 timer_Stop(&physical->hdlc.lqm.timer); 236 237 physical->hdlc.lqm.lqr.peer_timeout = lcp->his_lqrperiod; 238 if (lcp->his_lqrperiod) 239 log_Printf(LogLQM, "%s: Expecting LQR every %d.%02d secs\n", 240 physical->link.name, lcp->his_lqrperiod / 100, 241 lcp->his_lqrperiod % 100); 242 243 if (lcp->want_lqrperiod) { 244 log_Printf(LogLQM, "%s: Will send %s every %d.%02d secs\n", 245 physical->link.name, 246 physical->hdlc.lqm.method & LQM_LQR ? "LQR" : "ECHO LQR", 247 lcp->want_lqrperiod / 100, lcp->want_lqrperiod % 100); 248 physical->hdlc.lqm.timer.load = lcp->want_lqrperiod * SECTICKS / 100; 249 physical->hdlc.lqm.timer.func = SendLqrReport; 250 physical->hdlc.lqm.timer.name = "lqm"; 251 physical->hdlc.lqm.timer.arg = lcp; 252 } else { 253 physical->hdlc.lqm.timer.load = 0; 254 if (!lcp->his_lqrperiod) 255 log_Printf(LogLQM, "%s: LQR/ECHO LQR not negotiated\n", 256 physical->link.name); 257 } 258 } 259 260 void 261 lqr_Start(struct lcp *lcp) 262 { 263 struct physical *p = link2physical(lcp->fsm.link); 264 265 lqr_Setup(lcp); 266 if (p->hdlc.lqm.timer.load) 267 SendLqrReport(lcp); 268 } 269 270 void 271 lqr_reStart(struct lcp *lcp) 272 { 273 struct physical *p = link2physical(lcp->fsm.link); 274 275 lqr_Setup(lcp); 276 if (p->hdlc.lqm.timer.load) 277 timer_Start(&p->hdlc.lqm.timer); 278 } 279 280 void 281 lqr_StopTimer(struct physical *physical) 282 { 283 timer_Stop(&physical->hdlc.lqm.timer); 284 } 285 286 void 287 lqr_Stop(struct physical *physical, int method) 288 { 289 if (method == LQM_LQR) 290 log_Printf(LogLQM, "%s: Stop sending LQR, Use LCP ECHO instead.\n", 291 physical->link.name); 292 if (method == LQM_ECHO) 293 log_Printf(LogLQM, "%s: Stop sending LCP ECHO.\n", 294 physical->link.name); 295 physical->hdlc.lqm.method &= ~method; 296 if (physical->hdlc.lqm.method) 297 SendLqrReport(physical->hdlc.lqm.owner); 298 else 299 timer_Stop(&physical->hdlc.lqm.timer); 300 } 301 302 void 303 lqr_Dump(const char *link, const char *message, const struct lqrdata *lqr) 304 { 305 if (log_IsKept(LogLQM)) { 306 log_Printf(LogLQM, "%s: %s:\n", link, message); 307 log_Printf(LogLQM, " Magic: %08x LastOutLQRs: %08x\n", 308 lqr->MagicNumber, lqr->LastOutLQRs); 309 log_Printf(LogLQM, " LastOutPackets: %08x LastOutOctets: %08x\n", 310 lqr->LastOutPackets, lqr->LastOutOctets); 311 log_Printf(LogLQM, " PeerInLQRs: %08x PeerInPackets: %08x\n", 312 lqr->PeerInLQRs, lqr->PeerInPackets); 313 log_Printf(LogLQM, " PeerInDiscards: %08x PeerInErrors: %08x\n", 314 lqr->PeerInDiscards, lqr->PeerInErrors); 315 log_Printf(LogLQM, " PeerInOctets: %08x PeerOutLQRs: %08x\n", 316 lqr->PeerInOctets, lqr->PeerOutLQRs); 317 log_Printf(LogLQM, " PeerOutPackets: %08x PeerOutOctets: %08x\n", 318 lqr->PeerOutPackets, lqr->PeerOutOctets); 319 } 320 } 321