static void test_12() { slist sl; slist *l = &sl; slist_init(l); slist_add(l, (void *)42); slist_add(l, (void *)15); slist_add(l, (void *)14); slist_add(l, (void *)13); slist_add(l, (void *)29); slist_add(l, (void *)15); slist_add(l, (void *)25); slist_add(l, (void *)55); slist_add(l, (void *)66); slist_add(l, (void *)23); slist_qsort(l, test_12_compar); ASSERT((int)slist_get(l, 0) == 13); ASSERT((int)slist_get(l, 1) == 14); ASSERT((int)slist_get(l, 2) == 15); ASSERT((int)slist_get(l, 3) == 15); ASSERT((int)slist_get(l, 4) == 23); ASSERT((int)slist_get(l, 5) == 25); ASSERT((int)slist_get(l, 6) == 29); ASSERT((int)slist_get(l, 7) == 42); ASSERT((int)slist_get(l, 8) == 55); ASSERT((int)slist_get(l, 9) == 66); }
static void test_01() { int i; slist sl; slist *l = &sl; slist_init(&sl); for (i = 0; i < 255; i++) { slist_add(&sl, (void *)i); } for (i = 0; i < 128; i++) { slist_remove_first(&sl); } for (i = 0; i < 128; i++) { slist_add(&sl, (void *)(i + 255)); } ASSERT((int)slist_get(&sl, 127) == 255); ASSERT((int)slist_get(&sl, 254) == 129 + 253); ASSERT((int)slist_length(&sl) == 255); /* dump(&sl); */ /* printf("==\n"); */ slist_add(&sl, (void *)(128 + 255)); ASSERT((int)slist_get(&sl, 127) == 255); /* ASSERT((int)slist_get(&sl, 255) == 128 + 255); */ ASSERT((int)slist_length(&sl) == 256); /* dump(&sl); */ }
/* Test code for removing of the first, last and middle item. */ static void test_01a() { int i, f; slist sl; slist *l = &sl; slist_init(&sl); slist_add(&sl, (void *)1); ASSERT(sl.list_size == 256); #define SETUP() \ { \ l->last_idx = 64; \ l->first_idx = 192; \ for (i = 0; i < slist_length(l); i++) { \ slist_set(l, i, (void *)i); \ } \ } /* Remove the first item. */ SETUP(); f = 0; while (slist_length(l) > 0) { slist_remove(l, 0); f++; for (i = 0; i < slist_length(l); i++) { ASSERT((int)slist_get(l, i) == i + f); } } /* Remove the last item. */ SETUP(); while (slist_length(l) > 0) { slist_remove(l, slist_length(l) - 1); for (i = 0; i < slist_length(l); i++) { ASSERT((int)slist_get(l, i) == i); } } /* Remove the second item from the end. */ SETUP(); while (slist_length(l) > 1) { slist_remove(l, slist_length(l) - 2); for (i = 0; i < slist_length(l) - 1; i++) { ASSERT((int)slist_get(l, i) == i); } if (slist_length(l) > 0) { ASSERT((int)slist_get(l, slist_length(l) - 1) == 127); } } slist_remove(l, slist_length(l) - 1); ASSERT(slist_length(l) == 0); }
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 dump(slist *l) { int i; fprintf(stderr, "\tl->itr_curr = %d\n" "\tl->itr_next = %d\n" "\tl->first_idx = %d\n" "\tl->last_idx = %d\n" "\tl->list_size = %d\n" , l->itr_curr, l->itr_next, l->first_idx, l->last_idx , l->list_size); for (i = 0; i < slist_length(l); i++) { if ((i % 16) == 0) fprintf(stderr, "%08x ", i); fprintf(stderr, " %3d", (int)slist_get(l, i)); if ((i % 16) == 7) fprintf(stderr, " -"); if ((i % 16) == 15) fprintf(stderr, "\n"); } if ((i % 16) != 0) fprintf(stderr, "\n"); }
/* disconnect all calls on the control context * @return return # of calls that is not waiting cleanup. */ static int l2tp_ctrl_disconnect_all_calls(l2tp_ctrl *_this, int drop) { int i, len, ncalls; l2tp_call *call; L2TP_CTRL_ASSERT(_this != NULL); ncalls = 0; len = slist_length(&_this->call_list); for (i = 0; i < len; i++) { call = slist_get(&_this->call_list, i); if (call->state != L2TP_CALL_STATE_CLEANUP_WAIT) { ncalls++; if (l2tp_ctrl_txwin_is_full(_this)) { L2TP_CTRL_DBG((_this, LOG_INFO, "Too many calls. Sending window is not " "enough to send CDN to all clients.")); if (drop) l2tp_call_drop(call); } else l2tp_call_admin_disconnect(call); } } return ncalls; }
void* slist_find(const struct simple_list* slist, const void* key, slist_cmp cmp) { for ( unsigned int i = 0; i < slist->size; i++ ) { if ( cmp(slist->key[i], key) == 0 ) { return slist_get(slist, i); } } return 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); }
static void *slist_new(t_symbol *s) { t_slist *x = (t_slist *)pd_new(slist_class); x->x_sym = s; x->x_c = slist_get(s); outlet_new(&x->x_obj, &s_float); x->x_symout=outlet_new(&x->x_obj, &s_symbol); x->x_lenout=outlet_new(&x->x_obj, &s_float); return (x); }
static struct ConfigItem * find_item(uint32_t hash) { SLIST_ITERATOR p = slist_head(configs, NULL); while(p != NULL) { struct ConfigItem *item = *(struct ConfigItem **)slist_get(p); if (item->hash == hash) return item; p = slist_next(p); } return NULL; }
void* slist_put(struct simple_list* slist, void* key) { if ( slist->size == slist->capacity ) { slist_alloc(slist, /* growth = */ slist->capacity); } unsigned int index = slist->size; slist->key[index] = key; slist->size++; void* ptr = slist_get(slist, index); #ifndef NVALGRIND VALGRIND_MEMPOOL_ALLOC(slist->value, ptr, slist->element_size); #endif return ptr; }
void configs_cleanup(void) { if (!configs) return; SLIST_ITERATOR p = slist_head(configs, NULL); while(p != NULL) { struct ConfigItem *item = *(struct ConfigItem **)slist_get(p); free(item); p = slist_next(p); } slist_free(configs); }
static void test_02() { int i; slist sl; slist *l = &sl; slist_init(&sl); /* Place 300 items for left side and 211 items for right side. */ for (i = 0; i < 511; i++) slist_add(&sl, (void *)i); for (i = 0; i <= 300; i++) slist_remove_first(&sl); for (i = 0; i <= 300; i++) slist_add(&sl, (void *)i); /* Set values to make index number and value the same. */ for (i = 0; i < slist_length(&sl); i++) slist_set(&sl, i, (void *)(i + 1)); ASSERT(slist_length(&sl) == 511); /* The logical length is 511. */ ASSERT((int)sl.list[511] == 211); /* The most right is 211th. */ ASSERT((int)sl.list[0] == 212); /* The most left is 212th. */ ASSERT(sl.list_size == 512); /* The physical size is 512. */ slist_add(&sl, (void *)512); /* Add 512th item. */ ASSERT(sl.list_size == 768); /* The physical size is extended. */ ASSERT(slist_length(&sl) == 512); /* The logical length is 512. */ ASSERT((int)sl.list[511] == 211); /* boundary */ ASSERT((int)sl.list[512] == 212); /* boundary */ ASSERT((int)sl.list[767] == 467); /* The most right is 467th. */ ASSERT((int)sl.list[0] == 468); /* The most left is 468th. */ /* Check all items */ for (i = 0; i < slist_length(&sl); i++) ASSERT((int)slist_get(&sl, i) == i + 1); /* check */ }
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_ctrl_finished_notify(pptpd *_this, pptp_ctrl *ctrl) { pptp_ctrl *ctrl1; int i, nctrl; PPTPD_ASSERT(_this != NULL); PPTPD_ASSERT(ctrl != NULL); nctrl = 0; for (i = 0; i < slist_length(&_this->ctrl_list); i++) { ctrl1 = slist_get(&_this->ctrl_list, i); if (ctrl1 == ctrl) { slist_remove(&_this->ctrl_list, i); break; } } pptp_ctrl_destroy(ctrl); PPTPD_DBG((_this, LOG_DEBUG, "Remains %d ctrls", nctrl)); if (pptpd_is_shutting_down(_this) && nctrl == 0) pptpd_stop_immediatly(_this); }
/* * in - Source file to be interpreted * file_name - Name of the source file, for debugging purposes * sym_table - Global (master) symbol table */ void liten(FILE * in, char * file_name, slist * sym_table, token ** ret) { // *ret = NULL; slist * block_stack = slist_init(); slist * local_table = slist_init(); slist_push(sym_table, local_table); file_desc * desc = malloc(sizeof(file_desc)); desc->file = in; desc->name = file_name; desc->line = 1; int tok; char * temp = malloc(sizeof(char)*MAX_STR); strcpy(temp, "\0"); int type = -1; slist * tok_queue = slist_init(); while (1) { if (in == stdin) { printf(":> "); } else if (tok == EOF) { break; } tok = getc(in); while (1) { if (tok == '\n' || tok == EOF) { desc->line++; tokenize(desc, &temp, &type, tok_queue); type = -1; // slist_print(tok_queue, slist_print_token); // TODO: Check line for syntax errors if (tok_queue->len == 0) break; if (block_stack->len == 0) { rpn(desc, tok_queue, sym_table, block_stack, ret); } else { char * temp_str = ((token *) slist_get(tok_queue, 0)->obj)->obj; block * temp = (block *) slist_get(block_stack, -1)->obj; if (strcmp("end", temp_str) == 0) { rpn(desc, tok_queue, sym_table, block_stack, ret); } else if (strcmp("if", temp_str) == 0 || strcmp("while", temp_str) == 0) { if (temp->value == 1) rpn(desc, tok_queue, sym_table, block_stack, ret); else { block * temp1 = malloc(sizeof(block)); temp1->value = 0; if (strcmp("if", temp_str) == 0) { temp1->type = IF_B; } else if (strcmp("while", temp_str) == 0) { temp1->type = WHILE_B; } slist_push(block_stack, temp1); } } else if (strcmp("elif", temp_str) == 0) { if (temp->type != IF_B) lite_error(desc, "'elif' exists in 'if' block"); if (temp->value == 1) temp->value = 0; else rpn(desc, tok_queue, sym_table, block_stack, ret); } else if (strcmp("else", temp_str) == 0) { if (temp->type != IF_B) lite_error(desc, "'else' exists in 'if' block"); if (temp->value == 1) temp->value = 0; else temp->value = 1; } else { if (temp->value == 1) rpn(desc, tok_queue, sym_table, block_stack, ret); } } tok_queue = slist_init(); } else { token_parse(desc, tok, &temp, &type, tok_queue); } if (in == stdin && tok == '\n') break; tok = getc(in); } } return; }
/* call it when control packet is received */ int l2tp_call_recv_packet(l2tp_ctrl *ctrl, l2tp_call *_this, int mestype, u_char *pkt, int pktlen) { int i, len, session_id, send_cdn; l2tp_call *call; dialin_proxy_info dpi; /* when ICRQ, this will be NULL */ L2TP_CALL_ASSERT(_this != NULL || mestype == L2TP_AVP_MESSAGE_TYPE_ICRQ); if (_this == NULL) { if (mestype != L2TP_AVP_MESSAGE_TYPE_ICRQ) return 1; if ((_this = l2tp_call_create()) == NULL) { l2tp_ctrl_log(ctrl, LOG_ERR, "l2tp_call_create failed in %s(): %m", __func__); return 1; } l2tp_call_init(_this, ctrl); if (l2tp_call_recv_ICRQ(_this, pkt, pktlen) != 0) return 1; len = slist_length(&ctrl->call_list); session_id = _this->id; again: /* assign a session ID */ session_id &= 0xffff; if (session_id == 0) session_id = 1; for (i = 0; i < len; i++) { call = slist_get(&ctrl->call_list, i); if (call->session_id == session_id) { session_id++; goto again; } } _this->session_id = session_id; /* add the l2tp_call to call list */ slist_add(&_this->ctrl->call_list, _this); if (l2tp_call_send_ICRP(_this) != 0) return 1; _this->state = L2TP_CALL_STATE_WAIT_CONN; return 0; } /* state machine */ send_cdn = 0; switch (_this->state) { default: break; case L2TP_CALL_STATE_WAIT_CONN: switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_ICCN: memset(&dpi, 0, sizeof(dpi)); if (l2tp_call_recv_ICCN(_this, pkt, pktlen, &dpi) != 0) return 1; l2tp_call_bind_ppp(_this, &dpi); l2tp_call_send_ZLB(_this); _this->state = L2TP_CALL_STATE_ESTABLISHED; _this->ctrl->ncalls++; return 0; case L2TP_AVP_MESSAGE_TYPE_ICRQ: case L2TP_AVP_MESSAGE_TYPE_ICRP: send_cdn = 1; /* FALLTHROUGH */ default: l2tp_call_log(_this, LOG_ERR, "Waiting ICCN. But received %s", avp_mes_type_string(mestype)); if (send_cdn) { l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_GENERIC_ERROR, "Illegal state.", NULL, 0); return 0; } } break; case L2TP_CALL_STATE_ESTABLISHED: switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_CDN: /* disconnect from peer. log it */ l2tp_recv_CDN(_this, pkt, pktlen); _this->state = L2TP_CALL_STATE_CLEANUP_WAIT; l2tp_call_notify_down(_this); l2tp_call_send_ZLB(_this); return 0; case L2TP_AVP_MESSAGE_TYPE_ICRQ: case L2TP_AVP_MESSAGE_TYPE_ICRP: case L2TP_AVP_MESSAGE_TYPE_ICCN: send_cdn = 1; break; default: break; } l2tp_call_log(_this, LOG_ERR, "Call established. But received %s", avp_mes_type_string(mestype)); if (send_cdn) { l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_GENERIC_ERROR, "Illegal state.", NULL, 0); return 0; } l2tp_call_disconnect(_this, 0, 0, NULL, NULL, 0); return 1; } l2tp_call_log(_this, LOG_INFO, "Received %s in unexpected state=%s", avp_mes_type_string(mestype), l2tp_call_state_string(_this)); l2tp_call_disconnect(_this, 0, 0, NULL, NULL, 0); return 1; }
static void slist_setlist(t_slist *x,t_symbol *s) { slist_release(x->x_c); x->x_c = slist_get(s); }
/* Verify removing the last item on the physical location */ static void test_05() { int i; slist sl; slist *l = &sl; slist_init(&sl); /* Fill */ for (i = 0; i < 255; i++) { slist_add(&sl, (void *)i); } /* Remove 254 items */ for (i = 0; i < 254; i++) { slist_remove_first(&sl); } slist_set(l, 0, (void *)0); /* Add 7 items */ for (i = 0; i < 8; i++) { slist_add(&sl, (void *)i + 1); } ASSERT(sl.first_idx == 254); ASSERT(sl.last_idx == 7); slist_remove(l, 0); ASSERT((int)slist_get(l, 0) == 1); ASSERT((int)slist_get(l, 1) == 2); ASSERT((int)slist_get(l, 2) == 3); ASSERT((int)slist_get(l, 3) == 4); ASSERT((int)slist_get(l, 4) == 5); ASSERT((int)slist_get(l, 5) == 6); ASSERT((int)slist_get(l, 6) == 7); ASSERT((int)slist_get(l, 7) == 8); ASSERT(l->first_idx == 255); slist_remove(l, 0); 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); ASSERT((int)slist_get(l, 4) == 6); ASSERT((int)slist_get(l, 5) == 7); ASSERT((int)slist_get(l, 6) == 8); ASSERT(l->first_idx == 0); }
/* Receive packet */ void l2tp_ctrl_input(l2tpd *_this, int listener_index, struct sockaddr *peer, struct sockaddr *sock, void *nat_t_ctx, u_char *pkt, int pktlen) { int i, len, offsiz, reqlen, is_ctrl; uint16_t mestype; struct l2tp_avp *avp, *avp0; l2tp_ctrl *ctrl; l2tp_call *call; char buf[L2TP_AVP_MAXSIZ], errmsg[256]; time_t curr_time; u_char *pkt0; struct l2tp_header hdr; char hbuf[NI_MAXHOST + NI_MAXSERV + 16]; ctrl = NULL; curr_time = get_monosec(); pkt0 = pkt; L2TP_CTRL_ASSERT(peer->sa_family == sock->sa_family); L2TP_CTRL_ASSERT(peer->sa_family == AF_INET || peer->sa_family == AF_INET6) /* * Parse L2TP Header */ memset(&hdr, 0, sizeof(hdr)); if (pktlen < 2) { snprintf(errmsg, sizeof(errmsg), "a short packet. " "length=%d", pktlen); goto bad_packet; } memcpy(&hdr, pkt, 2); pkt += 2; if (hdr.ver != L2TP_HEADER_VERSION_RFC2661) { /* XXX: only RFC2661 is supported */ snprintf(errmsg, sizeof(errmsg), "Unsupported version at header = %d", hdr.ver); goto bad_packet; } is_ctrl = (hdr.t != 0)? 1 : 0; /* calc required length */ reqlen = 6; /* for Flags, Tunnel-Id, Session-Id field */ if (hdr.l) reqlen += 2; /* for Length field (opt) */ if (hdr.s) reqlen += 4; /* for Ns, Nr field (opt) */ if (hdr.o) reqlen += 2; /* for Offset Size field (opt) */ if (reqlen > pktlen) { snprintf(errmsg, sizeof(errmsg), "a short packet. length=%d", pktlen); goto bad_packet; } if (hdr.l != 0) { GETSHORT(hdr.length, pkt); if (hdr.length > pktlen) { snprintf(errmsg, sizeof(errmsg), "Actual packet size is smaller than the length " "field %d < %d", pktlen, hdr.length); goto bad_packet; } pktlen = hdr.length; /* remove trailing trash */ } GETSHORT(hdr.tunnel_id, pkt); GETSHORT(hdr.session_id, pkt); if (hdr.s != 0) { GETSHORT(hdr.ns, pkt); GETSHORT(hdr.nr, pkt); } if (hdr.o != 0) { GETSHORT(offsiz, pkt); if (pktlen < offsiz) { snprintf(errmsg, sizeof(errmsg), "offset field is bigger than remaining packet " "length %d > %d", offsiz, pktlen); goto bad_packet; } pkt += offsiz; } L2TP_CTRL_ASSERT(pkt - pkt0 == reqlen); pktlen -= (pkt - pkt0); /* cut down the length of header */ ctrl = NULL; memset(buf, 0, sizeof(buf)); mestype = 0; avp = NULL; if (is_ctrl) { avp0 = (struct l2tp_avp *)buf; avp = avp_find_message_type_avp(avp0, pkt, pktlen); if (avp != NULL) mestype = avp->attr_value[0] << 8 | avp->attr_value[1]; } ctrl = l2tpd_get_ctrl(_this, hdr.tunnel_id); if (ctrl == NULL) { /* new control */ if (!is_ctrl) { snprintf(errmsg, sizeof(errmsg), "bad data message: tunnelId=%d is not " "found.", hdr.tunnel_id); goto bad_packet; } if (mestype != L2TP_AVP_MESSAGE_TYPE_SCCRQ) { snprintf(errmsg, sizeof(errmsg), "bad control message: tunnelId=%d is not " "found. mestype=%s", hdr.tunnel_id, avp_mes_type_string(mestype)); goto bad_packet; } if ((ctrl = l2tp_ctrl_create()) == NULL) { l2tp_ctrl_log(ctrl, LOG_ERR, "l2tp_ctrl_create() failed: %m"); goto fail; } if (l2tp_ctrl_init(ctrl, _this, peer, sock, nat_t_ctx) != 0) { l2tp_ctrl_log(ctrl, LOG_ERR, "l2tp_ctrl_start() failed: %m"); goto fail; } ctrl->listener_index = listener_index; l2tp_ctrl_reload(ctrl); } else { /* * treat as an error if src address and port is not * match. (because it is potentially DoS attach) */ int notmatch = 0; if (ctrl->peer.ss_family != peer->sa_family) notmatch = 1; else if (peer->sa_family == AF_INET) { if (SIN(peer)->sin_addr.s_addr != SIN(&ctrl->peer)->sin_addr.s_addr || SIN(peer)->sin_port != SIN(&ctrl->peer)->sin_port) notmatch = 1; } else if (peer->sa_family == AF_INET6) { if (!IN6_ARE_ADDR_EQUAL(&(SIN6(peer)->sin6_addr), &(SIN6(&ctrl->peer)->sin6_addr)) || SIN6(peer)->sin6_port != SIN6(&ctrl->peer)->sin6_port) notmatch = 1; } if (notmatch) { snprintf(errmsg, sizeof(errmsg), "tunnelId=%u is already assigned for %s", hdr.tunnel_id, addrport_tostring( (struct sockaddr *)&ctrl->peer, ctrl->peer.ss_len, hbuf, sizeof(hbuf))); goto bad_packet; } } ctrl->last_rcv = curr_time; call = NULL; if (hdr.session_id != 0) { /* search l2tp_call by Session ID */ /* linear search is enough for this purpose */ len = slist_length(&ctrl->call_list); for (i = 0; i < len; i++) { call = slist_get(&ctrl->call_list, i); if (call->session_id == hdr.session_id) break; call = NULL; } } if (!is_ctrl) { int delayed = 0; /* L2TP data */ if (ctrl->state != L2TP_CTRL_STATE_ESTABLISHED) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received Data packet in '%s'", l2tp_ctrl_state_string(ctrl)); goto fail; } if (call == NULL) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received a data packet but it has no call. " "session_id=%u", hdr.session_id); goto fail; } L2TP_CTRL_DBG((ctrl, DEBUG_LEVEL_2, "call=%u RECV ns=%u nr=%u snd_nxt=%u rcv_nxt=%u len=%d", call->id, hdr.ns, hdr.nr, call->snd_nxt, call->rcv_nxt, pktlen)); if (call->state != L2TP_CALL_STATE_ESTABLISHED){ l2tp_ctrl_log(ctrl, LOG_WARNING, "Received a data packet but call is not " "established"); goto fail; } if (hdr.s != 0) { if (SEQ_LT(hdr.ns, call->rcv_nxt)) { if (SEQ_LT(hdr.ns, call->rcv_nxt - L2TP_CALL_DELAY_LIMIT)) { /* sequence number seems to be delayed */ /* XXX: need to log? */ L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "receive a out of sequence " "data packet: %u < %u.", hdr.ns, call->rcv_nxt)); return; } delayed = 1; } else { call->rcv_nxt = hdr.ns + 1; } } l2tp_call_ppp_input(call, pkt, pktlen, delayed); return; } if (hdr.s != 0) { L2TP_CTRL_DBG((ctrl, DEBUG_LEVEL_2, "RECV %s ns=%u nr=%u snd_nxt=%u snd_una=%u rcv_nxt=%u " "len=%d", (is_ctrl)? "C" : "", hdr.ns, hdr.nr, ctrl->snd_nxt, ctrl->snd_una, ctrl->rcv_nxt, pktlen)); if (pktlen <= 0) l2tp_ctrl_log(ctrl, LOG_INFO, "RecvZLB"); if (SEQ_GT(hdr.nr, ctrl->snd_una)) { if (hdr.nr == ctrl->snd_nxt || SEQ_LT(hdr.nr, ctrl->snd_nxt)) ctrl->snd_una = hdr.nr; else { l2tp_ctrl_log(ctrl, LOG_INFO, "Received message has bad Nr field: " "%u < %u.", hdr.ns, ctrl->snd_nxt); /* XXX Drop with ZLB? */ goto fail; } } if (l2tp_ctrl_txwin_size(ctrl) <= 0) { /* no waiting ack */ if (ctrl->hello_wait_ack != 0) { /* * Reset Hello state, as an ack for the Hello * is recived. */ ctrl->hello_wait_ack = 0; ctrl->hello_io_time = curr_time; } switch (ctrl->state) { case L2TP_CTRL_STATE_CLEANUP_WAIT: l2tp_ctrl_stop(ctrl, 0); return; } } if (hdr.ns != ctrl->rcv_nxt) { /* there are remaining packet */ if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) { /* resend or sent ZLB */ l2tp_ctrl_send_ZLB(ctrl); } #ifdef L2TP_CTRL_DEBUG if (pktlen != 0) { /* not ZLB */ L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "receive out of sequence %u must be %u. " "mestype=%s", hdr.ns, ctrl->rcv_nxt, avp_mes_type_string(mestype))); } #endif return; } if (pktlen <= 0) return; /* ZLB */ if (l2tp_ctrl_txwin_is_full(ctrl)) { L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "Received message cannot be handled. " "Transmission window is full.")); l2tp_ctrl_send_ZLB(ctrl); return; } ctrl->rcv_nxt++; if (avp == NULL) { l2tpd_log(_this, LOG_WARNING, "bad control message: no message-type AVP."); goto fail; } } /* * state machine (RFC2661 pp. 56-57) */ switch (ctrl->state) { case L2TP_CTRL_STATE_IDLE: switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCRQ: if (l2tp_ctrl_recv_SCCRQ(ctrl, pkt, pktlen, _this, peer) == 0) { /* acceptable */ l2tp_ctrl_send_SCCRP(ctrl); ctrl->state = L2TP_CTRL_STATE_WAIT_CTL_CONN; return; } /* * in case un-acceptable, it was already processed * at l2tcp_ctrl_recv_SCCRQ */ return; case L2TP_AVP_MESSAGE_TYPE_SCCRP: /* * RFC specifies that sent of StopCCN in the state, * However as this implementation only support Passive * open, this packet will not received. */ /* FALLTHROUGH */ case L2TP_AVP_MESSAGE_TYPE_SCCCN: default: break; } goto fsm_fail; case L2TP_CTRL_STATE_WAIT_CTL_CONN: /* Wait-Ctl-Conn */ switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCCN: l2tp_ctrl_log(ctrl, LOG_INFO, "RecvSCCN"); if (l2tp_ctrl_send_ZLB(ctrl) == 0) { ctrl->state = L2TP_CTRL_STATE_ESTABLISHED; } return; case L2TP_AVP_MESSAGE_TYPE_StopCCN: goto receive_stop_ccn; case L2TP_AVP_MESSAGE_TYPE_SCCRQ: case L2TP_AVP_MESSAGE_TYPE_SCCRP: default: break; } break; /* fsm_fail */ case L2TP_CTRL_STATE_ESTABLISHED: /* Established */ switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCCN: case L2TP_AVP_MESSAGE_TYPE_SCCRQ: case L2TP_AVP_MESSAGE_TYPE_SCCRP: break; receive_stop_ccn: case L2TP_AVP_MESSAGE_TYPE_StopCCN: if (l2tp_ctrl_recv_StopCCN(ctrl, pkt, pktlen) == 0) { if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) l2tp_ctrl_send_ZLB(ctrl); l2tp_ctrl_stop(ctrl, 0); return; } l2tp_ctrl_log(ctrl, LOG_ERR, "Received bad StopCCN"); l2tp_ctrl_send_ZLB(ctrl); l2tp_ctrl_stop(ctrl, 0); return; case L2TP_AVP_MESSAGE_TYPE_HELLO: if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) l2tp_ctrl_send_ZLB(ctrl); return; case L2TP_AVP_MESSAGE_TYPE_CDN: case L2TP_AVP_MESSAGE_TYPE_ICRP: case L2TP_AVP_MESSAGE_TYPE_ICCN: if (call == NULL) { l2tp_ctrl_log(ctrl, LOG_INFO, "Unknown call message: %s", avp_mes_type_string(mestype)); goto fail; } /* FALLTHROUGH */ case L2TP_AVP_MESSAGE_TYPE_ICRQ: l2tp_call_recv_packet(ctrl, call, mestype, pkt, pktlen); return; default: break; } break; /* fsm_fail */ case L2TP_CTRL_STATE_CLEANUP_WAIT: if (mestype == L2TP_AVP_MESSAGE_TYPE_StopCCN) { /* * We left ESTABLISHED state, but the peer sent StopCCN. */ goto receive_stop_ccn; } break; /* fsm_fail */ } fsm_fail: /* state machine error */ l2tp_ctrl_log(ctrl, LOG_WARNING, "Received %s in '%s' state", avp_mes_type_string(mestype), l2tp_ctrl_state_string(ctrl)); l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_FSM_ERROR); return; fail: if (ctrl != NULL && mestype != 0) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received %s in '%s' state", avp_mes_type_string(mestype), l2tp_ctrl_state_string(ctrl)); l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_GENERAL_ERROR); } return; bad_packet: l2tpd_log(_this, LOG_INFO, "Received from=%s: %s", addrport_tostring(peer, peer->sa_len, hbuf, sizeof(hbuf)), errmsg); return; }