James Andrewartha wrote:
On Sun, 11 Oct 2009, Michael Tokarev wrote:
[]
[] The fact that workarounds exist doesn't change
the fact it's a valid bug, albeit one that's very difficult to fix given the
current architecture of pppd.
Well, the patch is simple enough really.
Really? How do you work around the fact that the unit number is used as
the primary identifer throughout the code?
Well, "unit" variable in pppd sources is indeed heavily used.
For somewhat strange reason - it's an index in the internal
arr1ay where only one element (the one to which `unit' global
variable points to) is used. Maybe it was an earlier attempt
to implement multilink, I don't know. The global variable
"unit" is also used for ppp kernel driver control commands.
What else we're looking at is ifname[] global. It is used
for interface-specific ioctls (ifreq).
Each interface (on linux at least) has number and name.
ppp kernel module apparently expects the number. The rest
of the code (IP address manipulation, routing etc) expects
name. The two are not required to match (pppN), but
pppd assumes they are.
Also, this has been discussed several times (on ppp mailinglist
and in the BTS for ppp).
I'm attaching a patch that implements the feature and applies
to current 2.4.4 version (either upstream or debian).
/mjt
Patch adopted from
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=458646
Note that this one introduces additional variable $IFUNIT
to be used in multilink configuration to support the actual
unit number.
--- ppp-2.4.4.orig/pppd/auth.c 2006-06-18 15:26:00.000000000 +0400
+++ ppp-2.4.4/pppd/auth.c 2009-10-10 21:55:14.768770411 +0400
@@ -648,6 +648,8 @@ link_terminated(unit)
if (!hungup)
lcp_lowerdown(0);
- if (!doing_multilink && !demand)
+ if (!doing_multilink && !demand) {
script_unsetenv("IFNAME");
+ script_unsetenv("IFUNIT");
+ }
/*
--- ppp-2.4.4.orig/pppd/main.c 2006-06-04 07:52:50.000000000 +0400
+++ ppp-2.4.4/pppd/main.c 2009-10-10 21:58:26.472131980 +0400
@@ -737,7 +737,10 @@ set_ifunit(iskey)
int iskey;
{
- info("Using interface %s%d", PPP_DRV_NAME, ifunit);
slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit);
- script_setenv("IFNAME", ifname, iskey);
+ script_setenv("IFUNIT", ifname, iskey);
+ if (req_ifname[0] && sys_change_ifname(ifname, req_ifname))
+ slprintf(ifname, sizeof(ifname), "%s", req_ifname);
+ info("Using interface %s", ifname);
+ script_setenv("IFNAME", ifname, 0);
if (iskey) {
create_pidfile(getpid()); /* write pid to file */
--- ppp-2.4.4.orig/pppd/multilink.c 2004-11-13 11:57:36.000000000 +0300
+++ ppp-2.4.4/pppd/multilink.c 2009-10-10 21:55:14.772093333 +0400
@@ -205,5 +205,5 @@ mp_join_bundle()
rec.dptr[rec.dsize-1] = 0;
/* parse the interface number */
- parse_num(rec.dptr, "IFNAME=ppp", &unit);
+ parse_num(rec.dptr, "IFUNIT=ppp", &unit);
/* check the pid value */
if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid)
@@ -418,5 +418,5 @@ owns_unit(key, unit)
int ret = 0;
- slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit);
+ slprintf(ifkey, sizeof(ifkey), "IFUNIT=ppp%d", unit);
kd.dptr = ifkey;
kd.dsize = strlen(ifkey);
--- ppp-2.4.4.orig/pppd/options.c 2006-06-18 15:26:00.000000000 +0400
+++ ppp-2.4.4/pppd/options.c 2009-10-10 21:57:13.795727710 +0400
@@ -114,4 +114,5 @@ bool tune_kernel; /* may alter kernel s
int connect_delay = 1000; /* wait this many ms after connect script */
int req_unit = -1; /* requested interface unit */
+char req_ifname[16]; /* requested interface name */
bool multilink = 0; /* Enable multilink operation */
char *bundle_name = NULL; /* bundle name for multilink */
@@ -273,4 +274,8 @@ option_t general_options[] = {
OPT_PRIO | OPT_LLIMIT, 0, 0 },
+ { "ifname", o_string, req_ifname,
+ "PPP interface name to use if possible",
+ OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, sizeof(req_ifname) },
+
{ "dump", o_bool, &dump_options,
"Print out option values after parsing all options", 1 },
--- ppp-2.4.4.orig/pppd/pppd.h 2005-08-26 03:59:34.000000000 +0400
+++ ppp-2.4.4/pppd/pppd.h 2009-10-10 21:57:25.592234648 +0400
@@ -313,4 +313,5 @@ extern int connect_delay; /* Time to del
extern int max_data_rate; /* max bytes/sec through charshunt */
extern int req_unit; /* interface unit number to use */
+extern char req_ifname[16]; /* interface name to use */
extern bool multilink; /* enable multilink operation */
extern bool noendpoint; /* don't send or accept endpt. discrim. */
@@ -669,4 +670,5 @@ int cipxfaddr __P((int));
int get_if_hwaddr __P((u_char *addr, char *name));
char *get_first_ethernet __P((void));
+int sys_change_ifname __P((const char *, const char *));
/* Procedures exported from options.c */
diff -U2 -p -r ppp-2.4.4.orig/pppd/sys-linux.c ppp-2.4.4/pppd/sys-linux.c
--- ppp-2.4.4.orig/pppd/sys-linux.c 2005-08-27 02:44:35.000000000 +0400
+++ ppp-2.4.4/pppd/sys-linux.c 2009-10-10 22:00:33.308760098 +0400
@@ -2873,2 +2873,26 @@ ether_to_eui64(eui64_t *p_eui64)
}
#endif
+
+int
+sys_change_ifname(const char *old, const char *new)
+{
+ struct ifreq ifr;
+
+ SYSDEBUG ((LOG_DEBUG, "sys_change_ifname: %s -> %s\n", old, new));
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, old, sizeof (ifr.ifr_name));
+ strlcpy(ifr.ifr_newname, new, sizeof (ifr.ifr_newname));
+
+#ifndef SIOCSIFNAME
+#define SIOCSIFNAME 0x8923
+#endif
+ if (ioctl(sock_fd, SIOCSIFNAME, (caddr_t) &ifr) < 0) {
+ if (errno == EEXIST)
+ warn("Couldn't change name to %s as it is already in use", new);
+ else
+ error("Couldn't change name from %s to %s: %m", old, new);
+ return 0;
+ }
+ return 1;
+}
--- ppp-2.4.4.orig/pppd/pppd.8 2006-06-16 04:01:23.000000000 +0400
+++ ppp-2.4.4/pppd/pppd.8 2009-10-10 22:04:35.702156046 +0400
@@ -401,4 +401,9 @@
the link was terminated because it was idle.
.TP
+.B ifname \fIname
+Specifies interface name to use for outbound connection, on systems
+that supports network interface renaming. So far only Linux is
+known to work.
+.TP
.B idle \fIn
Specifies that pppd should disconnect if the link is idle for \fIn\fR