Subject: bin/20066: pppd does not have plugin hooks for LCP state
To: None <gnats-bugs@gnats.netbsd.org>
From: John F. Woods <jfw@jfwhome.funhouse.com>
List: netbsd-bugs
Date: 01/26/2003 09:26:16
>Number:         20066
>Category:       bin
>Synopsis:       pppd does not have plugin hooks for LCP state
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Jan 26 06:27:00 PST 2003
>Closed-Date:
>Last-Modified:
>Originator:     John F. Woods
>Release:        NetBSD 1.6F
>Organization:
Misanthropes-R-Us
>Environment:
	
	
System: NetBSD jfwhome.funhouse.com 1.6F NetBSD 1.6F (JFW) #6: Sun Aug 18 12:28:13 EDT 2002 jfw@jfwhome.funhouse.com:/usr/src/sys/arch/i386/compile/JFW i386
Architecture: i386
Machine: i386
>Description:
This depends on the acceptance of my previous change request (bin/20065) to
enable pppd to load plugins.  pppd has plugin hooks for IP state, PAP
authentication, and a handful of other things.  I found it desirable have
hooks for LCP state (primarily to get quicker feedback as to when the link
was about to go down), and have added such hooks to my local sources.
>How-To-Repeat:
UTSL
>Fix:
The following patches to pppd.h and lcp.c add hooks for LCP up, LCP down,
LCP ECHO transmit (with a count indicating the outstanding unacknowledged
echo count), and LCP ECHO REPLY (with a flag indicating that we've gotten
our own ECHO, a bad sign).  The "patches" to Makefile and status.c are for
an example usage of these hooks, and should be placed in a new directory
/usr/src/usr.sbin/pppd/plugins/status/; the status plugin simply writes the
current status to a file (whose name is given in a new pppd option) every
time the status changes.  This goofy, primitive mechanism was sufficient
for my needs, but is intended more as an example as a useful item in itself.
(For example, on my local network, once I've written the status to a file,
I use a separate process to read that file every second and send a broadcast
UDP packet, which the Macs on my network receive and use to display status;
it would probably make more sense to put that broadcast directly into the
status plugin.  Someone else might prefer to have the plugin offer the status
indication to an SNMP agent.)

Index: pppd.h
===================================================================
RCS file: /cvsroot/src/usr.sbin/pppd/pppd/pppd.h,v
retrieving revision 1.23
diff -u -d -b -w -r1.23 pppd.h
--- pppd.h	2002/07/01 22:19:40	1.23
+++ pppd.h	2003/01/19 16:54:08
@@ -638,6 +638,10 @@
 extern void (*ip_up_hook) __P((void));
 extern void (*ip_down_hook) __P((void));
 extern void (*ip_choose_hook) __P((u_int32_t *));
+void (*lcp_up_hook) __P((void));
+void (*lcp_down_hook) __P((void));
+void (*lcp_echo_hook) __P((int));
+void (*lcp_echoreply_hook) __P((int));
 
 /*
  * Inline versions of get/put char/short/long.

Index: lcp.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/pppd/pppd/lcp.c,v
retrieving revision 1.24
diff -u -d -b -w -r1.24 lcp.c
--- lcp.c	2002/07/01 22:19:35	1.24
+++ lcp.c	2003/01/19 16:54:39
@@ -204,6 +204,18 @@
 lcp_options lcp_allowoptions[NUM_PPP];	/* Options we allow peer to request */
 lcp_options lcp_hisoptions[NUM_PPP];	/* Options that we ack'd */
 
+/* Hook for LCP up */
+void (*lcp_up_hook) __P((void)) = NULL;
+
+/* Hook for LCP down */
+void (*lcp_down_hook) __P((void)) = NULL;
+
+/* Hook for sending an LCP echo request, argument is pending count */
+void (*lcp_echo_hook) __P((int)) = NULL;
+
+/* Hook for receiving an LCP echo reply, argument is whether it's ours */
+void (*lcp_echoreply_hook) __P((int)) = NULL;
+
 static int lcp_echos_pending = 0;	/* Number of outstanding echo msgs */
 static int lcp_echo_number   = 0;	/* ID number of next echo frame */
 static int lcp_echo_timer_running = 0;  /* set if a timer is running */
@@ -1836,6 +1848,8 @@
     if (ho->neg_mru)
 	peer_mru[f->unit] = ho->mru;
 
+    if (lcp_up_hook) (*lcp_up_hook)();
+
     lcp_echo_lowerup(f->unit);  /* Enable echo messages */
 
     link_established(f->unit);
@@ -1857,6 +1871,8 @@
 
     link_down(f->unit);
 
