void mac_queue_buf_insert(buffer_t *buf) { if (buf) { list_add(mac_rx_queue, buf); debug_dump_buf(buf->dptr, buf->len); } }
/* * Simulates the sending of data. For the sim interface, the transmission of * data means that the data gets sent into the pipe whose destination is * the simulator. */ U8 drvr_tx(const buffer_t *buf) { DBG_PRINT_RAW("DRVR_TX: "); debug_dump_buf(buf->dptr, buf->len); tx_len = buf->len; sim_pipe_data_out(buf->dptr, buf->len); DBG_PRINT("TEST_DRIVER: Frame transmitted.\n"); return 1; }
static bool skip_rr(u8 *dns, size_t len, size_t *offset) { u16 rdlength; if (skip_name(dns, len, offset) && ((*offset) + 6) <= len ){ rdlength = dns[(*offset) + 4] << 8 | dns[(*offset) + 5]; debug_dump_buf(dns, len, *offset, "skip_rr"); NFDEBUG("rdlength: %d\n", rdlength); if ((*offset) + 6 + rdlength < len) { (*offset) += 6 + rdlength; return true; } } pr_warn("Skipping RR failed. offset: %zu, len: %zu\n", *offset, len); return false; }
static bool skip_name(u8 *dns, size_t len, size_t *offset) { /* skip labels */ debug_dump_buf(dns, len, *offset, "skip_name"); while (dns[*offset] > 0 && (*offset) < len-4) { if (dns[*offset] <= 63) (*offset) += dns[*offset] + 1; else { (*offset) += 1; /* Compressed label */ break; } } if (*offset >= len-4) { pr_warn(KBUILD_MODNAME ": Tried to skip past packet length! offset: %zu, len: %zu\n", *offset, len); return false; } /* offset is now pointing on the last octet of name */ (*offset) += 5; /* skip qtype and qclass */ return true; }
static bool dns_mt(const struct sk_buff *skb, struct xt_action_param *par) #endif { const struct xt_dns_info *info = par->matchinfo; u8 *dns; size_t len, offset; bool is_match, invert; u16 counts[4]; /* qdcount, ancount, nscount, arcount */ u16 udpsize; int i; /* skip fragments */ if (par->fragoff) return false; NFDEBUG("skb->len: %d, skb->data_len: %d, par->thoff: %d\n", skb->len, skb->data_len, par->thoff); /* find UDP payload */ offset = par->thoff + sizeof(struct udphdr); len = skb->len - offset; if (len > sizeof(pktbuf)) { pr_warn(KBUILD_MODNAME": Packet too big. Increase MAX_MTU (size %d)\n", skb->len); return false; } dns = skb_header_pointer(skb, offset, len, pktbuf); if (dns == NULL) { pr_warn(KBUILD_MODNAME": skb_header_pointer failed!\n"); return false; } /* minimum DNS query payload is 17 bytes (for "." root zone) */ if (len < 17) return false; NFDEBUG("skb->len: %d, skb->data_len: %d, len: %zu\n", skb->len, skb->data_len, len); debug_dump_buf(dns, len, 0, "ipt_dns"); /* check if we are dealing with DNS query */ if (info->flags & XT_DNS_QUERY) { invert = ((info->invert_flags & XT_DNS_QUERY) != 0); is_match = ((dns[2] & NS_QR) == NS_QR_QUERY); if (is_match == invert) return false; } /* check if we are dealing with DNS response */ if (info->flags & XT_DNS_RESPONSE) { invert = ((info->invert_flags & XT_DNS_RESPONSE) != 0); is_match = ((dns[2] & NS_QR) == NS_QR_RESPONSE); if (is_match == invert) return false; } /* fill counts[] with data from dns header */ for (i=0; i<4; i++) { counts[i] = ntohs(((u16*)dns)[i+2]); } /* query type test */ if (info->flags & XT_DNS_QTYPE) { NFDEBUG("Entering qtype match\n"); invert = ((info->invert_flags & XT_DNS_QTYPE) != 0); is_match = counts[0] > 0; /* qdcount at least 1 */ if (!is_match) goto qtype_out; /* offset is set to the first question section */ offset = 12; is_match = skip_name(dns, len, &offset); if (!is_match) goto qtype_out; NFDEBUG("Matching qtype: %x %x %x %x\n", dns[offset-4], dns[offset-3], dns[offset-2], dns[offset-1]); /* match if type=info->type, class IN */ is_match = (dns[offset-4] == 0x00) && (dns[offset-3] == info->qtype) && (dns[offset-2] == 0x00) && (dns[offset-1] == 0x01); qtype_out: if (is_match == invert) return false; } /* check for EDNS0 */ if (info->flags & XT_DNS_EDNS0) { invert = ((info->invert_flags & XT_DNS_EDNS0) != 0); is_match = counts[3] > 0; /* arcount at least 1 */ offset = 12; /* skip query sections */ for (i=0; i<counts[0]; i++) { is_match &= skip_name(dns, len, &offset); if (!is_match) break; } if (!is_match) goto edns0_out; /* skip answer and authority sections */ for (i=0; i<(counts[1]+counts[2]); i++) { is_match &= skip_rr(dns, len, &offset); if (!is_match) break; } if (!is_match) goto edns0_out; /* try to find EDNS0 pseudo-RR */ for (i=0; i<counts[3]; i++) { if (dns[offset] == 0 && dns[offset+1] == 0 && dns[offset+2] == 41) break; is_match &= skip_rr(dns, len, &offset); if (!is_match) break; } if (!is_match || (i == counts[3])) { is_match = false; goto edns0_out; } /* EDNS0 found */ if (info->flags & XT_DNS_BUFSIZE) { /* TODO: XT_DNS_BUFSIZE inversion not implemented */ udpsize = dns[offset+3] << 8 | dns[offset+4]; if (udpsize < info->bufsize[0] || udpsize > info->bufsize[1]) { is_match = false; goto edns0_out; } } debug_dump_buf(dns, len, offset, "ipt_dns_edns0"); edns0_out: if (is_match == invert) return false; } /* Nothing stopped us so far, let's accept the packet */ return true; }
static void *on_stdin_read(oop_source *oop_src, int std_in, oop_event event, void *ctx) { ruli_res_t *res_ctx = (ruli_res_t *) ctx; int result; const int QBUF_SIZE = sizeof(srv_qbuf_t); assert(std_in == 0); assert(event == OOP_READ); /* * Read stdin */ result = read_stdin(std_in); switch (result) { case STDIN_READ_OK: break; case STDIN_READ_BLOCK: return OOP_CONTINUE; case STDIN_READ_EOF: /* Stop monitoring stdin */ oop_src->cancel_fd(oop_src, std_in, OOP_READ); return OOP_CONTINUE; case STDIN_READ_ERROR: return OOP_HALT; case STDIN_READ_OVERFLOW: fprintf(stderr, "%s: on_stdin_read(): stdin read buffer overflow\n", prog_name); reset_stdin_buf(); return OOP_CONTINUE; default: assert(0); /* NOT REACHED */ } /* * Scan possible hostnames from stdin */ for (;;) { srv_qbuf_t *qbuf; /* plain domain */ const int domain_buf_size = IN_BUF_SIZE; char domain[domain_buf_size]; int domain_len; /* * Parse hostname */ result = get_next_domain(domain, domain_buf_size, &domain_len); /* If no domain found yet, keep waiting for one */ if (result == PARSE_DOMAIN_NONE) return OOP_CONTINUE; /* Do not expect other errors, not even overflow */ assert(!result); /* * Now we have the full domain name, submit a query for it */ /* * Break full domain name in service + domain into qbuf */ { char *past_end = domain + domain_len; char *i = domain; for (; i < past_end; ++i) { if (*i == '.') { ++i; if (i < past_end) { if (*i != '_') break; } } } if (i >= past_end) { fprintf(stderr, "%s: on_stdin_read(): could not split service/domain\n", prog_name); return OOP_CONTINUE; } /* Allocate qbuf */ qbuf = (srv_qbuf_t *) malloc(QBUF_SIZE); if (!qbuf) { fprintf(stderr, "%s: on_stdin_read(): could not allocate srv_qbuf_t: malloc(%d) failed\n", prog_name, QBUF_SIZE); return OOP_CONTINUE; } qbuf->txt_service_len = i - domain - 1; assert(qbuf->txt_service_len < QBUFSZ); memcpy(qbuf->txt_service, domain, qbuf->txt_service_len); qbuf->txt_service[qbuf->txt_service_len] = '\0'; #ifdef SRVSOLVER_DEBUG debug_dump_buf(stderr, "on_stdin_read(): txt_service=%s txt_service_len=%d", qbuf->txt_service, qbuf->txt_service_len); #endif qbuf->txt_domain_len = past_end - i; assert(qbuf->txt_domain_len < QBUFSZ); memcpy(qbuf->txt_domain, i, qbuf->txt_domain_len); qbuf->txt_domain[qbuf->txt_domain_len] = '\0'; #ifdef SRVSOLVER_DEBUG debug_dump_buf(stderr, "on_stdin_read(): txt_domain=%s txt_domain_len=%d", qbuf->txt_domain, qbuf->txt_domain_len); #endif } /* * Encode buffers in qbuf (txt => raw) */ if (encode_srv_qbuf(qbuf)) { fprintf(stderr, "%s: on_stdin_read(): could not encode domain in srv_qbuf_t\n", prog_name); free(qbuf); return OOP_CONTINUE; } /* * Send query */ { ruli_srv_t *srv_qry = submit_query(res_ctx, qbuf); if (!srv_qry) { fprintf(stderr, "%s: on_stdin_read(): could not send SRV query\n", prog_name); free(qbuf); return OOP_CONTINUE; } } } /* for loop */ assert(0); /* NOT REACHED */ return OOP_CONTINUE; }
/* * Handle the rx events from the mac process. If the driver * receives a valid frame, it will send an event to the mac * process. The mac process will then call the event handler * which retrieves the frame from the rx queue and parses it. * Once parsed, it will be handled according to the frame type. * If its a command frame, it gets sent to the command handler, * a data frame gets sent to the next higher layer, etc... */ static void mac_eventhandler(process_event_t event) { buffer_t *buf, *buf_out; mac_hdr_t hdr; mac_cmd_t cmd; bool frm_pend; mac_pcb_t *pcb = mac_pcb_get(); mac_pib_t *pib = mac_pib_get(); if (event == event_mac_rx) { DBG_PRINT("MAC_EVENTHANDLER: Rx event occurred.\n"); buf = mac_queue_buf_pop(); if (buf) { DBG_PRINT_RAW("\n<INCOMING>"); debug_dump_buf(buf->dptr, buf->len); /* decode the packet */ mac_parse_hdr(buf, &hdr); debug_dump_mac_hdr(&hdr); /* * check if an ack is needed. if so, then generate * an ack and queue it for transmission. the frm * pending bit will be set for any frame coming from * an address that has an indirect frame for it. this * is against the spec, but it will speed up the ack * transmission. * NOTE: the ack response section may change due to the * tight ack timing requirements. */ if (hdr.mac_frm_ctrl.ack_req) { BUF_ALLOC(buf_out, TX); DBG_PRINT("MAC: ACK Required.\n"); frm_pend = mac_indir_frm_pend(&hdr.src_addr); mac_gen_ack(buf_out, frm_pend, hdr.dsn); mac_out(buf_out, false, hdr.dsn, 0); } /* * process accordingly. if a scan is in progress, * all frames except for beacon frames will be * discarded. */ switch(hdr.mac_frm_ctrl.frame_type) { case MAC_COMMAND: if (pcb->mac_state != MLME_SCAN) { /* * need to handle the case that this is an indirect * transfer, which means that we need to stop the * poll timer and send a status to the poll confirm. */ if ((pcb->mac_state == MLME_DATA_REQ) && (hdr.src_addr.mode == SHORT_ADDR) && (hdr.src_addr.short_addr == pib->coord_addr.short_addr)) { ctimer_stop(&pcb->mlme_tmr); mac_poll_conf(MAC_SUCCESS); } mac_parse_cmd(buf, &cmd); mac_cmd_handler(&cmd, &hdr); } buf_free(buf); break; case MAC_BEACON: /* discard the beacon if we're not doing a scan */ if (pcb->mac_state == MLME_SCAN) { mac_parse_beacon(buf, &hdr); mac_beacon_notify_ind(buf, mac_scan_descr_find_addr(&hdr.src_addr)); } buf_free(buf); break; case MAC_ACK: mac_retry_ack_handler(hdr.dsn); /* * we need to do some special ops depending on the * state we're in if we get an ACK. */ if (pcb->mac_state == MLME_ASSOC_REQ) { if (pcb->assoc_req_dsn == hdr.dsn) ctimer_set(&pcb->mlme_tmr, pib->resp_wait_time, mac_poll_req, NULL); } else if (pcb->mac_state == MLME_DATA_REQ) { if (hdr.mac_frm_ctrl.frame_pending) ctimer_set(&pcb->mlme_tmr, aMacMaxFrameTotalWaitTime, mac_poll_timeout, NULL); } buf_free(buf); break; case MAC_DATA: if (pcb->mac_state != MLME_SCAN) { /* * need to handle the case that this is an indirect * transfer, which means that we need to stop the poll * timer and send a status to the poll confirm. */ if ((pcb->mac_state == MLME_DATA_REQ) && (hdr.src_addr.mode == SHORT_ADDR) && (hdr.src_addr.short_addr == pib->coord_addr.short_addr)) { ctimer_stop(&pcb->mlme_tmr); mac_poll_conf(MAC_SUCCESS); } mac_data_ind(buf, &hdr); } else buf_free(buf); break; default: /* TODO: Add a statistic here to capture an error'd rx */ break; } } /* * there's a possibility that more than one frame is in the * buffer. if they came in before this function gets executed. * So process until the queue is empty. */ if (!mac_queue_is_empty()) { while (process_post(&mac_process, event_mac_rx, NULL) != PROCESS_ERR_OK) { ; } } } }