+void mp_exit_bundle()
+{
+ lock_db();
+ remove_bundle_link();
+ unlock_db();
+}
+
+static void sendhup(char *str)
+{
+ int pid;
+
+ if (parse_num(str, "PPPD_PID=", &pid) && pid != getpid()) {
+ if (debug)
+ dbglog("sending SIGHUP to process %d", pid);
+ kill(pid, SIGHUP);
+ }
+}
+
+void mp_bundle_terminated()
+{
+ TDB_DATA key;
+
+ bundle_terminating = 1;
+ upper_layers_down(0);
+ notice("Connection terminated.");
+ print_link_stats();
+ if (!demand) {
+ remove_pidfiles();
+ script_unsetenv("IFNAME");
+ }
+
+ lock_db();
+ destroy_bundle();
+ iterate_bundle_links(sendhup);
+ key.dptr = blinks_id;
+ key.dsize = strlen(blinks_id);
+ tdb_delete(pppdb, key);
+ unlock_db();
+
+ new_phase(PHASE_DEAD);
+
+ doing_multilink = 0;
+ multilink_master = 0;
+}
+
+static void make_bundle_links(int append)
+{
+ TDB_DATA key, rec;
+ char *p;
+ char entry[32];
+ int l;
+
+ key.dptr = blinks_id;
+ key.dsize = strlen(blinks_id);
+ slprintf(entry, sizeof(entry), "%s;", db_key);
+ p = entry;
+ if (append) {
+ rec = tdb_fetch(pppdb, key);
+ if (rec.dptr != NULL && rec.dsize > 0) {
+ rec.dptr[rec.dsize-1] = 0;
+ if (strstr(rec.dptr, db_key) != NULL) {
+ /* already in there? strange */
+ warn("link entry already exists in tdb");
+ return;
+ }
+ l = rec.dsize + strlen(entry);
+ p = malloc(l);
+ if (p == NULL)
+ novm("bundle link list");
+ slprintf(p, l, "%s%s", rec.dptr, entry);
+ } else {
+ warn("bundle link list not found");
+ }
+ if (rec.dptr != NULL)
+ free(rec.dptr);
+ }
+ rec.dptr = p;
+ rec.dsize = strlen(p) + 1;
+ if (tdb_store(pppdb, key, rec, TDB_REPLACE))
+ error("couldn't %s bundle link list",
+ append? "update": "create");
+ if (p != entry)
+ free(p);
+}
+
+static void remove_bundle_link()
+{
+ TDB_DATA key, rec;
+ char entry[32];
+ char *p, *q;
+ int l;
+
+ key.dptr = blinks_id;
+ key.dsize = strlen(blinks_id);
+ slprintf(entry, sizeof(entry), "%s;", db_key);
+
+ rec = tdb_fetch(pppdb, key);
+ if (rec.dptr == NULL || rec.dsize <= 0) {
+ if (rec.dptr != NULL)
+ free(rec.dptr);
+ return;
+ }
+ rec.dptr[rec.dsize-1] = 0;
+ p = strstr(rec.dptr, entry);
+ if (p != NULL) {
+ q = p + strlen(entry);
+ l = strlen(q) + 1;
+ memmove(p, q, l);
+ rec.dsize = p - rec.dptr + l;
+ if (tdb_store(pppdb, key, rec, TDB_REPLACE))
+ error("couldn't update bundle link list (removal)");
+ }
+ free(rec.dptr);
+}
+
+static void iterate_bundle_links(void (*func)(char *))
+{
+ TDB_DATA key, rec, pp;
+ char *p, *q;
+
+ key.dptr = blinks_id;
+ key.dsize = strlen(blinks_id);
+ rec = tdb_fetch(pppdb, key);
+ if (rec.dptr == NULL || rec.dsize <= 0) {
+ error("bundle link list not found (iterating list)");
+ if (rec.dptr != NULL)
+ free(rec.dptr);
+ return;
+ }
+ p = rec.dptr;
+ p[rec.dsize-1] = 0;
+ while ((q = strchr(p, ';')) != NULL) {
+ *q = 0;
+ key.dptr = p;
+ key.dsize = q - p;
+ pp = tdb_fetch(pppdb, key);
+ if (pp.dptr != NULL && pp.dsize > 0) {
+ pp.dptr[pp.dsize-1] = 0;
+ func(pp.dptr);
+ }
+ if (pp.dptr != NULL)
+ free(pp.dptr);
+ p = q + 1;
+ }
+ free(rec.dptr);
+}
+