xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.0.2/src/netif/ppp/multilink.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * multilink.c - support routines for multilink.
3*10465441SEvalZero  *
4*10465441SEvalZero  * Copyright (c) 2000-2002 Paul Mackerras. All rights reserved.
5*10465441SEvalZero  *
6*10465441SEvalZero  * Redistribution and use in source and binary forms, with or without
7*10465441SEvalZero  * modification, are permitted provided that the following conditions
8*10465441SEvalZero  * are met:
9*10465441SEvalZero  *
10*10465441SEvalZero  * 1. Redistributions of source code must retain the above copyright
11*10465441SEvalZero  *    notice, this list of conditions and the following disclaimer.
12*10465441SEvalZero  *
13*10465441SEvalZero  * 2. The name(s) of the authors of this software must not be used to
14*10465441SEvalZero  *    endorse or promote products derived from this software without
15*10465441SEvalZero  *    prior written permission.
16*10465441SEvalZero  *
17*10465441SEvalZero  * 3. Redistributions of any form whatsoever must retain the following
18*10465441SEvalZero  *    acknowledgment:
19*10465441SEvalZero  *    "This product includes software developed by Paul Mackerras
20*10465441SEvalZero  *     <[email protected]>".
21*10465441SEvalZero  *
22*10465441SEvalZero  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23*10465441SEvalZero  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24*10465441SEvalZero  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25*10465441SEvalZero  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26*10465441SEvalZero  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27*10465441SEvalZero  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28*10465441SEvalZero  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29*10465441SEvalZero  */
30*10465441SEvalZero 
31*10465441SEvalZero #include "netif/ppp/ppp_opts.h"
32*10465441SEvalZero #if PPP_SUPPORT && defined(HAVE_MULTILINK) /* don't build if not configured for use in lwipopts.h */
33*10465441SEvalZero 
34*10465441SEvalZero /* Multilink support
35*10465441SEvalZero  *
36*10465441SEvalZero  * Multilink uses Samba TDB (Trivial Database Library), which
37*10465441SEvalZero  * we cannot port, because it needs a filesystem.
38*10465441SEvalZero  *
39*10465441SEvalZero  * We have to choose between doing a memory-shared TDB-clone,
40*10465441SEvalZero  * or dropping multilink support at all.
41*10465441SEvalZero  */
42*10465441SEvalZero 
43*10465441SEvalZero #include <string.h>
44*10465441SEvalZero #include <ctype.h>
45*10465441SEvalZero #include <stdlib.h>
46*10465441SEvalZero #include <netdb.h>
47*10465441SEvalZero #include <errno.h>
48*10465441SEvalZero #include <signal.h>
49*10465441SEvalZero #include <netinet/in.h>
50*10465441SEvalZero #include <unistd.h>
51*10465441SEvalZero 
52*10465441SEvalZero #include "netif/ppp/ppp_impl.h"
53*10465441SEvalZero 
54*10465441SEvalZero #include "netif/ppp/fsm.h"
55*10465441SEvalZero #include "netif/ppp/lcp.h"
56*10465441SEvalZero #include "netif/ppp/tdb.h"
57*10465441SEvalZero 
58*10465441SEvalZero bool endpoint_specified;	/* user gave explicit endpoint discriminator */
59*10465441SEvalZero char *bundle_id;		/* identifier for our bundle */
60*10465441SEvalZero char *blinks_id;		/* key for the list of links */
61*10465441SEvalZero bool doing_multilink;		/* multilink was enabled and agreed to */
62*10465441SEvalZero bool multilink_master;		/* we own the multilink bundle */
63*10465441SEvalZero 
64*10465441SEvalZero extern TDB_CONTEXT *pppdb;
65*10465441SEvalZero extern char db_key[];
66*10465441SEvalZero 
67*10465441SEvalZero static void make_bundle_links (int append);
68*10465441SEvalZero static void remove_bundle_link (void);
69*10465441SEvalZero static void iterate_bundle_links (void (*func) (char *));
70*10465441SEvalZero 
71*10465441SEvalZero static int get_default_epdisc (struct epdisc *);
72*10465441SEvalZero static int parse_num (char *str, const char *key, int *valp);
73*10465441SEvalZero static int owns_unit (TDB_DATA pid, int unit);
74*10465441SEvalZero 
75*10465441SEvalZero #define set_ip_epdisc(ep, addr) do {	\
76*10465441SEvalZero 	ep->length = 4;			\
77*10465441SEvalZero 	ep->value[0] = addr >> 24;	\
78*10465441SEvalZero 	ep->value[1] = addr >> 16;	\
79*10465441SEvalZero 	ep->value[2] = addr >> 8;	\
80*10465441SEvalZero 	ep->value[3] = addr;		\
81*10465441SEvalZero } while (0)
82*10465441SEvalZero 
83*10465441SEvalZero #define LOCAL_IP_ADDR(addr)						  \
84*10465441SEvalZero 	(((addr) & 0xff000000) == 0x0a000000		/* 10.x.x.x */	  \
85*10465441SEvalZero 	 || ((addr) & 0xfff00000) == 0xac100000		/* 172.16.x.x */  \
86*10465441SEvalZero 	 || ((addr) & 0xffff0000) == 0xc0a80000)	/* 192.168.x.x */
87*10465441SEvalZero 
88*10465441SEvalZero #define process_exists(n)	(kill((n), 0) == 0 || errno != ESRCH)
89*10465441SEvalZero 
90*10465441SEvalZero void
mp_check_options()91*10465441SEvalZero mp_check_options()
92*10465441SEvalZero {
93*10465441SEvalZero 	lcp_options *wo = &lcp_wantoptions[0];
94*10465441SEvalZero 	lcp_options *ao = &lcp_allowoptions[0];
95*10465441SEvalZero 
96*10465441SEvalZero 	doing_multilink = 0;
97*10465441SEvalZero 	if (!multilink)
98*10465441SEvalZero 		return;
99*10465441SEvalZero 	/* if we're doing multilink, we have to negotiate MRRU */
100*10465441SEvalZero 	if (!wo->neg_mrru) {
101*10465441SEvalZero 		/* mrru not specified, default to mru */
102*10465441SEvalZero 		wo->mrru = wo->mru;
103*10465441SEvalZero 		wo->neg_mrru = 1;
104*10465441SEvalZero 	}
105*10465441SEvalZero 	ao->mrru = ao->mru;
106*10465441SEvalZero 	ao->neg_mrru = 1;
107*10465441SEvalZero 
108*10465441SEvalZero 	if (!wo->neg_endpoint && !noendpoint) {
109*10465441SEvalZero 		/* get a default endpoint value */
110*10465441SEvalZero 		wo->neg_endpoint = get_default_epdisc(&wo->endpoint);
111*10465441SEvalZero 	}
112*10465441SEvalZero }
113*10465441SEvalZero 
114*10465441SEvalZero /*
115*10465441SEvalZero  * Make a new bundle or join us to an existing bundle
116*10465441SEvalZero  * if we are doing multilink.
117*10465441SEvalZero  */
118*10465441SEvalZero int
mp_join_bundle()119*10465441SEvalZero mp_join_bundle()
120*10465441SEvalZero {
121*10465441SEvalZero 	lcp_options *go = &lcp_gotoptions[0];
122*10465441SEvalZero 	lcp_options *ho = &lcp_hisoptions[0];
123*10465441SEvalZero 	lcp_options *ao = &lcp_allowoptions[0];
124*10465441SEvalZero 	int unit, pppd_pid;
125*10465441SEvalZero 	int l, mtu;
126*10465441SEvalZero 	char *p;
127*10465441SEvalZero 	TDB_DATA key, pid, rec;
128*10465441SEvalZero 
129*10465441SEvalZero 	if (doing_multilink) {
130*10465441SEvalZero 		/* have previously joined a bundle */
131*10465441SEvalZero 		if (!go->neg_mrru || !ho->neg_mrru) {
132*10465441SEvalZero 			notice("oops, didn't get multilink on renegotiation");
133*10465441SEvalZero 			lcp_close(pcb, "multilink required");
134*10465441SEvalZero 			return 0;
135*10465441SEvalZero 		}
136*10465441SEvalZero 		/* XXX should check the peer_authname and ho->endpoint
137*10465441SEvalZero 		   are the same as previously */
138*10465441SEvalZero 		return 0;
139*10465441SEvalZero 	}
140*10465441SEvalZero 
141*10465441SEvalZero 	if (!go->neg_mrru || !ho->neg_mrru) {
142*10465441SEvalZero 		/* not doing multilink */
143*10465441SEvalZero 		if (go->neg_mrru)
144*10465441SEvalZero 			notice("oops, multilink negotiated only for receive");
145*10465441SEvalZero 		mtu = ho->neg_mru? ho->mru: PPP_MRU;
146*10465441SEvalZero 		if (mtu > ao->mru)
147*10465441SEvalZero 			mtu = ao->mru;
148*10465441SEvalZero 		if (demand) {
149*10465441SEvalZero 			/* already have a bundle */
150*10465441SEvalZero 			cfg_bundle(0, 0, 0, 0);
151*10465441SEvalZero 			netif_set_mtu(pcb, mtu);
152*10465441SEvalZero 			return 0;
153*10465441SEvalZero 		}
154*10465441SEvalZero 		make_new_bundle(0, 0, 0, 0);
155*10465441SEvalZero 		set_ifunit(1);
156*10465441SEvalZero 		netif_set_mtu(pcb, mtu);
157*10465441SEvalZero 		return 0;
158*10465441SEvalZero 	}
159*10465441SEvalZero 
160*10465441SEvalZero 	doing_multilink = 1;
161*10465441SEvalZero 
162*10465441SEvalZero 	/*
163*10465441SEvalZero 	 * Find the appropriate bundle or join a new one.
164*10465441SEvalZero 	 * First we make up a name for the bundle.
165*10465441SEvalZero 	 * The length estimate is worst-case assuming every
166*10465441SEvalZero 	 * character has to be quoted.
167*10465441SEvalZero 	 */
168*10465441SEvalZero 	l = 4 * strlen(peer_authname) + 10;
169*10465441SEvalZero 	if (ho->neg_endpoint)
170*10465441SEvalZero 		l += 3 * ho->endpoint.length + 8;
171*10465441SEvalZero 	if (bundle_name)
172*10465441SEvalZero 		l += 3 * strlen(bundle_name) + 2;
173*10465441SEvalZero 	bundle_id = malloc(l);
174*10465441SEvalZero 	if (bundle_id == 0)
175*10465441SEvalZero 		novm("bundle identifier");
176*10465441SEvalZero 
177*10465441SEvalZero 	p = bundle_id;
178*10465441SEvalZero 	p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname);
179*10465441SEvalZero 	if (ho->neg_endpoint || bundle_name)
180*10465441SEvalZero 		*p++ = '/';
181*10465441SEvalZero 	if (ho->neg_endpoint)
182*10465441SEvalZero 		p += slprintf(p, bundle_id+l-p, "%s",
183*10465441SEvalZero 			      epdisc_to_str(&ho->endpoint));
184*10465441SEvalZero 	if (bundle_name)
185*10465441SEvalZero 		p += slprintf(p, bundle_id+l-p, "/%v", bundle_name);
186*10465441SEvalZero 
187*10465441SEvalZero 	/* Make the key for the list of links belonging to the bundle */
188*10465441SEvalZero 	l = p - bundle_id;
189*10465441SEvalZero 	blinks_id = malloc(l + 7);
190*10465441SEvalZero 	if (blinks_id == NULL)
191*10465441SEvalZero 		novm("bundle links key");
192*10465441SEvalZero 	slprintf(blinks_id, l + 7, "BUNDLE_LINKS=%s", bundle_id + 7);
193*10465441SEvalZero 
194*10465441SEvalZero 	/*
195*10465441SEvalZero 	 * For demand mode, we only need to configure the bundle
196*10465441SEvalZero 	 * and attach the link.
197*10465441SEvalZero 	 */
198*10465441SEvalZero 	mtu = LWIP_MIN(ho->mrru, ao->mru);
199*10465441SEvalZero 	if (demand) {
200*10465441SEvalZero 		cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
201*10465441SEvalZero 		netif_set_mtu(pcb, mtu);
202*10465441SEvalZero 		script_setenv("BUNDLE", bundle_id + 7, 1);
203*10465441SEvalZero 		return 0;
204*10465441SEvalZero 	}
205*10465441SEvalZero 
206*10465441SEvalZero 	/*
207*10465441SEvalZero 	 * Check if the bundle ID is already in the database.
208*10465441SEvalZero 	 */
209*10465441SEvalZero 	unit = -1;
210*10465441SEvalZero 	lock_db();
211*10465441SEvalZero 	key.dptr = bundle_id;
212*10465441SEvalZero 	key.dsize = p - bundle_id;
213*10465441SEvalZero 	pid = tdb_fetch(pppdb, key);
214*10465441SEvalZero 	if (pid.dptr != NULL) {
215*10465441SEvalZero 		/* bundle ID exists, see if the pppd record exists */
216*10465441SEvalZero 		rec = tdb_fetch(pppdb, pid);
217*10465441SEvalZero 		if (rec.dptr != NULL && rec.dsize > 0) {
218*10465441SEvalZero 			/* make sure the string is null-terminated */
219*10465441SEvalZero 			rec.dptr[rec.dsize-1] = 0;
220*10465441SEvalZero 			/* parse the interface number */
221*10465441SEvalZero 			parse_num(rec.dptr, "IFNAME=ppp", &unit);
222*10465441SEvalZero 			/* check the pid value */
223*10465441SEvalZero 			if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid)
224*10465441SEvalZero 			    || !process_exists(pppd_pid)
225*10465441SEvalZero 			    || !owns_unit(pid, unit))
226*10465441SEvalZero 				unit = -1;
227*10465441SEvalZero 			free(rec.dptr);
228*10465441SEvalZero 		}
229*10465441SEvalZero 		free(pid.dptr);
230*10465441SEvalZero 	}
231*10465441SEvalZero 
232*10465441SEvalZero 	if (unit >= 0) {
233*10465441SEvalZero 		/* attach to existing unit */
234*10465441SEvalZero 		if (bundle_attach(unit)) {
235*10465441SEvalZero 			set_ifunit(0);
236*10465441SEvalZero 			script_setenv("BUNDLE", bundle_id + 7, 0);
237*10465441SEvalZero 			make_bundle_links(1);
238*10465441SEvalZero 			unlock_db();
239*10465441SEvalZero 			info("Link attached to %s", ifname);
240*10465441SEvalZero 			return 1;
241*10465441SEvalZero 		}
242*10465441SEvalZero 		/* attach failed because bundle doesn't exist */
243*10465441SEvalZero 	}
244*10465441SEvalZero 
245*10465441SEvalZero 	/* we have to make a new bundle */
246*10465441SEvalZero 	make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
247*10465441SEvalZero 	set_ifunit(1);
248*10465441SEvalZero 	netif_set_mtu(pcb, mtu);
249*10465441SEvalZero 	script_setenv("BUNDLE", bundle_id + 7, 1);
250*10465441SEvalZero 	make_bundle_links(pcb);
251*10465441SEvalZero 	unlock_db();
252*10465441SEvalZero 	info("New bundle %s created", ifname);
253*10465441SEvalZero 	multilink_master = 1;
254*10465441SEvalZero 	return 0;
255*10465441SEvalZero }
256*10465441SEvalZero 
mp_exit_bundle()257*10465441SEvalZero void mp_exit_bundle()
258*10465441SEvalZero {
259*10465441SEvalZero 	lock_db();
260*10465441SEvalZero 	remove_bundle_link();
261*10465441SEvalZero 	unlock_db();
262*10465441SEvalZero }
263*10465441SEvalZero 
sendhup(char * str)264*10465441SEvalZero static void sendhup(char *str)
265*10465441SEvalZero {
266*10465441SEvalZero 	int pid;
267*10465441SEvalZero 
268*10465441SEvalZero 	if (parse_num(str, "PPPD_PID=", &pid) && pid != getpid()) {
269*10465441SEvalZero 		if (debug)
270*10465441SEvalZero 			dbglog("sending SIGHUP to process %d", pid);
271*10465441SEvalZero 		kill(pid, SIGHUP);
272*10465441SEvalZero 	}
273*10465441SEvalZero }
274*10465441SEvalZero 
mp_bundle_terminated()275*10465441SEvalZero void mp_bundle_terminated()
276*10465441SEvalZero {
277*10465441SEvalZero 	TDB_DATA key;
278*10465441SEvalZero 
279*10465441SEvalZero 	bundle_terminating = 1;
280*10465441SEvalZero 	upper_layers_down(pcb);
281*10465441SEvalZero 	notice("Connection terminated.");
282*10465441SEvalZero #if PPP_STATS_SUPPORT
283*10465441SEvalZero 	print_link_stats();
284*10465441SEvalZero #endif /* PPP_STATS_SUPPORT */
285*10465441SEvalZero 	if (!demand) {
286*10465441SEvalZero 		remove_pidfiles();
287*10465441SEvalZero 		script_unsetenv("IFNAME");
288*10465441SEvalZero 	}
289*10465441SEvalZero 
290*10465441SEvalZero 	lock_db();
291*10465441SEvalZero 	destroy_bundle();
292*10465441SEvalZero 	iterate_bundle_links(sendhup);
293*10465441SEvalZero 	key.dptr = blinks_id;
294*10465441SEvalZero 	key.dsize = strlen(blinks_id);
295*10465441SEvalZero 	tdb_delete(pppdb, key);
296*10465441SEvalZero 	unlock_db();
297*10465441SEvalZero 
298*10465441SEvalZero 	new_phase(PPP_PHASE_DEAD);
299*10465441SEvalZero 
300*10465441SEvalZero 	doing_multilink = 0;
301*10465441SEvalZero 	multilink_master = 0;
302*10465441SEvalZero }
303*10465441SEvalZero 
make_bundle_links(int append)304*10465441SEvalZero static void make_bundle_links(int append)
305*10465441SEvalZero {
306*10465441SEvalZero 	TDB_DATA key, rec;
307*10465441SEvalZero 	char *p;
308*10465441SEvalZero 	char entry[32];
309*10465441SEvalZero 	int l;
310*10465441SEvalZero 
311*10465441SEvalZero 	key.dptr = blinks_id;
312*10465441SEvalZero 	key.dsize = strlen(blinks_id);
313*10465441SEvalZero 	slprintf(entry, sizeof(entry), "%s;", db_key);
314*10465441SEvalZero 	p = entry;
315*10465441SEvalZero 	if (append) {
316*10465441SEvalZero 		rec = tdb_fetch(pppdb, key);
317*10465441SEvalZero 		if (rec.dptr != NULL && rec.dsize > 0) {
318*10465441SEvalZero 			rec.dptr[rec.dsize-1] = 0;
319*10465441SEvalZero 			if (strstr(rec.dptr, db_key) != NULL) {
320*10465441SEvalZero 				/* already in there? strange */
321*10465441SEvalZero 				warn("link entry already exists in tdb");
322*10465441SEvalZero 				return;
323*10465441SEvalZero 			}
324*10465441SEvalZero 			l = rec.dsize + strlen(entry);
325*10465441SEvalZero 			p = malloc(l);
326*10465441SEvalZero 			if (p == NULL)
327*10465441SEvalZero 				novm("bundle link list");
328*10465441SEvalZero 			slprintf(p, l, "%s%s", rec.dptr, entry);
329*10465441SEvalZero 		} else {
330*10465441SEvalZero 			warn("bundle link list not found");
331*10465441SEvalZero 		}
332*10465441SEvalZero 		if (rec.dptr != NULL)
333*10465441SEvalZero 			free(rec.dptr);
334*10465441SEvalZero 	}
335*10465441SEvalZero 	rec.dptr = p;
336*10465441SEvalZero 	rec.dsize = strlen(p) + 1;
337*10465441SEvalZero 	if (tdb_store(pppdb, key, rec, TDB_REPLACE))
338*10465441SEvalZero 		error("couldn't %s bundle link list",
339*10465441SEvalZero 		      append? "update": "create");
340*10465441SEvalZero 	if (p != entry)
341*10465441SEvalZero 		free(p);
342*10465441SEvalZero }
343*10465441SEvalZero 
remove_bundle_link()344*10465441SEvalZero static void remove_bundle_link()
345*10465441SEvalZero {
346*10465441SEvalZero 	TDB_DATA key, rec;
347*10465441SEvalZero 	char entry[32];
348*10465441SEvalZero 	char *p, *q;
349*10465441SEvalZero 	int l;
350*10465441SEvalZero 
351*10465441SEvalZero 	key.dptr = blinks_id;
352*10465441SEvalZero 	key.dsize = strlen(blinks_id);
353*10465441SEvalZero 	slprintf(entry, sizeof(entry), "%s;", db_key);
354*10465441SEvalZero 
355*10465441SEvalZero 	rec = tdb_fetch(pppdb, key);
356*10465441SEvalZero 	if (rec.dptr == NULL || rec.dsize <= 0) {
357*10465441SEvalZero 		if (rec.dptr != NULL)
358*10465441SEvalZero 			free(rec.dptr);
359*10465441SEvalZero 		return;
360*10465441SEvalZero 	}
361*10465441SEvalZero 	rec.dptr[rec.dsize-1] = 0;
362*10465441SEvalZero 	p = strstr(rec.dptr, entry);
363*10465441SEvalZero 	if (p != NULL) {
364*10465441SEvalZero 		q = p + strlen(entry);
365*10465441SEvalZero 		l = strlen(q) + 1;
366*10465441SEvalZero 		memmove(p, q, l);
367*10465441SEvalZero 		rec.dsize = p - rec.dptr + l;
368*10465441SEvalZero 		if (tdb_store(pppdb, key, rec, TDB_REPLACE))
369*10465441SEvalZero 			error("couldn't update bundle link list (removal)");
370*10465441SEvalZero 	}
371*10465441SEvalZero 	free(rec.dptr);
372*10465441SEvalZero }
373*10465441SEvalZero 
iterate_bundle_links(void (* func)(char *))374*10465441SEvalZero static void iterate_bundle_links(void (*func)(char *))
375*10465441SEvalZero {
376*10465441SEvalZero 	TDB_DATA key, rec, pp;
377*10465441SEvalZero 	char *p, *q;
378*10465441SEvalZero 
379*10465441SEvalZero 	key.dptr = blinks_id;
380*10465441SEvalZero 	key.dsize = strlen(blinks_id);
381*10465441SEvalZero 	rec = tdb_fetch(pppdb, key);
382*10465441SEvalZero 	if (rec.dptr == NULL || rec.dsize <= 0) {
383*10465441SEvalZero 		error("bundle link list not found (iterating list)");
384*10465441SEvalZero 		if (rec.dptr != NULL)
385*10465441SEvalZero 			free(rec.dptr);
386*10465441SEvalZero 		return;
387*10465441SEvalZero 	}
388*10465441SEvalZero 	p = rec.dptr;
389*10465441SEvalZero 	p[rec.dsize-1] = 0;
390*10465441SEvalZero 	while ((q = strchr(p, ';')) != NULL) {
391*10465441SEvalZero 		*q = 0;
392*10465441SEvalZero 		key.dptr = p;
393*10465441SEvalZero 		key.dsize = q - p;
394*10465441SEvalZero 		pp = tdb_fetch(pppdb, key);
395*10465441SEvalZero 		if (pp.dptr != NULL && pp.dsize > 0) {
396*10465441SEvalZero 			pp.dptr[pp.dsize-1] = 0;
397*10465441SEvalZero 			func(pp.dptr);
398*10465441SEvalZero 		}
399*10465441SEvalZero 		if (pp.dptr != NULL)
400*10465441SEvalZero 			free(pp.dptr);
401*10465441SEvalZero 		p = q + 1;
402*10465441SEvalZero 	}
403*10465441SEvalZero 	free(rec.dptr);
404*10465441SEvalZero }
405*10465441SEvalZero 
406*10465441SEvalZero static int
parse_num(str,key,valp)407*10465441SEvalZero parse_num(str, key, valp)
408*10465441SEvalZero      char *str;
409*10465441SEvalZero      const char *key;
410*10465441SEvalZero      int *valp;
411*10465441SEvalZero {
412*10465441SEvalZero 	char *p, *endp;
413*10465441SEvalZero 	int i;
414*10465441SEvalZero 
415*10465441SEvalZero 	p = strstr(str, key);
416*10465441SEvalZero 	if (p != 0) {
417*10465441SEvalZero 		p += strlen(key);
418*10465441SEvalZero 		i = strtol(p, &endp, 10);
419*10465441SEvalZero 		if (endp != p && (*endp == 0 || *endp == ';')) {
420*10465441SEvalZero 			*valp = i;
421*10465441SEvalZero 			return 1;
422*10465441SEvalZero 		}
423*10465441SEvalZero 	}
424*10465441SEvalZero 	return 0;
425*10465441SEvalZero }
426*10465441SEvalZero 
427*10465441SEvalZero /*
428*10465441SEvalZero  * Check whether the pppd identified by `key' still owns ppp unit `unit'.
429*10465441SEvalZero  */
430*10465441SEvalZero static int
owns_unit(key,unit)431*10465441SEvalZero owns_unit(key, unit)
432*10465441SEvalZero      TDB_DATA key;
433*10465441SEvalZero      int unit;
434*10465441SEvalZero {
435*10465441SEvalZero 	char ifkey[32];
436*10465441SEvalZero 	TDB_DATA kd, vd;
437*10465441SEvalZero 	int ret = 0;
438*10465441SEvalZero 
439*10465441SEvalZero 	slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit);
440*10465441SEvalZero 	kd.dptr = ifkey;
441*10465441SEvalZero 	kd.dsize = strlen(ifkey);
442*10465441SEvalZero 	vd = tdb_fetch(pppdb, kd);
443*10465441SEvalZero 	if (vd.dptr != NULL) {
444*10465441SEvalZero 		ret = vd.dsize == key.dsize
445*10465441SEvalZero 			&& memcmp(vd.dptr, key.dptr, vd.dsize) == 0;
446*10465441SEvalZero 		free(vd.dptr);
447*10465441SEvalZero 	}
448*10465441SEvalZero 	return ret;
449*10465441SEvalZero }
450*10465441SEvalZero 
451*10465441SEvalZero static int
get_default_epdisc(ep)452*10465441SEvalZero get_default_epdisc(ep)
453*10465441SEvalZero      struct epdisc *ep;
454*10465441SEvalZero {
455*10465441SEvalZero 	char *p;
456*10465441SEvalZero 	struct hostent *hp;
457*10465441SEvalZero 	u32_t addr;
458*10465441SEvalZero 
459*10465441SEvalZero 	/* First try for an ethernet MAC address */
460*10465441SEvalZero 	p = get_first_ethernet();
461*10465441SEvalZero 	if (p != 0 && get_if_hwaddr(ep->value, p) >= 0) {
462*10465441SEvalZero 		ep->class = EPD_MAC;
463*10465441SEvalZero 		ep->length = 6;
464*10465441SEvalZero 		return 1;
465*10465441SEvalZero 	}
466*10465441SEvalZero 
467*10465441SEvalZero 	/* see if our hostname corresponds to a reasonable IP address */
468*10465441SEvalZero 	hp = gethostbyname(hostname);
469*10465441SEvalZero 	if (hp != NULL) {
470*10465441SEvalZero 		addr = *(u32_t *)hp->h_addr;
471*10465441SEvalZero 		if (!bad_ip_adrs(addr)) {
472*10465441SEvalZero 			addr = lwip_ntohl(addr);
473*10465441SEvalZero 			if (!LOCAL_IP_ADDR(addr)) {
474*10465441SEvalZero 				ep->class = EPD_IP;
475*10465441SEvalZero 				set_ip_epdisc(ep, addr);
476*10465441SEvalZero 				return 1;
477*10465441SEvalZero 			}
478*10465441SEvalZero 		}
479*10465441SEvalZero 	}
480*10465441SEvalZero 
481*10465441SEvalZero 	return 0;
482*10465441SEvalZero }
483*10465441SEvalZero 
484*10465441SEvalZero /*
485*10465441SEvalZero  * epdisc_to_str - make a printable string from an endpoint discriminator.
486*10465441SEvalZero  */
487*10465441SEvalZero 
488*10465441SEvalZero static char *endp_class_names[] = {
489*10465441SEvalZero     "null", "local", "IP", "MAC", "magic", "phone"
490*10465441SEvalZero };
491*10465441SEvalZero 
492*10465441SEvalZero char *
epdisc_to_str(ep)493*10465441SEvalZero epdisc_to_str(ep)
494*10465441SEvalZero      struct epdisc *ep;
495*10465441SEvalZero {
496*10465441SEvalZero 	static char str[MAX_ENDP_LEN*3+8];
497*10465441SEvalZero 	u_char *p = ep->value;
498*10465441SEvalZero 	int i, mask = 0;
499*10465441SEvalZero 	char *q, c, c2;
500*10465441SEvalZero 
501*10465441SEvalZero 	if (ep->class == EPD_NULL && ep->length == 0)
502*10465441SEvalZero 		return "null";
503*10465441SEvalZero 	if (ep->class == EPD_IP && ep->length == 4) {
504*10465441SEvalZero 		u32_t addr;
505*10465441SEvalZero 
506*10465441SEvalZero 		GETLONG(addr, p);
507*10465441SEvalZero 		slprintf(str, sizeof(str), "IP:%I", lwip_htonl(addr));
508*10465441SEvalZero 		return str;
509*10465441SEvalZero 	}
510*10465441SEvalZero 
511*10465441SEvalZero 	c = ':';
512*10465441SEvalZero 	c2 = '.';
513*10465441SEvalZero 	if (ep->class == EPD_MAC && ep->length == 6)
514*10465441SEvalZero 		c2 = ':';
515*10465441SEvalZero 	else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0)
516*10465441SEvalZero 		mask = 3;
517*10465441SEvalZero 	q = str;
518*10465441SEvalZero 	if (ep->class <= EPD_PHONENUM)
519*10465441SEvalZero 		q += slprintf(q, sizeof(str)-1, "%s",
520*10465441SEvalZero 			      endp_class_names[ep->class]);
521*10465441SEvalZero 	else
522*10465441SEvalZero 		q += slprintf(q, sizeof(str)-1, "%d", ep->class);
523*10465441SEvalZero 	c = ':';
524*10465441SEvalZero 	for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) {
525*10465441SEvalZero 		if ((i & mask) == 0) {
526*10465441SEvalZero 			*q++ = c;
527*10465441SEvalZero 			c = c2;
528*10465441SEvalZero 		}
529*10465441SEvalZero 		q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]);
530*10465441SEvalZero 	}
531*10465441SEvalZero 	return str;
532*10465441SEvalZero }
533*10465441SEvalZero 
hexc_val(int c)534*10465441SEvalZero static int hexc_val(int c)
535*10465441SEvalZero {
536*10465441SEvalZero 	if (c >= 'a')
537*10465441SEvalZero 		return c - 'a' + 10;
538*10465441SEvalZero 	if (c >= 'A')
539*10465441SEvalZero 		return c - 'A' + 10;
540*10465441SEvalZero 	return c - '0';
541*10465441SEvalZero }
542*10465441SEvalZero 
543*10465441SEvalZero int
str_to_epdisc(ep,str)544*10465441SEvalZero str_to_epdisc(ep, str)
545*10465441SEvalZero      struct epdisc *ep;
546*10465441SEvalZero      char *str;
547*10465441SEvalZero {
548*10465441SEvalZero 	int i, l;
549*10465441SEvalZero 	char *p, *endp;
550*10465441SEvalZero 
551*10465441SEvalZero 	for (i = EPD_NULL; i <= EPD_PHONENUM; ++i) {
552*10465441SEvalZero 		int sl = strlen(endp_class_names[i]);
553*10465441SEvalZero 		if (strncasecmp(str, endp_class_names[i], sl) == 0) {
554*10465441SEvalZero 			str += sl;
555*10465441SEvalZero 			break;
556*10465441SEvalZero 		}
557*10465441SEvalZero 	}
558*10465441SEvalZero 	if (i > EPD_PHONENUM) {
559*10465441SEvalZero 		/* not a class name, try a decimal class number */
560*10465441SEvalZero 		i = strtol(str, &endp, 10);
561*10465441SEvalZero 		if (endp == str)
562*10465441SEvalZero 			return 0;	/* can't parse class number */
563*10465441SEvalZero 		str = endp;
564*10465441SEvalZero 	}
565*10465441SEvalZero 	ep->class = i;
566*10465441SEvalZero 	if (*str == 0) {
567*10465441SEvalZero 		ep->length = 0;
568*10465441SEvalZero 		return 1;
569*10465441SEvalZero 	}
570*10465441SEvalZero 	if (*str != ':' && *str != '.')
571*10465441SEvalZero 		return 0;
572*10465441SEvalZero 	++str;
573*10465441SEvalZero 
574*10465441SEvalZero 	if (i == EPD_IP) {
575*10465441SEvalZero 		u32_t addr;
576*10465441SEvalZero 		i = parse_dotted_ip(str, &addr);
577*10465441SEvalZero 		if (i == 0 || str[i] != 0)
578*10465441SEvalZero 			return 0;
579*10465441SEvalZero 		set_ip_epdisc(ep, addr);
580*10465441SEvalZero 		return 1;
581*10465441SEvalZero 	}
582*10465441SEvalZero 	if (i == EPD_MAC && get_if_hwaddr(ep->value, str) >= 0) {
583*10465441SEvalZero 		ep->length = 6;
584*10465441SEvalZero 		return 1;
585*10465441SEvalZero 	}
586*10465441SEvalZero 
587*10465441SEvalZero 	p = str;
588*10465441SEvalZero 	for (l = 0; l < MAX_ENDP_LEN; ++l) {
589*10465441SEvalZero 		if (*str == 0)
590*10465441SEvalZero 			break;
591*10465441SEvalZero 		if (p <= str)
592*10465441SEvalZero 			for (p = str; isxdigit(*p); ++p)
593*10465441SEvalZero 				;
594*10465441SEvalZero 		i = p - str;
595*10465441SEvalZero 		if (i == 0)
596*10465441SEvalZero 			return 0;
597*10465441SEvalZero 		ep->value[l] = hexc_val(*str++);
598*10465441SEvalZero 		if ((i & 1) == 0)
599*10465441SEvalZero 			ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++);
600*10465441SEvalZero 		if (*str == ':' || *str == '.')
601*10465441SEvalZero 			++str;
602*10465441SEvalZero 	}
603*10465441SEvalZero 	if (*str != 0 || (ep->class == EPD_MAC && l != 6))
604*10465441SEvalZero 		return 0;
605*10465441SEvalZero 	ep->length = l;
606*10465441SEvalZero 	return 1;
607*10465441SEvalZero }
608*10465441SEvalZero 
609*10465441SEvalZero #endif /* PPP_SUPPORT && HAVE_MULTILINK */
610