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