Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
lwip_multilink.c
00001 /* 00002 * multilink.c - support routines for multilink. 00003 * 00004 * Copyright (c) 2000-2002 Paul Mackerras. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 00010 * 1. Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 00013 * 2. The name(s) of the authors of this software must not be used to 00014 * endorse or promote products derived from this software without 00015 * prior written permission. 00016 * 00017 * 3. Redistributions of any form whatsoever must retain the following 00018 * acknowledgment: 00019 * "This product includes software developed by Paul Mackerras 00020 * <paulus@samba.org>". 00021 * 00022 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 00023 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00024 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 00025 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00026 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 00027 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 00028 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00029 */ 00030 00031 #include "netif/ppp/ppp_opts.h" 00032 #if PPP_SUPPORT && defined(HAVE_MULTILINK) /* don't build if not configured for use in lwipopts.h */ 00033 00034 /* Multilink support 00035 * 00036 * Multilink uses Samba TDB (Trivial Database Library), which 00037 * we cannot port, because it needs a filesystem. 00038 * 00039 * We have to choose between doing a memory-shared TDB-clone, 00040 * or dropping multilink support at all. 00041 */ 00042 00043 #include <string.h> 00044 #include <ctype.h> 00045 #include <stdlib.h> 00046 #include <netdb.h> 00047 #include <errno.h> 00048 #include <signal.h> 00049 #include <netinet/in.h> 00050 #include <unistd.h> 00051 00052 #include "netif/ppp/ppp_impl.h" 00053 00054 #include "netif/ppp/fsm.h" 00055 #include "netif/ppp/lcp.h" 00056 #include "netif/ppp/tdb.h" 00057 00058 bool endpoint_specified; /* user gave explicit endpoint discriminator */ 00059 char *bundle_id; /* identifier for our bundle */ 00060 char *blinks_id; /* key for the list of links */ 00061 bool doing_multilink; /* multilink was enabled and agreed to */ 00062 bool multilink_master; /* we own the multilink bundle */ 00063 00064 extern TDB_CONTEXT *pppdb; 00065 extern char db_key[]; 00066 00067 static void make_bundle_links (int append); 00068 static void remove_bundle_link (void); 00069 static void iterate_bundle_links (void (*func) (char *)); 00070 00071 static int get_default_epdisc (struct epdisc *); 00072 static int parse_num (char *str, const char *key, int *valp); 00073 static int owns_unit (TDB_DATA pid, int unit); 00074 00075 #define set_ip_epdisc(ep, addr) do { \ 00076 ep->length = 4; \ 00077 ep->value[0] = addr >> 24; \ 00078 ep->value[1] = addr >> 16; \ 00079 ep->value[2] = addr >> 8; \ 00080 ep->value[3] = addr; \ 00081 } while (0) 00082 00083 #define LOCAL_IP_ADDR(addr) \ 00084 (((addr) & 0xff000000) == 0x0a000000 /* 10.x.x.x */ \ 00085 || ((addr) & 0xfff00000) == 0xac100000 /* 172.16.x.x */ \ 00086 || ((addr) & 0xffff0000) == 0xc0a80000) /* 192.168.x.x */ 00087 00088 #define process_exists(n) (kill((n), 0) == 0 || errno != ESRCH) 00089 00090 void 00091 mp_check_options() 00092 { 00093 lcp_options *wo = &lcp_wantoptions[0]; 00094 lcp_options *ao = &lcp_allowoptions[0]; 00095 00096 doing_multilink = 0; 00097 if (!multilink) 00098 return; 00099 /* if we're doing multilink, we have to negotiate MRRU */ 00100 if (!wo->neg_mrru) { 00101 /* mrru not specified, default to mru */ 00102 wo->mrru = wo->mru; 00103 wo->neg_mrru = 1; 00104 } 00105 ao->mrru = ao->mru; 00106 ao->neg_mrru = 1; 00107 00108 if (!wo->neg_endpoint && !noendpoint) { 00109 /* get a default endpoint value */ 00110 wo->neg_endpoint = get_default_epdisc(&wo->endpoint); 00111 } 00112 } 00113 00114 /* 00115 * Make a new bundle or join us to an existing bundle 00116 * if we are doing multilink. 00117 */ 00118 int 00119 mp_join_bundle() 00120 { 00121 lcp_options *go = &lcp_gotoptions[0]; 00122 lcp_options *ho = &lcp_hisoptions[0]; 00123 lcp_options *ao = &lcp_allowoptions[0]; 00124 int unit, pppd_pid; 00125 int l, mtu; 00126 char *p; 00127 TDB_DATA key, pid, rec; 00128 00129 if (doing_multilink) { 00130 /* have previously joined a bundle */ 00131 if (!go->neg_mrru || !ho->neg_mrru) { 00132 notice("oops, didn't get multilink on renegotiation"); 00133 lcp_close(pcb, "multilink required"); 00134 return 0; 00135 } 00136 /* XXX should check the peer_authname and ho->endpoint 00137 are the same as previously */ 00138 return 0; 00139 } 00140 00141 if (!go->neg_mrru || !ho->neg_mrru) { 00142 /* not doing multilink */ 00143 if (go->neg_mrru) 00144 notice("oops, multilink negotiated only for receive"); 00145 mtu = ho->neg_mru? ho->mru: PPP_MRU; 00146 if (mtu > ao->mru) 00147 mtu = ao->mru; 00148 if (demand) { 00149 /* already have a bundle */ 00150 cfg_bundle(0, 0, 0, 0); 00151 netif_set_mtu(pcb, mtu); 00152 return 0; 00153 } 00154 make_new_bundle(0, 0, 0, 0); 00155 set_ifunit(1); 00156 netif_set_mtu(pcb, mtu); 00157 return 0; 00158 } 00159 00160 doing_multilink = 1; 00161 00162 /* 00163 * Find the appropriate bundle or join a new one. 00164 * First we make up a name for the bundle. 00165 * The length estimate is worst-case assuming every 00166 * character has to be quoted. 00167 */ 00168 l = 4 * strlen(peer_authname) + 10; 00169 if (ho->neg_endpoint) 00170 l += 3 * ho->endpoint.length + 8; 00171 if (bundle_name) 00172 l += 3 * strlen(bundle_name) + 2; 00173 bundle_id = malloc(l); 00174 if (bundle_id == 0) 00175 novm("bundle identifier"); 00176 00177 p = bundle_id; 00178 p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname); 00179 if (ho->neg_endpoint || bundle_name) 00180 *p++ = '/'; 00181 if (ho->neg_endpoint) 00182 p += slprintf(p, bundle_id+l-p, "%s", 00183 epdisc_to_str(&ho->endpoint)); 00184 if (bundle_name) 00185 p += slprintf(p, bundle_id+l-p, "/%v", bundle_name); 00186 00187 /* Make the key for the list of links belonging to the bundle */ 00188 l = p - bundle_id; 00189 blinks_id = malloc(l + 7); 00190 if (blinks_id == NULL) 00191 novm("bundle links key"); 00192 slprintf(blinks_id, l + 7, "BUNDLE_LINKS=%s", bundle_id + 7); 00193 00194 /* 00195 * For demand mode, we only need to configure the bundle 00196 * and attach the link. 00197 */ 00198 mtu = LWIP_MIN(ho->mrru, ao->mru); 00199 if (demand) { 00200 cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); 00201 netif_set_mtu(pcb, mtu); 00202 script_setenv("BUNDLE", bundle_id + 7, 1); 00203 return 0; 00204 } 00205 00206 /* 00207 * Check if the bundle ID is already in the database. 00208 */ 00209 unit = -1; 00210 lock_db(); 00211 key.dptr = bundle_id; 00212 key.dsize = p - bundle_id; 00213 pid = tdb_fetch(pppdb, key); 00214 if (pid.dptr != NULL) { 00215 /* bundle ID exists, see if the pppd record exists */ 00216 rec = tdb_fetch(pppdb, pid); 00217 if (rec.dptr != NULL && rec.dsize > 0) { 00218 /* make sure the string is null-terminated */ 00219 rec.dptr[rec.dsize-1] = 0; 00220 /* parse the interface number */ 00221 parse_num(rec.dptr, "IFNAME=ppp", &unit); 00222 /* check the pid value */ 00223 if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid) 00224 || !process_exists(pppd_pid) 00225 || !owns_unit(pid, unit)) 00226 unit = -1; 00227 free(rec.dptr); 00228 } 00229 free(pid.dptr); 00230 } 00231 00232 if (unit >= 0) { 00233 /* attach to existing unit */ 00234 if (bundle_attach(unit)) { 00235 set_ifunit(0); 00236 script_setenv("BUNDLE", bundle_id + 7, 0); 00237 make_bundle_links(1); 00238 unlock_db(); 00239 info("Link attached to %s", ifname); 00240 return 1; 00241 } 00242 /* attach failed because bundle doesn't exist */ 00243 } 00244 00245 /* we have to make a new bundle */ 00246 make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); 00247 set_ifunit(1); 00248 netif_set_mtu(pcb, mtu); 00249 script_setenv("BUNDLE", bundle_id + 7, 1); 00250 make_bundle_links(pcb); 00251 unlock_db(); 00252 info("New bundle %s created", ifname); 00253 multilink_master = 1; 00254 return 0; 00255 } 00256 00257 void mp_exit_bundle() 00258 { 00259 lock_db(); 00260 remove_bundle_link(); 00261 unlock_db(); 00262 } 00263 00264 static void sendhup(char *str) 00265 { 00266 int pid; 00267 00268 if (parse_num(str, "PPPD_PID=", &pid) && pid != getpid()) { 00269 if (debug) 00270 dbglog("sending SIGHUP to process %d", pid); 00271 kill(pid, SIGHUP); 00272 } 00273 } 00274 00275 void mp_bundle_terminated() 00276 { 00277 TDB_DATA key; 00278 00279 bundle_terminating = 1; 00280 upper_layers_down(pcb); 00281 notice("Connection terminated."); 00282 #if PPP_STATS_SUPPORT 00283 print_link_stats(); 00284 #endif /* PPP_STATS_SUPPORT */ 00285 if (!demand) { 00286 remove_pidfiles(); 00287 script_unsetenv("IFNAME"); 00288 } 00289 00290 lock_db(); 00291 destroy_bundle(); 00292 iterate_bundle_links(sendhup); 00293 key.dptr = blinks_id; 00294 key.dsize = strlen(blinks_id); 00295 tdb_delete(pppdb, key); 00296 unlock_db(); 00297 00298 new_phase(PPP_PHASE_DEAD); 00299 00300 doing_multilink = 0; 00301 multilink_master = 0; 00302 } 00303 00304 static void make_bundle_links(int append) 00305 { 00306 TDB_DATA key, rec; 00307 char *p; 00308 char entry[32]; 00309 int l; 00310 00311 key.dptr = blinks_id; 00312 key.dsize = strlen(blinks_id); 00313 slprintf(entry, sizeof(entry), "%s;", db_key); 00314 p = entry; 00315 if (append) { 00316 rec = tdb_fetch(pppdb, key); 00317 if (rec.dptr != NULL && rec.dsize > 0) { 00318 rec.dptr[rec.dsize-1] = 0; 00319 if (strstr(rec.dptr, db_key) != NULL) { 00320 /* already in there? strange */ 00321 warn("link entry already exists in tdb"); 00322 return; 00323 } 00324 l = rec.dsize + strlen(entry); 00325 p = malloc(l); 00326 if (p == NULL) 00327 novm("bundle link list"); 00328 slprintf(p, l, "%s%s", rec.dptr, entry); 00329 } else { 00330 warn("bundle link list not found"); 00331 } 00332 if (rec.dptr != NULL) 00333 free(rec.dptr); 00334 } 00335 rec.dptr = p; 00336 rec.dsize = strlen(p) + 1; 00337 if (tdb_store(pppdb, key, rec, TDB_REPLACE)) 00338 error("couldn't %s bundle link list", 00339 append? "update": "create"); 00340 if (p != entry) 00341 free(p); 00342 } 00343 00344 static void remove_bundle_link() 00345 { 00346 TDB_DATA key, rec; 00347 char entry[32]; 00348 char *p, *q; 00349 int l; 00350 00351 key.dptr = blinks_id; 00352 key.dsize = strlen(blinks_id); 00353 slprintf(entry, sizeof(entry), "%s;", db_key); 00354 00355 rec = tdb_fetch(pppdb, key); 00356 if (rec.dptr == NULL || rec.dsize <= 0) { 00357 if (rec.dptr != NULL) 00358 free(rec.dptr); 00359 return; 00360 } 00361 rec.dptr[rec.dsize-1] = 0; 00362 p = strstr(rec.dptr, entry); 00363 if (p != NULL) { 00364 q = p + strlen(entry); 00365 l = strlen(q) + 1; 00366 memmove(p, q, l); 00367 rec.dsize = p - rec.dptr + l; 00368 if (tdb_store(pppdb, key, rec, TDB_REPLACE)) 00369 error("couldn't update bundle link list (removal)"); 00370 } 00371 free(rec.dptr); 00372 } 00373 00374 static void iterate_bundle_links(void (*func)(char *)) 00375 { 00376 TDB_DATA key, rec, pp; 00377 char *p, *q; 00378 00379 key.dptr = blinks_id; 00380 key.dsize = strlen(blinks_id); 00381 rec = tdb_fetch(pppdb, key); 00382 if (rec.dptr == NULL || rec.dsize <= 0) { 00383 error("bundle link list not found (iterating list)"); 00384 if (rec.dptr != NULL) 00385 free(rec.dptr); 00386 return; 00387 } 00388 p = rec.dptr; 00389 p[rec.dsize-1] = 0; 00390 while ((q = strchr(p, ';')) != NULL) { 00391 *q = 0; 00392 key.dptr = p; 00393 key.dsize = q - p; 00394 pp = tdb_fetch(pppdb, key); 00395 if (pp.dptr != NULL && pp.dsize > 0) { 00396 pp.dptr[pp.dsize-1] = 0; 00397 func(pp.dptr); 00398 } 00399 if (pp.dptr != NULL) 00400 free(pp.dptr); 00401 p = q + 1; 00402 } 00403 free(rec.dptr); 00404 } 00405 00406 static int 00407 parse_num(str, key, valp) 00408 char *str; 00409 const char *key; 00410 int *valp; 00411 { 00412 char *p, *endp; 00413 int i; 00414 00415 p = strstr(str, key); 00416 if (p != 0) { 00417 p += strlen(key); 00418 i = strtol(p, &endp, 10); 00419 if (endp != p && (*endp == 0 || *endp == ';')) { 00420 *valp = i; 00421 return 1; 00422 } 00423 } 00424 return 0; 00425 } 00426 00427 /* 00428 * Check whether the pppd identified by `key' still owns ppp unit `unit'. 00429 */ 00430 static int 00431 owns_unit(key, unit) 00432 TDB_DATA key; 00433 int unit; 00434 { 00435 char ifkey[32]; 00436 TDB_DATA kd, vd; 00437 int ret = 0; 00438 00439 slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit); 00440 kd.dptr = ifkey; 00441 kd.dsize = strlen(ifkey); 00442 vd = tdb_fetch(pppdb, kd); 00443 if (vd.dptr != NULL) { 00444 ret = vd.dsize == key.dsize 00445 && memcmp(vd.dptr, key.dptr, vd.dsize) == 0; 00446 free(vd.dptr); 00447 } 00448 return ret; 00449 } 00450 00451 static int 00452 get_default_epdisc(ep) 00453 struct epdisc *ep; 00454 { 00455 char *p; 00456 struct hostent *hp; 00457 u32_t addr; 00458 00459 /* First try for an ethernet MAC address */ 00460 p = get_first_ethernet(); 00461 if (p != 0 && get_if_hwaddr(ep->value, p) >= 0) { 00462 ep->class = EPD_MAC; 00463 ep->length = 6; 00464 return 1; 00465 } 00466 00467 /* see if our hostname corresponds to a reasonable IP address */ 00468 hp = gethostbyname(hostname); 00469 if (hp != NULL) { 00470 addr = *(u32_t *)hp->h_addr; 00471 if (!bad_ip_adrs(addr)) { 00472 addr = lwip_ntohl(addr); 00473 if (!LOCAL_IP_ADDR(addr)) { 00474 ep->class = EPD_IP; 00475 set_ip_epdisc(ep, addr); 00476 return 1; 00477 } 00478 } 00479 } 00480 00481 return 0; 00482 } 00483 00484 /* 00485 * epdisc_to_str - make a printable string from an endpoint discriminator. 00486 */ 00487 00488 static char *endp_class_names[] = { 00489 "null", "local", "IP", "MAC", "magic", "phone" 00490 }; 00491 00492 char * 00493 epdisc_to_str(ep) 00494 struct epdisc *ep; 00495 { 00496 static char str[MAX_ENDP_LEN*3+8]; 00497 u_char *p = ep->value; 00498 int i, mask = 0; 00499 char *q, c, c2; 00500 00501 if (ep->class == EPD_NULL && ep->length == 0) 00502 return "null"; 00503 if (ep->class == EPD_IP && ep->length == 4) { 00504 u32_t addr; 00505 00506 GETLONG(addr, p); 00507 slprintf(str, sizeof(str), "IP:%I", lwip_htonl(addr)); 00508 return str; 00509 } 00510 00511 c = ':'; 00512 c2 = '.'; 00513 if (ep->class == EPD_MAC && ep->length == 6) 00514 c2 = ':'; 00515 else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0) 00516 mask = 3; 00517 q = str; 00518 if (ep->class <= EPD_PHONENUM) 00519 q += slprintf(q, sizeof(str)-1, "%s", 00520 endp_class_names[ep->class]); 00521 else 00522 q += slprintf(q, sizeof(str)-1, "%d", ep->class); 00523 c = ':'; 00524 for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) { 00525 if ((i & mask) == 0) { 00526 *q++ = c; 00527 c = c2; 00528 } 00529 q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]); 00530 } 00531 return str; 00532 } 00533 00534 static int hexc_val(int c) 00535 { 00536 if (c >= 'a') 00537 return c - 'a' + 10; 00538 if (c >= 'A') 00539 return c - 'A' + 10; 00540 return c - '0'; 00541 } 00542 00543 int 00544 str_to_epdisc(ep, str) 00545 struct epdisc *ep; 00546 char *str; 00547 { 00548 int i, l; 00549 char *p, *endp; 00550 00551 for (i = EPD_NULL; i <= EPD_PHONENUM; ++i) { 00552 int sl = strlen(endp_class_names[i]); 00553 if (strncasecmp(str, endp_class_names[i], sl) == 0) { 00554 str += sl; 00555 break; 00556 } 00557 } 00558 if (i > EPD_PHONENUM) { 00559 /* not a class name, try a decimal class number */ 00560 i = strtol(str, &endp, 10); 00561 if (endp == str) 00562 return 0; /* can't parse class number */ 00563 str = endp; 00564 } 00565 ep->class = i; 00566 if (*str == 0) { 00567 ep->length = 0; 00568 return 1; 00569 } 00570 if (*str != ':' && *str != '.') 00571 return 0; 00572 ++str; 00573 00574 if (i == EPD_IP) { 00575 u32_t addr; 00576 i = parse_dotted_ip(str, &addr); 00577 if (i == 0 || str[i] != 0) 00578 return 0; 00579 set_ip_epdisc(ep, addr); 00580 return 1; 00581 } 00582 if (i == EPD_MAC && get_if_hwaddr(ep->value, str) >= 0) { 00583 ep->length = 6; 00584 return 1; 00585 } 00586 00587 p = str; 00588 for (l = 0; l < MAX_ENDP_LEN; ++l) { 00589 if (*str == 0) 00590 break; 00591 if (p <= str) 00592 for (p = str; isxdigit(*p); ++p) 00593 ; 00594 i = p - str; 00595 if (i == 0) 00596 return 0; 00597 ep->value[l] = hexc_val(*str++); 00598 if ((i & 1) == 0) 00599 ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++); 00600 if (*str == ':' || *str == '.') 00601 ++str; 00602 } 00603 if (*str != 0 || (ep->class == EPD_MAC && l != 6)) 00604 return 0; 00605 ep->length = l; 00606 return 1; 00607 } 00608 00609 #endif /* PPP_SUPPORT && HAVE_MULTILINK */
Generated on Sun Jul 17 2022 08:25:24 by 1.7.2