X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/0b06de8105dd567cb2d120770b2101afacce5f33..7fd68b1daeab9a2a1a3ee8f0652c25fc37bf3549:/l2tpns.c diff --git a/l2tpns.c b/l2tpns.c index 31a183a..ed85a91 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,8 +4,6 @@ // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced // vim: sw=8 ts=8 -char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.176 2011/01/20 12:48:40 bodea Exp $"; - #include #include #include @@ -104,6 +102,7 @@ uint32_t eth_tx = 0; static uint32_t ip_pool_size = 1; // Size of the pool of addresses used for dynamic address allocation. time_t time_now = 0; // Current time in seconds since epoch. +uint64_t time_now_ms = 0; // Current time in milliseconds since epoch. static char time_now_string[64] = {0}; // Current time as a string. static int time_changed = 0; // time_now changed char main_quit = 0; // True if we're in the process of exiting. @@ -163,6 +162,8 @@ config_descriptt config_values[] = { CONFIG("hostname", hostname, STRING), CONFIG("nexthop_address", nexthop_address, IPv4), CONFIG("nexthop6_address", nexthop6_address, IPv6), + CONFIG("echo_timeout", echo_timeout, INT), + CONFIG("idle_echo_timeout", idle_echo_timeout, INT), { NULL, 0, 0, 0 }, }; @@ -242,6 +243,10 @@ static clockt now(double *f) time_now = t.tv_sec; time_changed++; } + + // Time in milliseconds + time_now_ms = (t.tv_sec * 1000) + (t.tv_usec/1000); + return (t.tv_sec - basetime) * 10 + t.tv_usec / 100000 + 1; } @@ -469,7 +474,7 @@ static void routeset(sessionidt s, in_addr_t ip, int prefixlen, in_addr_t gw, in netlink_addattr(&req.nh, RTA_GATEWAY, &n_ip, sizeof(n_ip)); } - LOG(1, s, 0, "Route %s %s/%d%s%s\n", add ? "add" : "del", + LOG(1, s, session[s].tunnel, "Route %s %s/%d%s%s\n", add ? "add" : "del", fmtaddr(htonl(ip), 0), prefixlen, gw ? " via" : "", gw ? fmtaddr(htonl(gw), 2) : ""); @@ -544,7 +549,7 @@ void route6set(sessionidt s, struct in6_addr ip, int prefixlen, int add) metric = 1; netlink_addattr(&req.nh, RTA_METRICS, &metric, sizeof(metric)); - LOG(1, s, 0, "Route %s %s/%d\n", + LOG(1, s, session[s].tunnel, "Route %s %s/%d\n", add ? "add" : "del", inet_ntop(AF_INET6, &ip, ipv6addr, INET6_ADDRSTRLEN), prefixlen); @@ -1325,7 +1330,8 @@ static void update_session_out_stat(sessionidt s, sessiont *sp, int len) // process outgoing (to tunnel) IP // -static void processipout(uint8_t *buf, int len) +// (i.e. this routine writes to data[-8]). +void processipout(uint8_t *buf, int len) { sessionidt s; sessiont *sp; @@ -1462,75 +1468,123 @@ static void processipout(uint8_t *buf, int len) return; } - // Add on L2TP header - { - bundleidt bid = 0; - if(session[s].bundle != 0 && bundle[session[s].bundle].num_of_links > 1) - { - bid = session[s].bundle; - s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links]; - t = session[s].tunnel; - sp = &session[s]; - LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s); - if(len > MINFRAGLEN) - { - // Partition the packet to "bundle[b].num_of_links" fragments - bundlet *b = &bundle[bid]; - uint32_t num_of_links = b->num_of_links; - uint32_t fraglen = len / num_of_links; - fraglen = (fraglen > session[s].mru ? session[s].mru : fraglen); - uint32_t last_fraglen = fraglen + len % num_of_links; - last_fraglen = (last_fraglen > session[s].mru ? len % num_of_links : last_fraglen); + if(session[s].bundle != 0 && bundle[session[s].bundle].num_of_links > 1) + { + + if (!config->cluster_iam_master) + { + // The MPPP packets must be managed by the Master. + master_forward_mppp_packet(s, data, size); + return; + } + + // Add on L2TP header + sessionidt members[MAXBUNDLESES]; + bundleidt bid = session[s].bundle; + bundlet *b = &bundle[bid]; + uint32_t num_of_links, nb_opened; + int i; + + num_of_links = b->num_of_links; + nb_opened = 0; + for (i = 0;i < num_of_links;i++) + { + s = b->members[i]; + if (session[s].ppp.lcp == Opened) + { + members[nb_opened] = s; + nb_opened++; + } + } + + if (nb_opened < 1) + { + LOG(3, s, t, "MPPP: PROCESSIPOUT ERROR, no session opened in bundle:%d\n", bid); + return; + } + + num_of_links = nb_opened; + b->current_ses = (b->current_ses + 1) % num_of_links; + s = members[b->current_ses]; + t = session[s].tunnel; + sp = &session[s]; + LOG(4, s, t, "MPPP: (1)Session number becomes: %d\n", s); + + if (num_of_links > 1) + { + if(len > MINFRAGLEN) + { + //for rotate traffic among the member links + uint32_t divisor = num_of_links; + if (divisor > 2) + divisor = divisor/2 + (divisor & 1); + + // Partition the packet to "num_of_links" fragments + uint32_t fraglen = len / divisor; + uint32_t last_fraglen = fraglen + len % divisor; uint32_t remain = len; // send the first packet - uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, fraglen, s, t, PPPIP, 0, bid, MP_BEGIN); - if (!p) return; - tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... + uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, fraglen, s, t, PPPIP, 0, bid, MP_BEGIN); + if (!p) return; + tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... + // statistics update_session_out_stat(s, sp, fraglen); + remain -= fraglen; while (remain > last_fraglen) - { - s = b->members[b->current_ses = ++b->current_ses % num_of_links]; + { + b->current_ses = (b->current_ses + 1) % num_of_links; + s = members[b->current_ses]; t = session[s].tunnel; sp = &session[s]; - LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); - p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), fraglen, s, t, PPPIP, 0, bid, 0); - if (!p) return; - tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... + LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); + p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), fraglen, s, t, PPPIP, 0, bid, 0); + if (!p) return; + tunnelsend(fragbuf, fraglen + (p-fragbuf), t); // send it... update_session_out_stat(s, sp, fraglen); remain -= fraglen; } // send the last fragment - s = b->members[b->current_ses = ++b->current_ses % num_of_links]; + b->current_ses = (b->current_ses + 1) % num_of_links; + s = members[b->current_ses]; t = session[s].tunnel; sp = &session[s]; - LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); - p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), remain, s, t, PPPIP, 0, bid, MP_END); - if (!p) return; - tunnelsend(fragbuf, remain + (p-fragbuf), t); // send it... + LOG(4, s, t, "MPPP: (2)Session number becomes: %d\n", s); + p = makeppp(fragbuf, sizeof(fragbuf), buf+(len - remain), remain, s, t, PPPIP, 0, bid, MP_END); + if (!p) return; + tunnelsend(fragbuf, remain + (p-fragbuf), t); // send it... update_session_out_stat(s, sp, remain); if (remain != last_fraglen) LOG(3, s, t, "PROCESSIPOUT ERROR REMAIN != LAST_FRAGLEN, %d != %d\n", remain, last_fraglen); - } - else { - // Send it as one frame - uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, bid, MP_BOTH_BITS); - if (!p) return; - tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... + } + else + { + // Send it as one frame + uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, bid, MP_BOTH_BITS); + if (!p) return; + tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... LOG(4, s, t, "MPPP: packet sent as one frame\n"); update_session_out_stat(s, sp, len); - } - } - else - { - uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, 0, 0); - if (!p) return; - tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... + } + } + else + { + // Send it as one frame (NO MPPP Frame) + uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, 0, 0); + if (!p) return; + tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... update_session_out_stat(s, sp, len); - } - } + } + } + else + { + uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, 0, 0); + if (!p) return; + tunnelsend(fragbuf, len + (p-fragbuf), t); // send it... + update_session_out_stat(s, sp, len); + } // Snooping this session, send it to intercept box if (sp->snoop_ip && sp->snoop_port) @@ -1610,7 +1664,10 @@ static void processipv6out(uint8_t * buf, int len) if (session[s].bundle && bundle[session[s].bundle].num_of_links > 1) { bundleidt bid = session[s].bundle; - s = bundle[bid].members[bundle[bid].current_ses = ++bundle[bid].current_ses % bundle[bid].num_of_links]; + bundlet *b = &bundle[bid]; + + b->current_ses = (b->current_ses + 1) % b->num_of_links; + s = b->members[b->current_ses]; LOG(3, s, session[s].tunnel, "MPPP: Session number becomes: %u\n", s); } t = session[s].tunnel; @@ -1665,7 +1722,6 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) { sessiont *sp; tunnelidt t; - in_addr_t ip; uint8_t b[MAXETHER + 20]; @@ -1679,8 +1735,6 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) buf += 4; len -= 4; - ip = *(in_addr_t *)(buf + 16); - if (!session[s].ip) return; @@ -1713,10 +1767,10 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len) static void control16(controlt * c, uint16_t avp, uint16_t val, uint8_t m) { uint16_t l = (m ? 0x8008 : 0x0008); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - *(uint16_t *) (c->buf + c->length + 6) = htons(val); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + c->buf16[c->length/2 + 3] = htons(val); c->length += 8; } @@ -1724,10 +1778,10 @@ static void control16(controlt * c, uint16_t avp, uint16_t val, uint8_t m) static void control32(controlt * c, uint16_t avp, uint32_t val, uint8_t m) { uint16_t l = (m ? 0x800A : 0x000A); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - *(uint32_t *) (c->buf + c->length + 6) = htonl(val); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + *(uint32_t *) &c->buf[c->length + 6] = htonl(val); c->length += 10; } @@ -1735,10 +1789,10 @@ static void control32(controlt * c, uint16_t avp, uint32_t val, uint8_t m) static void controls(controlt * c, uint16_t avp, char *val, uint8_t m) { uint16_t l = ((m ? 0x8000 : 0) + strlen(val) + 6); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - memcpy(c->buf + c->length + 6, val, strlen(val)); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + memcpy(&c->buf[c->length + 6], val, strlen(val)); c->length += 6 + strlen(val); } @@ -1746,10 +1800,10 @@ static void controls(controlt * c, uint16_t avp, char *val, uint8_t m) static void controlb(controlt * c, uint16_t avp, uint8_t *val, unsigned int len, uint8_t m) { uint16_t l = ((m ? 0x8000 : 0) + len + 6); - *(uint16_t *) (c->buf + c->length + 0) = htons(l); - *(uint16_t *) (c->buf + c->length + 2) = htons(0); - *(uint16_t *) (c->buf + c->length + 4) = htons(avp); - memcpy(c->buf + c->length + 6, val, len); + c->buf16[c->length/2 + 0] = htons(l); + c->buf16[c->length/2 + 1] = htons(0); + c->buf16[c->length/2 + 2] = htons(avp); + memcpy(&c->buf[c->length + 6], val, len); c->length += 6 + len; } @@ -1766,7 +1820,7 @@ static controlt *controlnew(uint16_t mtype) } assert(c); c->next = 0; - *(uint16_t *) (c->buf + 0) = htons(0xC802); // flags/ver + c->buf16[0] = htons(0xC802); // flags/ver c->length = 12; control16(c, 0, mtype, 1); return c; @@ -1776,26 +1830,26 @@ static controlt *controlnew(uint16_t mtype) // (ZLB send). static void controlnull(tunnelidt t) { - uint8_t buf[12]; + uint16_t buf[6]; if (tunnel[t].controlc) // Messages queued; They will carry the ack. return; - *(uint16_t *) (buf + 0) = htons(0xC802); // flags/ver - *(uint16_t *) (buf + 2) = htons(12); // length - *(uint16_t *) (buf + 4) = htons(tunnel[t].far); // tunnel - *(uint16_t *) (buf + 6) = htons(0); // session - *(uint16_t *) (buf + 8) = htons(tunnel[t].ns); // sequence - *(uint16_t *) (buf + 10) = htons(tunnel[t].nr); // sequence - tunnelsend(buf, 12, t); + buf[0] = htons(0xC802); // flags/ver + buf[1] = htons(12); // length + buf[2] = htons(tunnel[t].far); // tunnel + buf[3] = htons(0); // session + buf[4] = htons(tunnel[t].ns); // sequence + buf[5] = htons(tunnel[t].nr); // sequence + tunnelsend((uint8_t *)buf, 12, t); } // add a control message to a tunnel, and send if within window static void controladd(controlt *c, sessionidt far, tunnelidt t) { - *(uint16_t *) (c->buf + 2) = htons(c->length); // length - *(uint16_t *) (c->buf + 4) = htons(tunnel[t].far); // tunnel - *(uint16_t *) (c->buf + 6) = htons(far); // session - *(uint16_t *) (c->buf + 8) = htons(tunnel[t].ns); // sequence + c->buf16[1] = htons(c->length); // length + c->buf16[2] = htons(tunnel[t].far); // tunnel + c->buf16[3] = htons(far); // session + c->buf16[4] = htons(tunnel[t].ns); // sequence tunnel[t].ns++; // advance sequence // link in message in to queue if (tunnel[t].controlc) @@ -1971,36 +2025,67 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e if (session[s].ppp.ipv6cp == Opened && session[s].ipv6prefixlen && del_routes) route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0); - if (b) + if (b) { - // This session was part of a bundle - bundle[b].num_of_links--; - LOG(3, s, 0, "MPPP: Dropping member link: %d from bundle %d\n",s,b); - if(bundle[b].num_of_links == 0) + // This session was part of a bundle + bundle[b].num_of_links--; + LOG(3, s, session[s].tunnel, "MPPP: Dropping member link: %d from bundle %d\n",s,b); + if(bundle[b].num_of_links == 0) { - bundleclear(b); - LOG(3, s, 0, "MPPP: Kill bundle: %d (No remaing member links)\n",b); - } - else + bundleclear(b); + LOG(3, s, session[s].tunnel, "MPPP: Kill bundle: %d (No remaing member links)\n",b); + } + else { - // Adjust the members array to accomodate the new change - uint8_t mem_num = 0; - // It should be here num_of_links instead of num_of_links-1 (previous instruction "num_of_links--") - if(bundle[b].members[bundle[b].num_of_links] != s) + // Adjust the members array to accomodate the new change + uint8_t mem_num = 0; + // It should be here num_of_links instead of num_of_links-1 (previous instruction "num_of_links--") + if(bundle[b].members[bundle[b].num_of_links] != s) { - uint8_t ml; - for(ml = 0; ml sizeof(buf)) m = sizeof(buf) - 4; - memcpy(buf+4, msg, m); + memcpy(buf+2, msg, m); l += m; } - controlb(c, 1, buf, l, 1); + controlb(c, 1, (uint8_t *)buf, l, 1); } else control16(c, 1, result, 1); @@ -2539,7 +2624,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) case 0: // message type message = ntohs(*(uint16_t *) b); mandatory = flags & 0x80; - LOG(4, s, t, " Message type = %u (%s)\n", *b, l2tp_code(message)); + LOG(4, s, t, " Message type = %u (%s)\n", message, l2tp_code(message)); break; case 1: // result code { @@ -3093,8 +3178,9 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } session[s].last_packet = session[s].last_data = time_now; - if (session[s].walled_garden && !config->cluster_iam_master) + if (!config->cluster_iam_master) { + // The fragments reconstruction is managed by the Master. master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; } @@ -3133,6 +3219,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr) } // read and process packet on tun +// (i.e. this routine writes to buf[-8]). static void processtun(uint8_t * buf, int len) { LOG_HEX(5, "Receive TUN Data", buf, len); @@ -3406,8 +3493,8 @@ static void regular_cleanups(double period) } } - // Drop sessions who have not responded within IDLE_TIMEOUT seconds - if (session[s].last_packet && (time_now - session[s].last_packet >= IDLE_TIMEOUT)) + // Drop sessions who have not responded within IDLE_ECHO_TIMEOUT seconds + if (session[s].last_packet && (time_now - session[s].last_packet >= config->idle_echo_timeout)) { sessionshutdown(s, "No response to LCP ECHO requests.", CDN_ADMIN_DISC, TERM_LOST_SERVICE); STAT(session_timeout); @@ -3416,7 +3503,7 @@ static void regular_cleanups(double period) } // No data in ECHO_TIMEOUT seconds, send LCP ECHO - if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= ECHO_TIMEOUT) && + if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= config->echo_timeout) && (time_now - sess_local[s].last_echo >= ECHO_TIMEOUT)) { uint8_t b[MAXETHER]; @@ -3697,6 +3784,8 @@ static void mainloop(void) { int i; uint8_t buf[65536]; + uint8_t *p = buf + 8; // for the hearder of the forwarded MPPP packet (see C_MPPP_FORWARD) + int size_bufp = sizeof(buf) - 8; clockt next_cluster_ping = 0; // send initial ping immediately struct epoll_event events[BASE_FDS + RADIUS_FDS + EXTRA_FDS]; int maxevent = sizeof(events)/sizeof(*events); @@ -3941,9 +4030,9 @@ static void mainloop(void) // incoming IP if (tun_ready) { - if ((s = read(tunfd, buf, sizeof(buf))) > 0) + if ((s = read(tunfd, p, size_bufp)) > 0) { - processtun(buf, s); + processtun(p, s); tun_pkts++; } else @@ -4192,6 +4281,9 @@ static void initdata(int optdebug, char *optconfig) config->ppp_max_failure = 5; config->kill_timedout_sessions = 1; strcpy(config->random_device, RANDOMDEVICE); + // Set default value echo_timeout and idle_echo_timeout + config->echo_timeout = ECHO_TIMEOUT; + config->idle_echo_timeout = IDLE_ECHO_TIMEOUT; log_stream = stderr; @@ -4716,7 +4808,7 @@ int main(int argc, char *argv[]) /* set hostname /after/ having read the config file */ if (*config->hostname) strcpy(hostname, config->hostname); - cli_init_hostname(hostname); + cli_init_complete(hostname); update_config(); init_tbf(config->num_tbfs); @@ -5135,18 +5227,18 @@ int sessionsetup(sessionidt s, tunnelidt t) LOG(3, s, t, "Doing session setup for session\n"); // Join a bundle if the MRRU option is accepted - if(session[s].mrru > 0 && session[s].bundle == 0) - { - LOG(3, s, t, "This session can be part of multilink bundle\n"); - if (join_bundle(s) > 0) - cluster_send_bundle(session[s].bundle); + if(session[s].mrru > 0 && session[s].bundle == 0) + { + LOG(3, s, t, "This session can be part of multilink bundle\n"); + if (join_bundle(s) > 0) + cluster_send_bundle(session[s].bundle); else { LOG(0, s, t, "MPPP: Mismaching mssf option with other sessions in bundle\n"); sessionshutdown(s, "Mismaching mssf option.", CDN_NONE, TERM_SERVICE_UNAVAILABLE); return 0; } - } + } if (!session[s].ip) { @@ -5161,7 +5253,6 @@ int sessionsetup(sessionidt s, tunnelidt t) fmtaddr(htonl(session[s].ip), 0)); } - // Make sure this is right session[s].tunnel = t; @@ -5174,13 +5265,14 @@ int sessionsetup(sessionidt s, tunnelidt t) for (i = 1; i <= config->cluster_highest_sessionid; i++) { if (i == s) continue; - if (!session[s].opened) continue; + if (!session[s].opened) break; // Allow duplicate sessions for multilink ones of the same bundle. - if (session[s].bundle && session[i].bundle && session[s].bundle == session[i].bundle) - continue; + if (session[s].bundle && session[i].bundle && session[s].bundle == session[i].bundle) continue; + if (ip == session[i].ip) { sessionkill(i, "Duplicate IP address"); + cluster_listinvert_session(s, i); continue; } @@ -5188,16 +5280,16 @@ int sessionsetup(sessionidt s, tunnelidt t) if (session[s].walled_garden || session[i].walled_garden) continue; // Guest change int found = 0; - int gu; - for (gu = 0; gu < guest_accounts_num; gu++) - { - if (!strcasecmp(user, guest_users[gu])) - { - found = 1; - break; - } - } - if (found) continue; + int gu; + for (gu = 0; gu < guest_accounts_num; gu++) + { + if (!strcasecmp(user, guest_users[gu])) + { + found = 1; + break; + } + } + if (found) continue; // Drop the new session in case of duplicate sessionss, not the old one. if (!strcasecmp(user, session[i].user)) @@ -5208,7 +5300,7 @@ int sessionsetup(sessionidt s, tunnelidt t) // no need to set a route for the same IP address of the bundle if (!session[s].bundle || (bundle[session[s].bundle].num_of_links == 1)) { - int routed = 0; + int routed = 0; // Add the route for this session. for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)