u08 eth_find_interface( mac_addr dest ) { if (mac_equal( dest, get_macaddr() )) return IFACE_INTERNAL; if (mac_equal( dest, broadcast_mac )) return IFACE_BROADCAST; return IFACE_WAN; }
/* if there was a timeout waiting for an acknowledgement of a sequence * packet we sent out, resend it. */ void resend_packets() { int i, j; if (db[23].d) { ddprintf("resend_packets..\n"); } for (i = 0; i < stp_list_count; i++) { if (!stp_list[i].box.awaiting_ack) { continue; } for (j = 0; j < device_list_count; j++) { if (device_list[j].device_type != device_type_wds || !mac_equal(stp_list[i].box.name, device_list[j].mac_address)) { continue; } if (db[23].d) { ddprintf("resend_packets doing send_seq..\n"); } stp_list[i].box.send_error++; // stp_list[i].delayed_cloud_packets++; send_seq(i, stp_list[i].box.message, stp_list[i].box.message_len); if (db[23].d) { ddprintf("resend_packets sending message..\n"); } send_message((message_t *) stp_list[i].box.message, stp_list[i].box.message_len, &device_list[j]); } } } /* resend_packets */
/* * 过滤得到登录成功包 * @return: 0: 成功获取 * -1: 超时 * -2: 服务器中止登录,密码错误吧 */ static int filte_success(pcap_t *skfd) { int stime = time((time_t*)NULL); struct pcap_pkthdr *pkt_hd; const uchar *recvbuff; int timeout; for (; time((time_t*)NULL)-stime <= TIMEOUT;) { timeout = pcap_next_ex(skfd, &pkt_hd, &recvbuff); if (0 >= timeout) return -1; FORMAT_RECVPKT(recvbuff); if (recvethii->type == htons(ETHII_8021X) && mac_equal(recvethii->dst_mac, client_mac) && recveapol->type == EAPOL_PACKET ) { if (recveap->id == sendeap->id && recveap->code == EAP_CODE_SUCS) { _D("id: %d login success.\n", sendeap->id); return 0; } else if (recveap->id == sendeap->id && recveap->code == EAP_CODE_FAIL) { _D("id: %d fail.\n", sendeap->id); return -2; } } } return -1; }
/* print our model of the current topology of the cloud */ void dprint_cloud_stats(ddprintf_t *fn, FILE *f) { bool_t first = true; int i, j; // status_dprint_title(fn, f, strlen(" ")); for (i = 0; i < cloud_stp_list_count; i++) { if (first) { first = false; } else { fn(f, "\n"); } mac_dprint(fn, f, cloud_stp_list[i].v.stp_beacon.originator); fn(f, "stp connections:\n"); for (j = 0; j < cloud_stp_list[i].v.stp_beacon.status_count; j++) { status_t *s = &cloud_stp_list[i].v.stp_beacon.status[j]; if (s->device_type == device_type_wds && s->neighbor_type == STATUS_CLOUD_NBR && !mac_equal(s->name, cloud_stp_list[i].v.stp_beacon.originator)) { fn(f, " "); mac_dprint(fn, f, s->name); } } fn(f, "outgoing arc values:\n"); status_dprint_short_array(fn, f, cloud_stp_list[i].v.stp_beacon.status, cloud_stp_list[i].v.stp_beacon.status_count); } }
/* we got an acknowledgement of our sequence message from another cloud box. */ void process_ack_sequence_msg(message_t *message, int d) { int i; if (db[23].d) { ddprintf("process_ack_sequence_msg processing <%d %d>\n", message->v.seq.sequence_num, message->v.seq.message_len); } for (i = 0; i < stp_list_count; i++) { if (!stp_list[i].box.awaiting_ack) { continue; } if (stp_list[i].box.has_eth_mac_addr || !mac_equal(stp_list[i].box.name, device_list[d].mac_address)) { continue; } if (db[23].d) { ddprintf(" found it; bumping send_sequence..\n"); } stp_list[i].box.awaiting_ack = false; stp_list[i].box.send_sequence++; // stp_list[i].box.non_cloud_packets++; } /* maybe we only have at most one box awaiting an ack. right now we * may cause the whole cloud to operate in lock step. */ turn_off_ack_timer(); }
/* debug-print the cloud box, and if we think it is a neighbor * (i.e., if we can directly see 802.11 beacons from it) print out * the signal strength to it. */ void cloud_box_print(ddprintf_t *fn, FILE *f, cloud_box_t *cloud_box, int indent) { int i; char found = 0; print_space(fn, f, indent); fn(f, "one true name (wifi interface): "); mac_dprint_no_eoln(fn, f, cloud_box->name); for (i = 0; i < nbr_device_list_count; i++) { if (mac_equal(cloud_box->name, nbr_device_list[i].name)) { found = 1; break; } } if (found) { fn(f, "; strength %d", nbr_device_list[i].signal_strength); } else { fn(f, "; (no signal strength)"); } if (cloud_box->has_eth_mac_addr) { fn(f, "; eth address "); mac_dprint_no_eoln(fn, f, cloud_box->eth_mac_addr); } fn(f, "\n"); }
dessert_cb_result_t lsr_loopback(dessert_msg_t *msg, uint32_t len, dessert_msg_proc_t *proc, dessert_sysif_t *sysif, dessert_frameid_t id) { struct ether_header* l25h = dessert_msg_getl25ether(msg); if(mac_equal(l25h->ether_dhost, dessert_l25_defsrc)) { dessert_syssend_msg(msg); return DESSERT_MSG_DROP; } return DESSERT_MSG_KEEP; }
/* see if mac address "src" is the "name" field of any element in the * status array of the stp beacon. */ static bool_t in_status_list(mac_address_t src, stp_beacon_t *stp_beacon) { int i; for (i = 0; i < stp_beacon->status_count; i++) { if (mac_equal(stp_beacon->status[i].name, src)) { return true; } } return false; }
/* find the index of the status struct in the array that has mac address mac */ int status_find_by_mac(status_t *s, int status_count, mac_address_t mac) { int i; for (i = 0; i < status_count; i++) { if (mac_equal(s[i].name, mac)) { return i; } } return -1; }
/* see if mac address "name" is the originator field of an element of * the array "new_stp_list". */ static bool_t in_mac_list(message_t *new_stp_list, int new_stp_list_count, mac_address_t name) { int i; for (i = 0; i < new_stp_list_count; i++) { if (mac_equal(new_stp_list[i].v.stp_beacon.originator, name)) { return true; } } return false; }
/* we have an arc <src -> dest>. wish to see if <dest -> src> is also * valid. we do this by finding a node whose originator is dest, and * which has src among the names in its status records. * valid places to look for dest are my_beacon (we never get here or * try this if we don't yet have a beacon), beacon, as long as have_beacon * is true, and entries in cloud_stp_list that are not shadowed by * those first two options. */ static bool_t has_valid_back_pointer(mac_address_t src, mac_address_t dest) { int i; if (mac_equal(dest, my_wlan_mac_address)) { return in_status_list(src, &my_beacon.v.stp_beacon); } else if (have_beacon && mac_equal(dest, beacon.v.stp_beacon.originator)) { return in_status_list(src, &beacon.v.stp_beacon); } /* else, look through cloud_stp_list */ for (i = 0; i < cloud_stp_list_count; i++) { if (mac_equal(dest, cloud_stp_list[i].v.stp_beacon.originator)) { return in_status_list(src, &cloud_stp_list[i].v.stp_beacon); } } return false; }
/* put mac into mac_list if it's not already there. */ static void add_mac_addr(mac_address_t mac) { int i; for (i = 0; i < mac_count; i++) { if (mac_equal(mac, mac_list[i])) { ddprintf("add_mac_addr warning: duplicat mac addresses.\n"); // return; } } if (mac_count >= MAX_CLOUD) { ddprintf("add_mac_addr; too many mac addresses.\n"); return; } mac_copy(mac_list[mac_count++], mac); }
/* print the cloud boxes in our cloud, and for each one print * the boxes it can see 802.11 beacons for, i.e., its wireless neighbors. */ void dprint_cloud_stats_short(ddprintf_t *fn, FILE *f) { bool_t first = true; int i, j; int sent = 0, dropped = 0; float fraction; for (i = 0; i < cloud_stp_list_count; i++) { if (first) { first = false; } else { fn(f, "\n"); } mac_dprint_no_eoln(fn, f, cloud_stp_list[i].v.stp_beacon.originator); for (j = 0; j < cloud_stp_list[i].v.stp_beacon.status_count; j++) { // status_t *s = &cloud_stp_list[i].v.stp_beacon.status[j]; // sent += s->noncloud_packets_sent; // dropped += s->dropped_noncloud_packets; } if (sent == 0 && dropped == 0) { fraction = 1.; } else { fraction = 1. - ((float) dropped) / (float) (dropped + sent); } fn(f, "; %.1f percent of packets delivered; stp connections:\n", fraction * 100.); for (j = 0; j < cloud_stp_list[i].v.stp_beacon.status_count; j++) { status_t *s = &cloud_stp_list[i].v.stp_beacon.status[j]; if (!mac_equal(s->name, cloud_stp_list[i].v.stp_beacon.originator) && s->device_type != device_type_wlan && s->device_type != device_type_eth) { fn(f, " "); mac_dprint(fn, f, s->name); } } } }
/* is it ok to read from the current file descriptor, which gives us * data received from another cloud box? if we are awaiting an * acknowledgement of a sequence packet we sent to another box, we * don't want to read from other devices until we get it. */ bool_t ack_read_ok(int d) { int i; /* if we're not doing flow control, just go for it. */ if (!db[22].d) { return true; } /* if we're not waiting for any ack's, it's ok to read input */ if (!awaiting_ack()) { return true; } /* if we are pretending we have no ethernet connection and this is an * ethernet connection, it's ok to read input */ if (device_list[d].device_type == device_type_eth && db[20].d) { return true; } /* if this isn't a wds device, it won't be giving us an ack. * don't read anything from any upstream devices if we are awaiting an * ack from a downstream wds device. */ if (device_list[d].device_type != device_type_wds) { return false; } /* see if we can find the stp node for this device, and if we are * awaiting an ack from that stp node. if so, it's ok to read from * this device, because we may get the ack we are hoping for. */ for (i = 0; i < stp_list_count; i++) { if (!stp_list[i].box.has_eth_mac_addr && mac_equal(stp_list[i].box.name, device_list[d].mac_address) && stp_list[i].box.awaiting_ack) { return true; } } return false; }
/* used to add wds or ad-hoc devices. uses cloud_box_t, which would cause * circularities in .h files, so leave it here. */ void add_perm_io_stat_index(int *nbr_perm_io_stat_index, mac_address_t neighbor_name, device_type_t type) { int i; bool_t found; status_t *p; ddprintf("\n\n ADD_PERM_IO_STAT_INDEX \n\n"); found = false; for (i = 0; i < perm_io_stat_count; i++) { if (mac_equal(perm_io_stat[i].name, neighbor_name)) { *nbr_perm_io_stat_index = i; found = true; break; } } if (!found) { if (perm_io_stat_count >= MAX_CLOUD) { ddprintf("add_perm_io_stat_index; too many perm_io_stat's\n"); /* at some point, garbage collect perm_io_stat with oldest * last-update time */ goto done; } p = &perm_io_stat[perm_io_stat_count++]; status_init(p); mac_copy(p->name, neighbor_name); p->device_type = type; *nbr_perm_io_stat_index = perm_io_stat_count - 1; } done : ; status_dprint_short_array(eprintf, stderr, perm_io_stat, perm_io_stat_count); ddprintf("perm_io_stat_count: %d\n", perm_io_stat_count); } /* add_perm_io_stat_index */
/* * 过滤得到eap-request-identity包 * @return: 0: 成功获取 * -1: 超时 */ static int filte_req_identity(pcap_t *skfd) { int stime = time((time_t*)NULL); struct pcap_pkthdr *pkt_hd; const uchar *recvbuff; int timeout; for (; time((time_t*)NULL)-stime <= TIMEOUT;) { timeout = pcap_next_ex(skfd, &pkt_hd, &recvbuff); if (0 >= timeout) return -1; FORMAT_RECVPKT(recvbuff); /* eap包且是request */ if (recvethii->type == htons(ETHII_8021X) && mac_equal(recvethii->dst_mac, client_mac) && recveapol->type == EAPOL_PACKET && recveap->code == EAP_CODE_REQ && recveap->type == EAP_TYPE_IDEN) { return 0; } } return -1; }
/* see if there is any output available on fd using select, and if so * read it and send it as a verified message to the other side. */ static void read_and_fwd_shell_output(int fd) { while (true) { byte buf[1024]; fd_set read_set; struct timeval timer = {0, 0}; int result; FD_ZERO(&read_set); FD_SET(fd, &read_set); result = select(fd + 1, &read_set, 0, 0, &timer); if (result == -1) { fprintf(stderr, "read_and_fwd_shell_output; select error %s\n", strerror(errno)); } if (result == 0) { break; } result = read(fd, (char *) &(buf[4]), 1020); if (db[2].d) { fprintf(stderr, "read_and_fwd_shell_output message from fd %d:\n", fd); print_message(stderr, (unsigned char *) &buf, result); } if (result == 0) { break; } if (result == -1) { perror("read of stdin failed"); } else if (!mac_equal(dest_mac_addr, zero_mac_addr)) { if (state != state_receiving_shell_output) { state = state_receiving_shell_output; seq = 1; } verified_send_message(buf, result, shell_response_msg); } } }
/* * 过滤得到eap-request-md5clg包 * @return: 0: 成功获取 * -1: 超时 * -2: 服务器中止登录,用户名不存在 */ static int filte_req_md5clg(pcap_t *skfd) { int stime = time((time_t*)NULL); struct pcap_pkthdr *pkt_hd; const uchar *recvbuff; int timeout; for (; time((time_t*)NULL)-stime <= TIMEOUT;) { timeout = pcap_next_ex(skfd, &pkt_hd, &recvbuff); if (0 >= timeout) return -1; FORMAT_RECVPKT(recvbuff); /* 是request且是eap-request-md5clg */ if (recvethii->type == htons(ETHII_8021X) && mac_equal(recvethii->dst_mac, client_mac) && recveapol->type == EAPOL_PACKET ) { if (recveap->code == EAP_CODE_REQ && recveap->type == EAP_TYPE_MD5) { #ifdef DEBUG _M("id: %d\n", sendeap->id); _M("md5: "); for (int i = 0; i < recveapbody->md5size; ++i) _M("%.2x", recveapbody->md5value[i]); _M("\n"); _M("ex-md5: "); for (int i = 0; i < ntohs(recveap->len) - recveapbody->md5size - 2; ++i) _M("%.2x", recveapbody->md5exdata[i]); _M("\n"); #endif return 0; } else if (recveap->id == sendeap->id && recveap->code == EAP_CODE_FAIL) { _D("id: %d fail.\n", sendeap->id); return -2; } } } return -1; }
/* write an html page to /tmp/cloud.tmp giving an ascii-art representation * of the entire cloud, and two matrices giving packets received and lost, * and signal strengths among the boxes in the cloud. */ void do_print_cloud(void) { int i, j, k, r; FILE *f = fopen("/tmp/cloud.tmp", "w"); if (f == NULL) { ddprintf("do_print_cloud; could not open /tmp/cloud.tmp: %s\n", strerror(errno)); goto done; } fprintf(f, "<html>\n"); fprintf(f, "<head>\n"); fprintf(f, "<SCRIPT language=JavaScript>\n"); fprintf(f, "function init()\n"); fprintf(f, "{\n"); fprintf(f, " x = '<%c set_merge_cloud_db(\"d 2038\"); %c>';\n", '%', '%'); fprintf(f, "}\n"); fprintf(f, "</SCRIPT>\n"); fprintf(f, "<META HTTP-EQUIV=\"refresh\" CONTENT=\"5\">\n"); fprintf(f, "</head>\n"); fprintf(f, "<body onload=init()>\n"); fprintf(f, "<p>\n"); fprintf(f, "<h3>\n"); fprintf(f, "Cloud connectivity\n"); fprintf(f, "</h3>\n"); fprintf(f, "<pre>\n"); graphit_dprint(eprintf, f, &cloud_stp_tree[0]); fprintf(f, "</pre>\n"); if (!db[38].d) { goto almost_done; } /* add all of the cloud_stp_list entries to mac_list, a temporary * array giving mac addresses of rows and columns. */ mac_count = 0; for (i = 0; i < cloud_stp_list_count; i++) { stp_beacon_t *beacon = &cloud_stp_list[i].v.stp_beacon; add_mac_addr(beacon->originator); } /* do the two matrices (packets sent and signal strength) */ for (r = 0; r < 2; r++) { /* print the title of the packet matrix */ fprintf(f, "<p>\n"); fprintf(f, "<h3>\n"); if (r == 0) { fprintf(f, "Packets received, packets dropped, " "percent packets received\n"); fprintf(f, "<br>\n"); fprintf(f, "(sender at top of column, receiver at start of row)\n"); } else { fprintf(f, "Signal strength\n"); fprintf(f, "<br>\n"); fprintf(f, "(how strongly each row entry sees each column entry)\n" ); } fprintf(f, "</h3>\n"); if (cloud_stp_list_count <= 1) { goto almost_done; } fprintf(f, "<table frame=box rules=all>\n"); /* top row; empty first cell, then mac addresses */ fprintf(f, " <tr>\n"); fprintf(f, " <td> </td>"); for (j = 0; j < mac_count; j++) { /* skip ad-hoc clients for column headers of first matrix */ if (r == 0 && node_names[j][0] == '(') { continue; } fprintf(f, " <td> "); //mac_dprint_no_eoln(eprintf, f, mac_list[j]); fprintf(f, "%s", node_names[j]); fprintf(f, " </td> "); } fprintf(f, "\n"); fprintf(f, " </tr>\n"); for (i = 0; i < mac_count; i++) { stp_beacon_t *src = NULL; /* for row entries, ignore ad-hoc clients */ if (node_names[i][0] == '(') { continue; } for (j = 0; j < cloud_stp_list_count; j++) { stp_beacon_t *beacon = &cloud_stp_list[j].v.stp_beacon; if (mac_equal(mac_list[i], beacon->originator)) { src = beacon; break; } } fprintf(f, " <tr>\n"); fprintf(f, " <td> "); // mac_dprint_no_eoln(eprintf, f, mac_list[i]); fprintf(f, "%s", node_names[i]); fprintf(f, " </td> "); for (j = 0; j < mac_count; j++) { bool_t did_something = false; /* for column entries, ignore ad-hoc clients in first matrix */ if (r == 0 && node_names[j][0] == '(') { continue; } if (src != NULL) { for (k = 0; k < src->status_count; k++) { status_t *s = &src->status[k]; if (s->device_type != device_type_wds) { continue; } if (mac_equal(mac_list[j], s->name)) { if (r == 0) { float den = s->packets_received + s->packets_lost + s->ping_packets_received + s->ping_packets_lost; int percent; if (den == 0) { percent = 100; } else { float fpct; fpct = ((float) (s->packets_received + s->ping_packets_received)) / den; percent = (int) (.5 + 100. * fpct); } fprintf(f, " <td> %d %d %d%c </td> ", s->packets_received + s->ping_packets_received, s->packets_lost + s->ping_packets_lost, percent, '%'); did_something = true; break; } else { fprintf(f, " <td> %d </td> ", s->sig_strength); did_something = true; break; } } } } if (!did_something) { fprintf(f, " <td> </td> "); } } fprintf(f, "\n </tr>\n"); } fprintf(f, "</table>\n"); } almost_done: fprintf(f, "</body>\n"); fprintf(f, "</html>\n"); if (fclose(f) != 0) { ddprintf("do_print_cloud; could not fclose /tmp/cloud.tmp: %s\n", strerror(errno)); goto done; } if (rename("/tmp/cloud.tmp", "/tmp/cloud.asp") != 0) { ddprintf("do_print_cloud; unable to rename %s to %s: %s\n", "/tmp/cloud.tmp", "/tmp/cloud.asp", strerror(errno)); goto done; } done: set_next_cloud_print_alarm(); } /* do_print_cloud */
/* just got a message from raw device d. if d is not a wds device, the * message is ok. (for now we are just doing flow control over wds * connections.) if it is a wds device, find the corresponding stp link * and return true iff we have gotten a sequence packet and are expecting * a message. */ bool_t message_ok(int d, int message_len) { int i; if (!db[22].d) { return true; } if (db[23].d) { ddprintf("message_ok;\n"); } if (device_list[d].device_type != device_type_wds) { if (db[23].d) { ddprintf(" not wds; returning true\n"); } return true; } for (i = 0; i < stp_list_count; i++) { if (stp_list[i].box.has_eth_mac_addr || !mac_equal(stp_list[i].box.name, device_list[d].mac_address)) { continue; } if (stp_list[i].box.expect_seq) { if (db[23].d) { ddprintf(" !expect_seq; " "returning false\n"); } stp_list[i].box.recv_error++; return false; } if (stp_list[i].box.recv_message_len != message_len) { if (db[23].d) { ddprintf(" bad message_len; " "returning false\n"); } stp_list[i].box.recv_error++; return false; } { message_t response; memset(&response, 0, sizeof(response)); response.message_type = ack_sequence_msg; response.v.seq.sequence_num = stp_list[i].box.recv_sequence; response.v.seq.message_len = stp_list[i].box.recv_message_len; if (db[23].d) { ddprintf(" sending ack_sequence_msg <%d %d>\n", stp_list[i].box.recv_sequence, stp_list[i].box.recv_message_len); } mac_copy(response.dest, stp_list[i].box.name); if (db[24].d) { ddprintf(" not sending ack message..\n"); db[24].d = false; } else { send_cloud_message(&response); } stp_list[i].box.expect_seq = true; if (!stp_list[i].box.received_duplicate) { stp_list[i].box.recv_sequence++; } else { stp_list[i].box.received_duplicate = false; if (db[23].d) { ddprintf(" received_duplicate; " "returning false\n"); } return false; } } if (db[23].d) { ddprintf(" found it; returning true\n"); } return true; } if (db[23].d) { ddprintf(" didn't find it; returning false\n"); } return false; }
/* we have received a sequence message from another cloud box. see if * it is the sequence message we expected. tally any errors we detect * if we weren't expecting a sequence message, if we got one that didn't * agree with what we expected, etc. if everything is fine, update our * state to indicate that we are not expecting a sequence number from * the cloud box that sent it any more. */ void process_sequence_msg(message_t *message, int d) { int i; if (db[23].d) { ddprintf("process_sequence_msg processing <%d %d>\n", message->v.seq.sequence_num, message->v.seq.message_len); } if ((!ad_hoc_mode && device_list[d].device_type != device_type_wds) || (ad_hoc_mode && device_list[d].device_type != device_type_ad_hoc)) { ddprintf("process_sequence_msg: message from non-wds device.\n"); return; } for (i = 0; i < stp_list_count; i++) { if (stp_list[i].box.has_eth_mac_addr || !mac_equal(stp_list[i].box.name, device_list[d].mac_address)) { continue; } if (!stp_list[i].box.expect_seq) { ddprintf("process_sequence_msg: stp device not expecting seq.\n"); stp_list[i].box.recv_error++; return; } /* is this a duplicate? */ if (stp_list[i].box.recv_sequence == (byte) (message->v.seq.sequence_num + 1)) { ddprintf("process_sequence_msg: got duplicate message.\n"); stp_list[i].box.received_duplicate = true; stp_list[i].box.recv_error++; } else if (stp_list[i].box.recv_sequence != message->v.seq.sequence_num && stp_list[i].box.recv_sequence_error < MAX_SEQUENCE_ERROR) { ddprintf("process_sequence_msg: expecting sequence num %d, " "got %d.\n", stp_list[i].box.recv_sequence, message->v.seq.sequence_num); stp_list[i].box.recv_sequence_error++; stp_list[i].box.recv_error++; return; } else if (stp_list[i].box.recv_sequence != message->v.seq.sequence_num && stp_list[i].box.recv_sequence_error >= MAX_SEQUENCE_ERROR) { ddprintf("process_sequence_msg: expecting sequence num %d, " "got %d. but, sequence_error threshold exceeded.\n" "resetting recv_sequence.\n", stp_list[i].box.recv_sequence, message->v.seq.sequence_num); stp_list[i].box.recv_sequence = message->v.seq.sequence_num; stp_list[i].box.recv_error++; } else { stp_list[i].box.recv_sequence_error = 0; if (db[23].d) { ddprintf("process_sequence_msg: got sequence num %d, " "which we expected.\n", message->v.seq.sequence_num); } } stp_list[i].box.expect_seq = false; stp_list[i].box.recv_message_len = message->v.seq.message_len; break; } }
/* expire any stale mac addresses from the mac_list. * add mac_address to the list, or if it's already there refresh its * time to "now". * * include name, signal_strength, and desc in the record for this mac address. */ void mac_list_add(mac_list_t *mac_list, mac_address_t mac_addr, mac_address_t name, int signal_strength, char *desc, bool_t write_um) { int i, this_beacon; struct timeval tv; struct timezone tz; if (gettimeofday(&tv, &tz)) { fprintf(stderr, "mac_list_add; gettimeofday failed\n"); return; } if (mac_list_expire_timed_macs(mac_list)) { fprintf(stderr, "mac_list_add; mac_list_expire_timed_macs failed\n"); return; } this_beacon = -1; for (i = 0; i < mac_list->next_beacon; i++) { if (mac_equal(mac_addr, mac_list->beacons[i].mac_addr)) { this_beacon = i; break; } } if (this_beacon == -1) { if (mac_list->next_beacon == MAX_CLOUD) { fprintf(stderr, "mac_list_add; too many mac addresses\n"); return; } mac_copy(mac_list->beacons[mac_list->next_beacon].mac_addr, mac_addr); this_beacon = mac_list->next_beacon; mac_list->next_beacon++; } mac_copy(mac_list->names[this_beacon], name); if (desc != NULL) { strncpy(mac_list->desc[this_beacon], desc, MAX_DESC); } if (signal_strength != NO_SIGNAL_STRENGTH) { mac_list->signal_strength[this_beacon] = signal_strength; } mac_list->beacons[this_beacon].tv_sec = tv.tv_sec; mac_list->beacons[this_beacon].tv_usec = tv.tv_usec; #ifdef DEBUG if (debug_file_inited) { fprintf(debug_file, "%s; time update ", mac_list->fname); mac_print_no_eoln(debug_file, mac_list->beacons[this_beacon].mac_addr); fprintf(debug_file, " at "); util_print_time(debug_file, &tv); fprintf(debug_file, "\n"); fflush(debug_file); } #endif if (write_um) { if (mac_list_write(mac_list)) { fprintf(stderr, "mac_list_add; write_beacons failed\n"); } } }
/* we have an incoming message from another cloud box. * see if the message has a sequence number, and compare it to our * own sequence number for that box. this allows us to see if we * got missing packets or duplicate packets from the other box. * * broadcast pings are treated specially; they have type "ping_response_msg" * and broadcast mac address as destination. so, we keep track of pings * from all cloud boxes. * * otherwise, use the dest mac address to find the index of the sender * among our neighbors. * * tally received packet count and error count (number of packets missed * or duplicated) in three categories: * * - broadcast pings * - cloud protocol messages (received via a separate set of interfaces * (eth0.1 etc.) * - raw client data packets received */ void sequence_check(message_t *message, int device_index, int dev_index) { int pind; int diff; byte last_recvd, incoming; mac_address_ptr_t neighbor; bool_t have_recv_seq; bool_t bcast_ping = false; neighbor = get_name(device_index, message->eth_header.h_source); if (neighbor == NULL) { ddprintf("sequence_check; couldn't find neighbor for "); mac_dprint(eprintf, stderr, message->eth_header.h_source); } if (mac_equal(message->eth_header.h_dest, mac_address_bcast) && message->message_type == ping_response_msg) { bcast_ping = true; } if ((!bcast_ping && mac_equal(message->eth_header.h_dest, mac_address_bcast)) || mac_equal(message->eth_header.h_dest, mac_address_zero)) { return; } pind = status_find_by_mac(perm_io_stat, perm_io_stat_count, neighbor); if (pind == -1) { if (db[48].d) { ddprintf("sequence_check; no pind; returning.\n"); } return; } if (bcast_ping) { perm_io_stat[pind].ping_packets_received++; have_recv_seq = have_recv_ping_sequence[pind]; last_recvd = recv_ping_sequence[pind]; } else if (message->eth_header.h_proto == htons(CLOUD_MSG)) { perm_io_stat[pind].packets_received++; have_recv_seq = have_recv_sequence[pind]; last_recvd = recv_sequence[pind]; } else { perm_io_stat[pind].data_packets_received++; have_recv_seq = have_recv_data_sequence[pind]; last_recvd = recv_data_sequence[pind]; } incoming = message->sequence_num; #ifdef DEBUG_48 if (db[48].d) { ddprintf("sequence_check; seq got <%d %d %d> " "expected <%d %d %d>\n", incoming, device_index, dev_index, last_recvd, db_i[pind], db_dev_index[pind]); } #endif if (have_recv_seq) { if (incoming != (last_recvd + 1) % 256) { diff = ((int) incoming) - ((int) last_recvd); if (diff != 0) { if (diff < 0) { diff += 256; } if (bcast_ping) { perm_io_stat[pind].ping_packets_lost += diff; } else if (message->eth_header.h_proto == htons(CLOUD_MSG)) { perm_io_stat[pind].packets_lost += diff; } else { perm_io_stat[pind].data_packets_lost += diff; } } if (db[48].d) { ddprintf("seq error; diff %d\n", diff); } } } if (bcast_ping) { have_recv_ping_sequence[pind] = true; recv_ping_sequence[pind] = incoming; } else if (message->eth_header.h_proto == htons(CLOUD_MSG)) { have_recv_sequence[pind] = true; recv_sequence[pind] = incoming; } else { have_recv_data_sequence[pind] = true; recv_data_sequence[pind] = incoming; } #ifdef DEBUG_48 memcpy(&db_messages[pind], message, sizeof(message)); db_i[pind] = device_index; db_dev_index[pind] = dev_index; #endif } /* sequence_check */
/* add children of new_stp_list[ind]. we do this by looking at * the status array of new_stp_list[ind]. for each of those, we see * if we have a valid back pointer, based on my_beacon, beacon if we have * a new one, or cloud_stp_list. for valid dest nodes we find, see which * ones are not yet in new_stp_list, and add those as children. the * new_stp_list entries we copy will be beacon if we have it and the * dest matches beacon's originator field, or from cloud_stp_list, our * old version of this data structure that contains most recent beacons * from all nodes we were connected to the last time this set of routines * was run. */ static void add_children(int ind) { int i, j; int prev_new_stp_list_count, next_new_stp_list_count; stp_beacon_t *node = &new_stp_list[ind].v.stp_beacon; char buf[20]; if (db[32].d) { ddprintf("add_children..\n"); } prev_new_stp_list_count = new_stp_list_count; new_stp_child_start[ind] = new_stp_list_count; new_stp_child_count[ind] = 0; mac_sprintf(new_node_names[ind], node->originator); if (db[32].d) { ddprintf("added new_node_names[%d]: %s\n", ind, mac_sprintf(buf, node->originator)); } for (i = 0; i < node->status_count; i++) { status_t *s = &node->status[i]; message_t *new_node = NULL; if (s->device_type != device_type_wds) { continue; } if (s->neighbor_type != STATUS_CLOUD_NBR) { continue; } if (in_mac_list(new_stp_list, new_stp_list_count, s->name)) { continue; } if (!has_valid_back_pointer(node->originator, s->name)) { continue; } if (have_beacon && mac_equal(s->name, beacon.v.stp_beacon.originator)) { new_node = &beacon; } else { for (j = 0; j < cloud_stp_list_count; j++) { if (mac_equal(s->name, cloud_stp_list[j].v.stp_beacon.originator)) { new_node = &cloud_stp_list[j]; break; } } } if (new_node == NULL || new_stp_list_count >= MAX_CLOUD) { break; } new_stp_list[new_stp_list_count] = *new_node; new_stp_child_count[new_stp_list_count] = 0; new_stp_list_count++; new_stp_child_count[ind]++; if (db[32].d) { ddprintf("add "); mac_dprint(eprintf, stderr, new_stp_list[new_stp_list_count - 1] .v.stp_beacon.originator); } } next_new_stp_list_count = new_stp_list_count; /* add any ad-hoc clients that this box serves */ for (i = 0; i < node->status_count; i++) { status_t *s = &node->status[i]; char buf[20]; if (s->neighbor_type != STATUS_NON_CLOUD_CLIENT) { continue; } if (in_mac_list(new_stp_list, new_stp_list_count, s->name)) { continue; } if (new_stp_list_count >= MAX_CLOUD) { break; } new_stp_child_count[ind]++; /* not really necessary since we now init new_node_names[i] here */ mac_copy(new_stp_list[new_stp_list_count].v.stp_beacon.originator, s->name); new_stp_child_count[new_stp_list_count] = 0; sprintf(new_node_names[new_stp_list_count], "(%s)", mac_sprintf(buf, s->name)); new_stp_list_count++; } for (i = prev_new_stp_list_count; i < next_new_stp_list_count; i++) { add_children(i); } if (db[32].d) { ddprintf("done add_children(%d)..\n", ind); dprint_db_cloud_stats(eprintf, stderr, new_stp_list, new_stp_child_start, new_stp_child_count, new_stp_list_count); } }
/* see which wds devices we are getting beacons from. (this routine doesn't * look at the ethernet connection or the wlan connection. those devices * are added at startup, the latter only if we were told to do so from the * command line. they don't come and go. only the wds devices * come and go.) * * this routine manages the device_list array, which includes if_index, * file descriptor, etc. to support actual low-level communication. */ char check_devices(void) { char result = 0; int retval; static struct ifreq get_index; struct sockaddr_ll bind_arg; char wds_devices[MAX_CLOUD][64]; mac_address_t wds_macs[MAX_CLOUD]; int wds_count = 0; int w, d; char buf[64]; FILE *wds = fopen(wds_file, "r"); if (wds == NULL) { ddprintf("check_devices; fopen failed: %s\n", strerror(errno)); ddprintf(" file: '%s'\n", wds_file); goto finish; } /* read the mac addresses of the wds devices into * local array wds_devices */ while (1) { if (wds_count >= MAX_CLOUD) { ddprintf("check_devices: too many wds devices\n"); break; } if (skip_comment_line(wds) != 0) { ddprintf("check_devices; problem reading file.\n"); break; } #ifdef WRT54G retval = mac_read(wds, wds_macs[wds_count]); #else retval = fscanf(wds, "%s", wds_devices[wds_count]); #endif if (retval != 1) { break; } #ifdef WRT54G retval = fscanf(wds, "%s", wds_devices[wds_count]); #else retval = mac_read(wds, wds_macs[wds_count]); #endif if (retval != 1) { ddprintf("check_devices; could not read device name from wds\n"); goto finish; } wds_count++; } top : /* see if every wds device in our list matches current truth */ for (d = 0; d < device_list_count; d++) { int found = 0; if (device_list[d].device_type != device_type_wds && device_list[d].device_type != device_type_cloud_wds) { continue; } for (w = 0; w < wds_count; w++) { if (mac_equal(device_list[d].mac_address, wds_macs[w])) { found = 1; break; } } if (!found || strstr(device_list[d].device_name, wds_devices[w]) == NULL) { result = 1; delete_device(d); goto top; } if (!use_pipes) { /* check to see that the if_index is still the same. * (if "wds0.2" gets deleted and then re-created, it probably * has a different if_index.) */ sprintf(get_index.ifr_name, device_list[d].device_name); retval = ioctl(device_list[d].fd, SIOCGIFINDEX, &get_index); if (retval == -1) { ddprintf("check_devices; could not get device index: %s\n", strerror(errno)); goto finish; } if (device_list[d].if_index != get_index.ifr_ifindex) { device_list[d].if_index = get_index.ifr_ifindex; memset(&bind_arg, 0, sizeof(bind_arg)); bind_arg.sll_family = AF_PACKET; bind_arg.sll_ifindex = get_index.ifr_ifindex; bind_arg.sll_protocol = htons(ETH_P_ALL); retval = bind(device_list[d].fd, (struct sockaddr *) &bind_arg, sizeof(bind_arg)); if (retval == -1) { ddprintf("check_devices; bind failed: %s\n", strerror(errno)); goto finish; } result = 1; goto top; } } } /* see if every device out there is in our local table */ for (w = 0; w < wds_count; w++) { int found = 0; for (d = 0; d < device_list_count; d++) { if (mac_equal(device_list[d].mac_address, wds_macs[w])) { found = 1; break; } } if (!found) { result = 1; add_device( ad_hoc_mode ? "ad-hoc device" : wds_devices[w], wds_macs[w], ad_hoc_mode ? device_type_ad_hoc : device_type_wds); if (!ad_hoc_mode && db[47].d) { sprintf(buf, "%s:1", wds_devices[w]); add_device(buf, wds_macs[w], device_type_cloud_wds); } } } finish : if (wds != NULL) { fclose(wds); } return result; } /* check_devices */
/* accept this node iff it is not equal to "delete_me". */ char delete_node(node_t *node) { return (!mac_equal(node->box.name, delete_me)); }