Subject: Re: ISDN - first TCP connection fails
To: Ingolf Steinbach <ingolf@steinba.ch>
From: Martin Husemann <martin@duskware.de>
List: tech-net
Date: 03/08/2002 19:38:53
--ibTvN161/egqYuK8
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
> The ones in -current do, so this might be fixed.
FWIW - here is an uncompiled & untested patch against the 1.5 branch.
Please let me know if it works for you. No guarantee though.
Martin
--ibTvN161/egqYuK8
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=patch
Index: if_sppp.h
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_sppp.h,v
retrieving revision 1.6
diff -c -u -r1.6 if_sppp.h
--- if_sppp.h 2000/05/02 12:43:16 1.6
+++ if_sppp.h 2002/03/08 18:36:30
@@ -51,12 +51,16 @@
u_long opts; /* IPCP options to send (bitfield) */
u_int flags;
#define IPCP_HISADDR_SEEN 1 /* have seen his address already */
-#define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */
-#define IPCP_MYADDR_SEEN 4 /* have seen his address already */
+#define IPCP_MYADDR_SEEN 2 /* have a local address assigned already */
+#define IPCP_MYADDR_DYN 4 /* my address is dynamically assigned */
+#define IPCP_HISADDR_DYN 8 /* his address is dynamically assigned */
#ifdef notdef
#define IPV6CP_MYIFID_DYN 2 /* my ifid is dynamically assigned */
#endif
#define IPV6CP_MYIFID_SEEN 4 /* have seen his ifid already */
+ u_int32_t saved_hisaddr;/* if hisaddr (IPv4) is dynamic, save original one here, in network byte order */
+ u_int32_t req_hisaddr; /* remote address requested */
+ u_int32_t req_myaddr; /* local address requested */
};
#define AUTHNAMELEN 32
Index: if_spppsubr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_spppsubr.c,v
retrieving revision 1.10.4.2
diff -c -u -r1.10.4.2 if_spppsubr.c
--- if_spppsubr.c 2001/07/29 19:51:36 1.10.4.2
+++ if_spppsubr.c 2002/03/08 18:36:32
@@ -400,7 +400,8 @@
static void sppp_print_bytes(const u_char *p, u_short len);
static void sppp_print_string(const char *p, u_short len);
static void sppp_qflush(struct ifqueue *ifq);
-static void sppp_set_ip_addr(struct sppp *sp, u_long src);
+static void sppp_set_ip_addrs(struct sppp *sp, u_int32_t myaddr, u_int32_t hisaddr);
+static void sppp_clear_ip_addrs(struct sppp *sp);
#ifdef INET6
static void sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src,
struct in6_addr *dst, struct in6_addr *srcmask);
@@ -2731,7 +2732,9 @@
STDDCL;
u_long myaddr, hisaddr;
- sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN|IPCP_MYADDR_SEEN|IPCP_MYADDR_DYN);
+ sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN|IPCP_MYADDR_SEEN|IPCP_MYADDR_DYN|IPCP_HISADDR_DYN);
+ sp->ipcp.req_myaddr = 0;
+ sp->ipcp.req_hisaddr = 0;
sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0);
/*
@@ -2748,15 +2751,21 @@
return;
}
- if (myaddr == 0L) {
+ if (myaddr == 0) {
/*
* I don't have an assigned address, so i need to
* negotiate my address.
*/
sp->ipcp.flags |= IPCP_MYADDR_DYN;
sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
- } else
- sp->ipcp.flags |= IPCP_MYADDR_SEEN;
+ }
+ if (hisaddr == 1) {
+ /*
+ * XXX - remove this hack!
+ * remote has no valid adress, we need to get one assigned.
+ */
+ sp->ipcp.flags |= IPCP_HISADDR_DYN;
+ }
sppp_open_event(&ipcp, sp);
}
@@ -2764,11 +2773,11 @@
sppp_ipcp_close(struct sppp *sp)
{
sppp_close_event(&ipcp, sp);
- if (sp->ipcp.flags & IPCP_MYADDR_DYN)
+ if (sp->ipcp.flags & (IPCP_MYADDR_DYN|IPCP_HISADDR_DYN))
/*
- * My address was dynamic, clear it again.
+ * Some address was dynamic, clear it again.
*/
- sppp_set_ip_addr(sp, 0L);
+ sppp_clear_ip_addrs(sp);
}
static void
@@ -2790,7 +2799,6 @@
struct ifnet *ifp = &sp->pp_if;
int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
u_long hisaddr, desiredaddr;
- int gotmyaddr = 0;
len -= 4;
origlen = len;
@@ -2849,7 +2857,10 @@
addlog("\n");
/* pass 2: parse option values */
- sppp_get_ip_addrs(sp, 0, &hisaddr, 0);
+ if (sp->ipcp.flags & IPCP_HISADDR_SEEN)
+ hisaddr = sp->ipcp.req_hisaddr; /* we already aggreed on that */
+ else
+ sppp_get_ip_addrs(sp, 0, &hisaddr, 0); /* user configuration */
if (debug)
log(LOG_DEBUG, SPP_FMT "ipcp parse opt values: ",
SPP_ARGS(ifp));
@@ -2866,62 +2877,42 @@
case IPCP_OPT_ADDRESS:
desiredaddr = p[2] << 24 | p[3] << 16 |
p[4] << 8 | p[5];
- if (!(sp->ipcp.flags & IPCP_MYADDR_SEEN) &&
- (sp->ipcp.flags & IPCP_MYADDR_DYN)) {
- /*
- * hopefully this is our address !!
- */
- if (debug)
- addlog(" [wantmyaddr %s]",
- sppp_dotted_quad(desiredaddr));
+ if (desiredaddr == hisaddr ||
+ ((sp->ipcp.flags & IPCP_HISADDR_DYN) && desiredaddr != 0)) {
/*
- * When doing dynamic address assignment,
- * we accept his offer. Otherwise, we
- * ignore it and thus continue to negotiate
- * our already existing value.
- */
- sppp_set_ip_addr(sp, desiredaddr);
+ * Peer's address is same as our value,
+ * this is agreeable. Gonna conf-ack
+ * it.
+ */
if (debug)
- addlog(" [agree]");
- sp->ipcp.flags |= IPCP_MYADDR_SEEN;
- gotmyaddr++;
+ addlog(" %s [ack]",
+ sppp_dotted_quad(hisaddr));
+ /* record that we've seen it already */
+ sp->ipcp.flags |= IPCP_HISADDR_SEEN;
+ sp->ipcp.req_hisaddr = desiredaddr;
+ hisaddr = desiredaddr;
continue;
- } else {
- if (desiredaddr == hisaddr ||
- (hisaddr == 1 && desiredaddr != 0)) {
- /*
- * Peer's address is same as our value,
- * this is agreeable. Gonna conf-ack
- * it.
- */
- if (debug)
- addlog(" %s [ack]",
- sppp_dotted_quad(hisaddr));
- /* record that we've seen it already */
- sp->ipcp.flags |= IPCP_HISADDR_SEEN;
- continue;
- }
- /*
- * The address wasn't agreeable. This is either
- * he sent us 0.0.0.0, asking to assign him an
- * address, or he send us another address not
- * matching our value. Either case, we gonna
- * conf-nak it with our value.
- */
- if (debug) {
- if (desiredaddr == 0)
- addlog(" [addr requested]");
- else
- addlog(" %s [not agreed]",
- sppp_dotted_quad(desiredaddr));
- }
-
- p[2] = hisaddr >> 24;
- p[3] = hisaddr >> 16;
- p[4] = hisaddr >> 8;
- p[5] = hisaddr;
- break;
}
+ /*
+ * The address wasn't agreeable. This is either
+ * he sent us 0.0.0.0, asking to assign him an
+ * address, or he send us another address not
+ * matching our value. Either case, we gonna
+ * conf-nak it with our value.
+ */
+ if (debug) {
+ if (desiredaddr == 0)
+ addlog(" [addr requested]");
+ else
+ addlog(" %s [not agreed]",
+ sppp_dotted_quad(desiredaddr));
+ }
+
+ p[2] = hisaddr >> 24;
+ p[3] = hisaddr >> 16;
+ p[4] = hisaddr >> 8;
+ p[5] = hisaddr;
+ break;
}
/* Add the option to nak'ed list. */
bcopy (p, r, p[1]);
@@ -2939,7 +2930,7 @@
* doesn't want to send us his address. Q: What should we do
* about it? XXX A: implement the max-failure counter.
*/
- if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN) && !gotmyaddr) {
+ if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN)) {
buf[0] = IPCP_OPT_ADDRESS;
buf[1] = 6;
buf[2] = hisaddr >> 24;
@@ -3058,10 +3049,10 @@
* our already existing value.
*/
if (sp->ipcp.flags & IPCP_MYADDR_DYN) {
- sppp_set_ip_addr(sp, wantaddr);
if (debug)
addlog(" [agree]");
sp->ipcp.flags |= IPCP_MYADDR_SEEN;
+ sp->ipcp.req_myaddr = wantaddr;
}
}
break;
@@ -3083,7 +3074,14 @@
static void
sppp_ipcp_tlu(struct sppp *sp)
{
- /* we are up - notify isdn daemon */
+ /* we are up. Set addresses and notify anyone interested */
+ u_int32_t myaddr, hisaddr;
+ sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0);
+ if ((sp->ipcp.flags & IPCP_MYADDR_DYN) && (sp->ipcp.flags & IPCP_MYADDR_SEEN))
+ myaddr = sp->ipcp.req_myaddr;
+ if ((sp->ipcp.flags & IPCP_HISADDR_DYN) && (sp->ipcp.flags & IPCP_HISADDR_SEEN))
+ hisaddr = sp->ipcp.req_hisaddr;
+ sppp_set_ip_addrs(sp, myaddr, hisaddr);
if (sp->pp_con)
sp->pp_con(sp);
}
@@ -3126,7 +3124,10 @@
#endif
if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) {
- sppp_get_ip_addrs(sp, &ouraddr, 0, 0);
+ if (sp->ipcp.flags & IPCP_MYADDR_SEEN)
+ ouraddr = sp->ipcp.req_myaddr; /* not sure if this can ever happen */
+ else
+ sppp_get_ip_addrs(sp, &ouraddr, 0, 0);
opt[i++] = IPCP_OPT_ADDRESS;
opt[i++] = 6;
opt[i++] = ouraddr >> 24;
@@ -4717,37 +4718,30 @@
}
/*
- * Set my IP address. Must be called at splimp.
+ * Set IP addresses. Must be called at splnet.
+ * If an address is 0, leave it the way it is.
*/
static void
-sppp_set_ip_addr(struct sppp *sp, u_long src)
+sppp_set_ip_addrs(struct sppp *sp, u_int32_t myaddr, u_int32_t hisaddr)
{
STDDCL;
struct ifaddr *ifa;
struct sockaddr_in *si;
+ struct sockaddr_in *dest;
/*
* Pick the first AF_INET address from the list,
* aliases don't make any sense on a p2p link anyway.
*/
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
- for (ifa = ifp->if_addrhead.tqh_first, si = 0;
- ifa;
- ifa = ifa->ifa_link.tqe_next)
-#elif defined(__NetBSD__) || defined (__OpenBSD__)
for (ifa = ifp->if_addrlist.tqh_first, si = 0;
ifa;
ifa = ifa->ifa_list.tqe_next)
-#else
- for (ifa = ifp->if_addrlist, si = 0;
- ifa;
- ifa = ifa->ifa_next)
-#endif
{
if (ifa->ifa_addr->sa_family == AF_INET)
{
si = (struct sockaddr_in *)ifa->ifa_addr;
+ dest = (struct sockaddr_in *)ifa->ifa_dstaddr;
if (si)
break;
}
@@ -4756,38 +4750,81 @@
if (ifa && si)
{
int error;
-#if __NetBSD_Version__ >= 103080000
struct sockaddr_in new_sin = *si;
+ struct sockaddr_in new_dst = *dest;
- new_sin.sin_addr.s_addr = htonl(src);
- error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 1);
- if(debug && error)
- {
- log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: in_ifinit "
- " failed, error=%d\n", SPP_ARGS(ifp), error);
+ /*
+ * Scrub old routes now instead of calling in_ifinit with
+ * scrub=1, because we may change the dstaddr
+ * before the call to in_ifinit.
+ */
+ in_ifscrub(ifp, ifatoia(ifa));
+
+ if (myaddr != 0)
+ new_sin.sin_addr.s_addr = htonl(myaddr);
+ if (hisaddr != 0) {
+ new_dst.sin_addr.s_addr = htonl(hisaddr);
+ if (new_dst.sin_addr.s_addr != dest->sin_addr.s_addr) {
+ sp->ipcp.saved_hisaddr = dest->sin_addr.s_addr;
+ *dest = new_dst; /* fix dstaddr in place */
+ }
}
-#else
- /* delete old route */
- error = rtinit(ifa, (int)RTM_DELETE, RTF_HOST);
+ error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0);
if(debug && error)
{
- log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit DEL failed, error=%d\n",
+ log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addrs: in_ifinit "
SPP_ARGS(ifp), error);
}
+ }
+}
+
+/*
+ * Clear IP addresses. Must be called at splnet.
+ */
+static void
+sppp_clear_ip_addrs(struct sppp *sp)
+{
+ struct ifnet *ifp = &sp->pp_if;
+ struct ifaddr *ifa;
+ struct sockaddr_in *si;
+ struct sockaddr_in *dest;
+
+ u_int32_t remote;
+ if (sp->ipcp.flags & IPCP_HISADDR_DYN)
+ remote = sp->ipcp.saved_hisaddr;
+ else
+ sppp_get_ip_addrs(sp, 0, &remote, 0);
- /* set new address */
- si->sin_addr.s_addr = htonl(src);
+ /*
+ * Pick the first AF_INET address from the list,
+ * aliases don't make any sense on a p2p link anyway.
+ */
- /* add new route */
- error = rtinit(ifa, (int)RTM_ADD, RTF_HOST);
- if (debug && error)
+ si = 0;
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
+ {
+ if (ifa->ifa_addr->sa_family == AF_INET)
{
- log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit ADD failed, error=%d",
- SPP_ARGS(ifp), error);
+ si = (struct sockaddr_in *)ifa->ifa_addr;
+ dest = (struct sockaddr_in *)ifa->ifa_dstaddr;
+ if (si)
+ break;
}
-#endif
}
-}
+
+ if (ifa && si)
+ {
+ struct sockaddr_in new_sin = *si;
+
+ in_ifscrub(ifp, ifatoia(ifa));
+ if (sp->ipcp.flags & IPCP_MYADDR_DYN)
+ new_sin.sin_addr.s_addr = 0;
+ if (sp->ipcp.flags & IPCP_HISADDR_DYN)
+ /* replace peer addr in place */
+ dest->sin_addr.s_addr = sp->ipcp.saved_hisaddr;
+ in_ifinit(ifp, ifatoia(ifa), &new_sin, 0);
+ }
+}
#ifdef INET6
/*
--ibTvN161/egqYuK8--