+    if (lcp_down_hook) (*lcp_down_hook)();
+
     ppp_send_config(f->unit, PPP_MRU, 0xffffffff, 0, 0);
     ppp_recv_config(f->unit, PPP_MRU,
 		    (go->neg_asyncmap? go->asyncmap: 0xffffffff),
@@ -2181,8 +2197,10 @@
     if (lcp_gotoptions[f->unit].neg_magicnumber
 	&& magic == lcp_gotoptions[f->unit].magicnumber) {
 	warn("appear to have received our own echo-reply!");
+	if (lcp_echoreply_hook) (*lcp_echoreply_hook)(1);
 	return;
     }
+    if (lcp_echoreply_hook) (*lcp_echoreply_hook)(0);
 
     /* Reset the number of outstanding echo frames */
     lcp_echos_pending = 0;
@@ -2213,6 +2231,7 @@
      * Make and send the echo request frame.
      */
     if (f->state == OPENED) {
+      if (*lcp_echo_hook) (*lcp_echo_hook)(lcp_echos_pending);
         lcp_magic = lcp_gotoptions[f->unit].magicnumber;
 	pktp = pkt;
 	PUTLONG(lcp_magic, pktp);

================================================================
--- /dev/null	Sun Jan 26 08:56:21 2003
+++ plugins/status/Makefile	Sun Jan 26 09:16:46 2003
@@ -0,0 +1,16 @@
+#	$NetBSD: Makefile,v 1.3 2002/09/18 13:31:55 lukem Exp $
+
+NOLINT=	# defined
+
+.include <bsd.own.mk>
+
+PCAPDIR=${NETBSDSRCDIR}/lib/libpcap
+
+LIB=status
+SRCS=status.c
+CPPFLAGS+=-I${.CURDIR}/../../pppd
+
+LIBPREFIX=
+SHLIB_FULLVERSION=
+
+.include <bsd.lib.mk>

================================================================
--- /dev/null	Sun Jan 26 08:56:21 2003
+++ plugins/status/status.c	Sun Jan 26 09:16:46 2003
@@ -0,0 +1,91 @@
+/*
+ * status.c - pppd plugin to implement an `lcpstatus' option.
+ *
+ * Copyright 2003 John Woods;
+ * based on minconn.c, Copyright 1999 Paul Mackerras.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms.  The name of the author
+ * may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <stddef.h>
+#include <time.h>
+#include <stdio.h>
+#include "pppd.h"
+
+char pppd_version[] = VERSION;
+
+static char *statusfilename = 0;
+static char *laststatus = 0;
+static char UP[] = "up";
+static char DOWN[] = "down";
+static char MISS[] = "?";
+static char MINE[] = "!";
+
+static option_t my_options[] = {
+	{ "lcpstatus", o_string, &statusfilename,
+	  "Name of file to which LCP status string will be written" },
+	{ NULL }
+};
+
+/* status should be one of the canned constants above. */
+static void writestatus(char *status)
+{
+        FILE *statusfile;
+	if (status == laststatus) return;  /* we knew that already */
+	statusfile = fopen(statusfilename, "w");
+	if (!statusfile) {
+                warn("can't write %s to log LCP status", statusfilename);
+		free(statusfilename);
+		statusfilename = 0;
+		return;
+	}
+	fprintf(statusfile, "%s\n", status);
+	fclose(statusfile);
+	laststatus = status;
+}
+
+static void my_lcp_up(void)
+{
+        if (!statusfilename) return; /* not enabled */
+	writestatus(UP);
+}
+
+static void my_lcp_down(void)
+{
+        if (!statusfilename) return; /* not enabled */
+	writestatus(DOWN);
+}
+
+static void my_lcp_echo(int pending)
+{
+        if (!statusfilename) return; /* not enabled */
+	if (pending == 0)
+                writestatus(UP);
+	else if (laststatus != MINE)
+                writestatus(MISS);
+}
+
+static void my_lcp_echoreply(int mine)
+{
+        if (!statusfilename) return; /* not enabled */
+	if (mine == 0)
+                writestatus(UP);
+	else
+                writestatus(MINE);
+}        
+
+void plugin_init(void)
+{
+	info("plugin_init");
+	add_options(my_options);
+	lcp_up_hook = my_lcp_up;
+	lcp_down_hook = my_lcp_down;
+	lcp_echo_hook = my_lcp_echo;
+	lcp_echoreply_hook = my_lcp_echoreply;
+}
>Release-Note:
>Audit-Trail:
>Unformatted:
 Sun Jan 26 06:09:01 PST 2003