static void test_10() { int i; slist sl; slist *l = &sl; slist_init(l); slist_add(l, (void *)1); slist_add(l, (void *)2); slist_add(l, (void *)3); slist_itr_first(l); ASSERT((int)slist_itr_next(l) == 1); ASSERT((int)slist_itr_next(l) == 2); for (i = 4; i < 10000; i++) { ASSERT(slist_itr_has_next(l)); ASSERT((int)slist_itr_next(l) == i - 1); if (i % 3 == 1) slist_add(l, (void *)i); if (i % 3 == 0) ASSERT((int)slist_itr_remove(l) == i - 1); if (i % 3 != 1) slist_add(l, (void *)i); } slist_itr_first(l); while (slist_itr_has_next(l)) { slist_itr_next(l); slist_itr_remove(l); } ASSERT((int)slist_length(l) == 0); slist_fini(l); }
static void test_itr_subr_01(slist *l) { int i; for (i = 0; i < slist_length(l); i++) slist_set(l, i, (void *)(i + 1)); slist_itr_first(l); ASSERT((int)slist_itr_next(l) == 1); /* normal iterate */ ASSERT((int)slist_itr_next(l) == 2); /* normal iterate */ slist_remove(l, 2); /* remove next. "3" is removed */ ASSERT((int)slist_itr_next(l) == 4); /* removed item is skipped */ slist_remove(l, 1); /* remove past item. "2" is removed */ ASSERT((int)slist_itr_next(l) == 5); /* no influence */ ASSERT((int)slist_get(l, 0) == 1); /* checking for removing */ ASSERT((int)slist_get(l, 1) == 4); /* checking for removing */ ASSERT((int)slist_get(l, 2) == 5); /* checking for removing */ /* * Total number was 255. We removed 2 items and iterated 4 times. * 1 removing was past item, so the remaining is 250. */ for (i = 0; i < 249; i++) ASSERT(slist_itr_next(l) != NULL); ASSERT(slist_itr_next(l) != NULL); ASSERT(slist_itr_next(l) == NULL); /* * Same as above except removing before getting the last item. */ /* Reset (253 items) */ for (i = 0; i < slist_length(l); i++) slist_set(l, i, (void *)(i + 1)); slist_itr_first(l); ASSERT(slist_length(l) == 253); for (i = 0; i < 252; i++) ASSERT(slist_itr_next(l) != NULL); slist_remove(l, 252); ASSERT(slist_itr_next(l) == NULL); /* The last item is NULL */ slist_itr_first(l); while (slist_length(l) > 0) slist_remove_first(l); ASSERT(slist_length(l) == 0); ASSERT(slist_itr_next(l) == NULL); }
static void test_08() { slist sl; slist *l = &sl; slist_init(l); slist_set_size(l, 4); slist_add(l, (void *)1); slist_add(l, (void *)2); slist_add(l, (void *)3); /* [1, 2, 3] */ slist_itr_first(l); slist_itr_has_next(l); slist_itr_next(l); slist_itr_remove(l); /* [2, 3] */ slist_add(l, (void *)4); /* [2, 3, 4] */ ASSERT((int)slist_get(l, 0) == 2); ASSERT((int)slist_get(l, 1) == 3); ASSERT((int)slist_get(l, 2) == 4); slist_add(l, (void *)5); /* [2, 3, 4, 5] */ ASSERT((int)slist_get(l, 0) == 2); ASSERT((int)slist_get(l, 1) == 3); ASSERT((int)slist_get(l, 2) == 4); ASSERT((int)slist_get(l, 3) == 5); }
/* finalize L2TP daemon instance */ void l2tpd_uninit(l2tpd *_this) { l2tpd_listener *plsnr; L2TPD_ASSERT(_this != NULL); slist_fini(&_this->free_session_id_list); if (_this->ctrl_map != NULL) { hash_free(_this->ctrl_map); _this->ctrl_map = NULL; } slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { plsnr = slist_itr_next(&_this->listener); L2TPD_ASSERT(plsnr != NULL); L2TPD_ASSERT(plsnr->sock == -1); free(plsnr); } slist_fini(&_this->listener); event_del(&_this->ev_timeout); /* just in case */ _this->state = L2TPD_STATE_STOPPED; }
void pptpd_uninit(pptpd *_this) { pptpd_listener *plstn; slist_fini(&_this->ctrl_list); slist_fini(&_this->call_free_list); slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { plstn = slist_itr_next(&_this->listener); PPTPD_ASSERT(plstn != NULL); PPTPD_ASSERT(plstn->sock == -1); PPTPD_ASSERT(plstn->sock_gre == -1); free(plstn); } slist_fini(&_this->listener); if (_this->call_id_map != NULL) { hash_free(_this->call_id_map); } if (_this->ip4_allow != NULL) in_addr_range_list_remove_all(&_this->ip4_allow); _this->call_id_map = NULL; _this->config = NULL; }
int pptpd_assign_call(pptpd *_this, pptp_call *call) { int shuffle_cnt = 0, call_id; shuffle_cnt = 0; slist_itr_first(&_this->call_free_list); while (slist_length(&_this->call_free_list) > 1 && slist_itr_has_next(&_this->call_free_list)) { call_id = (int)slist_itr_next(&_this->call_free_list); if (call_id == 0) break; slist_itr_remove(&_this->call_free_list); if (call_id == PPTPD_SHUFFLE_MARK) { if (shuffle_cnt++ > 0) break; slist_shuffle(&_this->call_free_list); slist_add(&_this->call_free_list, (void *)PPTPD_SHUFFLE_MARK); slist_itr_first(&_this->call_free_list); continue; } call->id = call_id; hash_insert(_this->call_id_map, CALL_MAP_KEY(call), call); return 0; } errno = EBUSY; pptpd_log(_this, LOG_ERR, "call request reached limit=%d", PPTP_MAX_CALL); return -1; }
/* start L2TP daemon */ int l2tpd_start(l2tpd *_this) { int rval; l2tpd_listener *plsnr; rval = 0; L2TPD_ASSERT(_this->state == L2TPD_STATE_INIT); if (_this->state != L2TPD_STATE_INIT) { l2tpd_log(_this, LOG_ERR, "Failed to start l2tpd: illegal " "state."); return -1; } slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { plsnr = slist_itr_next(&_this->listener); rval |= l2tpd_listener_start(plsnr); } if (rval == 0) _this->state = L2TPD_STATE_RUNNING; return rval; }
/* stop PPPoE daemon */ void pppoed_stop(pppoed *_this) { pppoed_listener *plistener; hash_link *hl; pppoe_session *session; if (!pppoed_is_running(_this)) return; _this->state = PPPOED_STATE_STOPPED; if (_this->session_hash != NULL) { for (hl = hash_first(_this->session_hash); hl != NULL; hl = hash_next(_this->session_hash)) { session = (pppoe_session *)hl->item; pppoe_session_disconnect(session); pppoe_session_stop(session); } } for (slist_itr_first(&_this->listener); slist_itr_has_next(&_this->listener);) { plistener = slist_itr_next(&_this->listener); pppoed_listener_stop(plistener); free(plistener); slist_itr_remove(&_this->listener); } PPPOED_DBG((_this, LOG_DEBUG, "Stopped")); }
/* start PPPoE daemon */ int pppoed_start(pppoed *_this) { int rval = 0; int nlistener_fail = 0; pppoed_listener *plistener; slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { plistener = slist_itr_next(&_this->listener); PPPOED_ASSERT(plistener != NULL); if (plistener->bpf < 0) { if (pppoed_listener_start(plistener, _this->listen_incomplete) != 0) nlistener_fail++; } } if (nlistener_fail > 0) _this->listen_incomplete = 1; else _this->listen_incomplete = 0; _this->state = PPPOED_STATE_RUNNING; return rval; }
/* * Configuration */ int l2tpd_reload(l2tpd *_this, struct l2tp_confs *l2tp_conf) { int i; struct l2tp_conf *conf; l2tpd_listener *listener; struct l2tp_listen_addr *addr; if (slist_length(&_this->listener) > 0) { /* * TODO: add / remove / restart listener. */ slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { listener = slist_itr_next(&_this->listener); TAILQ_FOREACH(conf, l2tp_conf, entry) { if (strcmp(listener->tun_name, conf->name) == 0) { listener->conf = conf; break; } } } return 0; }
static void pptpd_close_1723(pptpd *_this) { pptpd_listener *plistener; slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { plistener = slist_itr_next(&_this->listener); pptpd_listener_close_1723(plistener); } }
/* stop immediattly without disconnect operation */ void l2tpd_stop_immediatly(l2tpd *_this) { l2tpd_listener *plsnr; slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { plsnr = slist_itr_next(&_this->listener); l2tpd_listener_stop(plsnr); } event_del(&_this->ev_timeout); /* XXX */ _this->state = L2TPD_STATE_STOPPED; }
/* * Add a {@link :l2tpd_listener} to the {@link ::l2tpd L2TP daemon} * @param _this {@link ::l2tpd L2TP daemon} * @param idx index of the lisnter * @param tun_name tunnel name (ex. "L2TP") * @param bindaddr bind address */ int l2tpd_add_listener(l2tpd *_this, int idx, struct l2tp_conf *conf, struct sockaddr *addr) { l2tpd_listener *plistener, *plsnr; plistener = NULL; if (idx == 0 && slist_length(&_this->listener) > 0) { slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { slist_itr_next(&_this->listener); plsnr = slist_itr_remove(&_this->listener); L2TPD_ASSERT(plsnr != NULL); L2TPD_ASSERT(plsnr->sock == -1); free(plsnr); } } L2TPD_ASSERT(slist_length(&_this->listener) == idx); if (slist_length(&_this->listener) != idx) { l2tpd_log(_this, LOG_ERR, "Invalid argument error on %s(): idx must be %d but %d", __func__, slist_length(&_this->listener), idx); goto fail; } if ((plistener = calloc(1, sizeof(l2tpd_listener))) == NULL) { l2tpd_log(_this, LOG_ERR, "calloc() failed in %s: %m", __func__); goto fail; } L2TPD_ASSERT(sizeof(plistener->bind) >= addr->sa_len); memcpy(&plistener->bind, addr, addr->sa_len); if (plistener->bind.sin6.sin6_port == 0) plistener->bind.sin6.sin6_port = htons(L2TPD_DEFAULT_UDP_PORT); plistener->sock = -1; plistener->self = _this; plistener->index = idx; plistener->conf = conf; strlcpy(plistener->tun_name, conf->name, sizeof(plistener->tun_name)); if (slist_add(&_this->listener, plistener) == NULL) { l2tpd_log(_this, LOG_ERR, "slist_add() failed in %s: %m", __func__); goto fail; } return 0; fail: free(plistener); return 1; }
int pptpd_start(pptpd *_this) { int rval = 0; pptpd_listener *plistener; slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { plistener = slist_itr_next(&_this->listener); PPTPD_ASSERT(plistener != NULL); rval |= pptpd_listener_start(plistener); } if (rval == 0) _this->state = PPTPD_STATE_RUNNING; return rval; }
/* process PADR from the peer */ int pppoe_session_recv_PADR(pppoe_session *_this, slist *tag_list) { pppoed *pppoed0 = _this->pppoed; struct pppoe_tlv *tlv, *hostuniq, *service_name, *ac_cookie; service_name = NULL; hostuniq = NULL; ac_cookie = NULL; for (slist_itr_first(tag_list); slist_itr_has_next(tag_list); ) { tlv = slist_itr_next(tag_list); if (tlv->type == PPPOE_TAG_HOST_UNIQ) hostuniq = tlv; if (tlv->type == PPPOE_TAG_SERVICE_NAME) service_name = tlv; if (tlv->type == PPPOE_TAG_AC_COOKIE) ac_cookie = tlv; } if (ac_cookie) { /* avoid a session which has already has cookie. */ if (hash_lookup(pppoed0->acookie_hash, (void *)ac_cookie->value) != NULL) goto fail; _this->acookie = *(uint32_t *)(ac_cookie->value); hash_insert(pppoed0->acookie_hash, (void *)(intptr_t)_this->acookie, _this); } if (pppoe_session_send_PADS(_this, hostuniq, service_name) != 0) goto fail; if (pppoe_session_bind_ppp(_this) != 0) goto fail; _this->state = PPPOE_SESSION_STATE_RUNNING; return 0; fail: return -1; }
static void test_07() { int i; slist sl; slist *l = &sl; slist_init(l); slist_add(l, (void *)1); slist_remove_first(l); l->first_idx = 120; l->last_idx = 120; for (i = 0; i < 255; i++) slist_add(l, (void *)i); for (i = 0, slist_itr_first(l); slist_itr_has_next(l); i++) { ASSERT((int)slist_itr_next(l) == i); if (i > 200) ASSERT((int)slist_itr_remove(l) == i); } }
static void test_06() { int i, j; slist sl; slist *l = &sl; slist_init(l); for (i = 0; i < 255; i++) slist_add(l, (void *)i); i = 255; for (slist_itr_first(l); slist_itr_has_next(l); ) { ASSERT(slist_length(l) == i); slist_itr_next(l); ASSERT((int)slist_itr_remove(l) == 255 - i); ASSERT(slist_length(l) == i - 1); for (j = i; j < slist_length(l); j++) ASSERT((int)slist_get(l, j) == i + j); i--; } }
void pptpd_stop(pptpd *_this) { int nctrl; pptp_ctrl *ctrl; struct timeval tv; if (event_initialized(&_this->ev_timer)) evtimer_del(&_this->ev_timer); pptpd_close_1723(_this); /* XXX: use common procedure with l2tpd_stop */ if (pptpd_is_stopped(_this)) return; if (pptpd_is_shutting_down(_this)) { pptpd_stop_immediatly(_this); return; } _this->state = PPTPD_STATE_SHUTTING_DOWN; nctrl = 0; for (slist_itr_first(&_this->ctrl_list); (ctrl = slist_itr_next(&_this->ctrl_list)) != NULL;) { pptp_ctrl_stop(ctrl, PPTP_CDN_RESULT_ADMIN_SHUTDOWN); nctrl++; } if (nctrl > 0) { tv.tv_sec = PPTPD_SHUTDOWN_TIMEOUT; tv.tv_usec = 0; evtimer_set(&_this->ev_timer, pptpd_stop_timeout, _this); evtimer_add(&_this->ev_timer, &tv); return; } pptpd_stop_immediatly(_this); }
void pptpd_stop_immediatly(pptpd *_this) { pptp_ctrl *ctrl; if (event_initialized(&_this->ev_timer)) evtimer_del(&_this->ev_timer); if (_this->state != PPTPD_STATE_STOPPED) { /* lock, to avoid multiple call from pptp_ctrl_stop() */ _this->state = PPTPD_STATE_STOPPED; pptpd_close_1723(_this); for (slist_itr_first(&_this->ctrl_list); (ctrl = slist_itr_next(&_this->ctrl_list)) != NULL;) { pptp_ctrl_stop(ctrl, 0); } pptpd_close_gre(_this); slist_fini(&_this->ctrl_list); slist_fini(&_this->call_free_list); pptpd_log(_this, LOG_NOTICE, "Stopped"); } else { PPTPD_DBG((_this, LOG_DEBUG, "(Already) Stopped")); } }
static void test_09() { slist sl; slist *l = &sl; /* * #1 */ slist_init(l); slist_set_size(l, 3); slist_add(l, (void *)1); slist_add(l, (void *)2); slist_add(l, (void *)3); slist_itr_first(l); ASSERT((int)slist_itr_next(l) == 1); /* 1 */ ASSERT((int)slist_itr_next(l) == 2); /* 2 */ ASSERT((int)slist_itr_next(l) == 3); /* 3 */ /* reaches the last */ slist_add(l, (void *)4); /* add a new item */ ASSERT(slist_itr_has_next(l)); /* iterates the new */ ASSERT((int)slist_itr_next(l) == 4); slist_fini(l); /* * #2 */ slist_init(l); slist_set_size(l, 3); slist_add(l, (void *)1); slist_add(l, (void *)2); slist_add(l, (void *)3); slist_itr_first(l); ASSERT((int)slist_itr_next(l) == 1); /* 1 */ ASSERT((int)slist_itr_next(l) == 2); /* 2 */ ASSERT((int)slist_itr_next(l) == 3); /* 3 */ /* reaches the last */ slist_itr_remove(l); /* and remove the last*/ slist_add(l, (void *)4); /* add 4 (new last)*/ ASSERT(slist_itr_has_next(l)); /* */ ASSERT((int)slist_itr_next(l) == 4); /* 4 */ slist_fini(l); /* * #3 */ slist_init(l); slist_set_size(l, 3); slist_add(l, (void *)1); slist_add(l, (void *)2); slist_add(l, (void *)3); slist_itr_first(l); ASSERT((int)slist_itr_next(l) == 1); /* 1 */ ASSERT((int)slist_itr_next(l) == 2); /* 2 */ ASSERT((int)slist_itr_next(l) == 3); /* 3 */ /* reaches the last */ slist_add(l, (void *)4); /* add a new */ slist_itr_remove(l); ASSERT(slist_itr_has_next(l)); ASSERT((int)slist_itr_next(l) == 4); /* 4 */ slist_fini(l); /* * #4 - remove iterator's next and it is the last */ slist_init(l); slist_set_size(l, 3); slist_add(l, (void *)1); slist_add(l, (void *)2); slist_add(l, (void *)3); slist_itr_first(l); ASSERT((int)slist_itr_next(l) == 1); /* 1 */ ASSERT((int)slist_itr_next(l) == 2); /* 2 */ slist_remove(l, 2); /* remove the next */ slist_add(l, (void *)4); /* add the new next */ ASSERT(slist_itr_has_next(l)); /* iterates the new */ ASSERT((int)slist_itr_next(l) == 4); slist_fini(l); }
/** Reload the account list */ static int npppd_auth_reload_acctlist(npppd_auth_base *base) { CSVREADER_STATUS status; int linno, ncols, usersz, nuser, eof, off; const char **cols, *passwd, *callnum; char line[8192]; csvreader *csv; npppd_auth_user *user; struct in_addr ip4, ip4mask; slist users; FILE *file; struct stat st; if (base->acctlist_ready != 0 && lstat(base->acctlist_path, &st) == 0) { if (st.st_mtime == base->last_load) return 0; base->last_load = st.st_mtime; } slist_init(&users); csv = NULL; if ((file = priv_fopen(base->acctlist_path)) == NULL) { /* hash is empty if file is not found. */ if (errno == ENOENT) hash_delete_all(base->users_hash, 1); npppd_auth_base_log(base, (errno == ENOENT)? LOG_DEBUG : LOG_ERR, "Open %s failed: %m", base->acctlist_path); return 0; } if ((csv = csvreader_create()) == NULL) { npppd_auth_base_log(base, LOG_ERR, "Loading a account list failed: csvreader_create(): %m"); goto fail; } for (linno = 0, eof = 0; !eof;) { ip4.s_addr = 0; ip4mask.s_addr = 0xffffffffL; if (fgets(line, sizeof(line), file) != NULL) { int linelen; linelen = strlen(line); if (linelen <= 0) { npppd_auth_base_log(base, LOG_ERR, "Loading a account list failed: lineno=%d " "line too short", linno + 1); goto fail; } if (line[linelen - 1] != '\n' && !feof(file)) { npppd_auth_base_log(base, LOG_ERR, "Loading a account list failed: lineno=%d " "line too long", linno + 1); goto fail; } status = csvreader_parse(csv, line); } else { if (!feof(file)) { npppd_auth_base_log(base, LOG_ERR, "Loading a account list failed: %m"); goto fail; } status = csvreader_parse_flush(csv); eof = 1; } if (status != CSVREADER_NO_ERROR) { if (status == CSVREADER_OUT_OF_MEMORY) npppd_auth_base_log(base, LOG_ERR, "Loading a account list failed: %m"); else npppd_auth_base_log(base, LOG_ERR, "Loading a account list " "failed: lineno=%d parse error", linno); goto fail; } ncols = csvreader_get_number_of_column(csv); if ((cols = csvreader_get_column(csv)) == NULL) continue; linno++; /* count up here because line number is treated as CSV. */ if (linno == 1) { /* skip a title line */ continue; } if (ncols < 1) { npppd_auth_base_log(base, LOG_ERR, "account list lineno=%d has only %d fields.", linno, ncols); continue; } if (strlen(cols[0]) <= 0) continue; /* skip if the user-name is empty */ if (ncols >= 3) { if (*cols[2] != '\0' && inet_aton(cols[2], &ip4) != 1) { npppd_auth_base_log(base, LOG_ERR, "account list lineno=%d parse error: " "invalid 'Framed-IP-Address' field: %s", linno, cols[2]); continue; } } if (ncols >= 4) { if ((*cols[3] != '\0' && inet_aton(cols[3], &ip4mask) != 1) || netmask2prefixlen(htonl(ip4mask.s_addr)) < 0) { npppd_auth_base_log(base, LOG_ERR, "account list lineno=%d parse error: " "invalid 'Framed-IP-Netmask' field: %s", linno, cols[3]); continue; } } passwd = ""; if (cols[1] != NULL) passwd = cols[1]; callnum = ""; if (ncols >= 6 && cols[5] != NULL) callnum = cols[5]; usersz = sizeof(npppd_auth_user); usersz += strlen(cols[0]) + 1; usersz += strlen(passwd) + 1; usersz += strlen(callnum) + 1; if ((user = malloc(usersz)) == NULL) { npppd_auth_base_log(base, LOG_ERR, "Loading a account list failed: %m"); goto fail; } memset(user, 0, usersz); off = 0; user->username = user->space + off; off += strlcpy(user->username, cols[0], usersz - off); ++off; user->password = user->space + off; off += strlcpy(user->password, passwd, usersz - off); ++off; user->calling_number = user->space + off; strlcpy(user->calling_number, callnum, usersz - off); user->framed_ip_address = ip4; user->framed_ip_netmask = ip4mask; slist_add(&users, user); } hash_delete_all(base->users_hash, 1); nuser = 0; for (slist_itr_first(&users); slist_itr_has_next(&users);) { user = slist_itr_next(&users); if (hash_lookup(base->users_hash, user->username) != NULL) { npppd_auth_base_log(base, LOG_WARNING, "Record for user='******' is redefined, the first " "record will be used.", user->username); free(user); goto next_user; } if (hash_insert(base->users_hash, user->username, user) != 0) { npppd_auth_base_log(base, LOG_ERR, "Loading a account list failed: hash_insert(): %m"); goto fail; } nuser++; next_user: slist_itr_remove(&users); } slist_fini(&users); csvreader_destroy(csv); fclose(file); npppd_auth_base_log(base, LOG_INFO, "Loaded users from='%s' successfully. %d users", base->acctlist_path, nuser); base->acctlist_ready = 1; return 0; fail: fclose(file); if (csv != NULL) csvreader_destroy(csv); hash_delete_all(base->users_hash, 1); for (slist_itr_first(&users); slist_itr_has_next(&users);) { user = slist_itr_next(&users); free(user); } slist_fini(&users); return 1; }
/* timeout processing */ static void l2tp_ctrl_timeout(int fd, short evtype, void *ctx) { int next_timeout, need_resend; time_t curr_time; l2tp_ctrl *_this; l2tp_call *call; /* * the timer must be reset, when leave this function. * MEMO: l2tp_ctrl_stop() will reset the timer in it. * and please remember that the l2tp_ctrl_stop() may free _this. */ _this = ctx; L2TP_CTRL_ASSERT(_this != NULL); curr_time = get_monosec(); next_timeout = 2; need_resend = 0; if (l2tp_ctrl_txwin_size(_this) > 0) { if (_this->state == L2TP_CTRL_STATE_ESTABLISHED) { if (_this->hello_wait_ack != 0) { /* wait Hello reply */ if (curr_time - _this->hello_io_time >= _this->hello_timeout) { l2tp_ctrl_log(_this, LOG_NOTICE, "timeout waiting ack for hello " "packets."); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); return; } } } else if (curr_time - _this->last_snd_ctrl >= L2TP_CTRL_CTRL_PKT_TIMEOUT) { l2tp_ctrl_log(_this, LOG_NOTICE, "timeout waiting ack for ctrl packets."); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); return; } need_resend = 1; } else { for (slist_itr_first(&_this->call_list); slist_itr_has_next(&_this->call_list);) { call = slist_itr_next(&_this->call_list); if (call->state == L2TP_CALL_STATE_CLEANUP_WAIT) { l2tp_call_destroy(call, 1); slist_itr_remove(&_this->call_list); } } } switch (_this->state) { case L2TP_CTRL_STATE_IDLE: /* * idle: * XXX: never happen in current implementation */ l2tp_ctrl_log(_this, LOG_ERR, "Internal error, timeout on illegal state=idle"); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); break; case L2TP_CTRL_STATE_WAIT_CTL_CONN: /* * wait-ctrl-conn: * if there is no ack for SCCRP, the peer will * resend SCCRQ. however this implementation can * not recognize that the SCCRQ was resent or not. * Therefore, never resent from this side. */ need_resend = 0; break; case L2TP_CTRL_STATE_ESTABLISHED: if (slist_length(&_this->call_list) == 0 && curr_time - _this->last_snd_ctrl >= L2TP_CTRL_WAIT_CALL_TIMEOUT) { if (_this->ncalls == 0) /* fail to receive first call */ l2tp_ctrl_log(_this, LOG_WARNING, "timeout waiting call"); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); return; } if (_this->hello_wait_ack == 0 && _this->hello_interval > 0) { /* send Hello */ if (curr_time - _this->hello_interval >= _this->hello_io_time) { if (l2tp_ctrl_send_HELLO(_this) == 0) /* success */ _this->hello_wait_ack = 1; _this->hello_io_time = curr_time; need_resend = 0; } } break; case L2TP_CTRL_STATE_CLEANUP_WAIT: if (curr_time - _this->last_snd_ctrl >= L2TP_CTRL_CLEANUP_WAIT_TIME) { l2tp_ctrl_log(_this, LOG_NOTICE, "Cleanup timeout state=%d", _this->state); l2tp_ctrl_stop(_this, 0); return; } if (_this->active_closing != 0) l2tp_ctrl_send_disconnect_notify(_this); break; default: l2tp_ctrl_log(_this, LOG_ERR, "Internal error, timeout on illegal state=%d", _this->state); l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL); return; } /* resend if required */ if (need_resend) l2tp_ctrl_resend_una_packets(_this); l2tp_ctrl_reset_timeout(_this); }
/* add a listner to pptpd daemon context */ int pptpd_add_listener(pptpd *_this, int idx, const char *label, struct sockaddr *bindaddr) { int inaddr_any; pptpd_listener *plistener, *plstn; plistener = NULL; if (idx == 0 && slist_length(&_this->listener) > 0) { slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { slist_itr_next(&_this->listener); plstn = slist_itr_remove(&_this->listener); PPTPD_ASSERT(plstn != NULL); PPTPD_ASSERT(plstn->sock == -1); PPTPD_ASSERT(plstn->sock_gre == -1); free(plstn); } } PPTPD_ASSERT(slist_length(&_this->listener) == idx); if (slist_length(&_this->listener) != idx) { pptpd_log(_this, LOG_ERR, "Invalid argument error on %s(): idx must be %d but %d", __func__, slist_length(&_this->listener), idx); goto fail; } if ((plistener = malloc(sizeof(pptpd_listener))) == NULL) { pptpd_log(_this, LOG_ERR, "malloc() failed in %s: %m", __func__); goto fail; } memset(plistener, 0, sizeof(pptpd_listener)); PPTPD_ASSERT(sizeof(plistener->bind_sin) >= bindaddr->sa_len); memcpy(&plistener->bind_sin, bindaddr, bindaddr->sa_len); memcpy(&plistener->bind_sin_gre, bindaddr, bindaddr->sa_len); if (plistener->bind_sin.sin_port == 0) plistener->bind_sin.sin_port = htons(PPTPD_DEFAULT_TCP_PORT); /* When a raw socket binds both of an INADDR_ANY and specific IP * address sockets, packets will be received by those sockets * simultaneously. To avoid this duplicate receives, not * permit such kind of configuration */ inaddr_any = 0; slist_itr_first(&_this->listener); while (slist_itr_has_next(&_this->listener)) { plstn = slist_itr_next(&_this->listener); if (plstn->bind_sin_gre.sin_addr.s_addr == INADDR_ANY) inaddr_any++; } if (plistener->bind_sin_gre.sin_addr.s_addr == INADDR_ANY) inaddr_any++; if (inaddr_any > 0 && idx > 0) { log_printf(LOG_ERR, "configuration error at pptpd.listener_in: " "combination 0.0.0.0 and other address is not allowed."); goto fail; } plistener->bind_sin_gre.sin_port = 0; plistener->sock = -1; plistener->sock_gre = -1; plistener->self = _this; plistener->index = idx; strlcpy(plistener->phy_label, label, sizeof(plistener->phy_label)); if (slist_add(&_this->listener, plistener) == NULL) { pptpd_log(_this, LOG_ERR, "slist_add() failed in %s: %m", __func__); goto fail; } return 0; fail: if (plistener != NULL) free(plistener); return 1; }