static int icmp_hnd_dest_unreach(const struct icmphdr *icmph, const struct icmpbody_dest_unreach *dest_unreach, struct sk_buff *skb) { size_t len; switch (icmph->code) { default: skb_free(skb); return 0; /* error: bad code */ case ICMP_NET_UNREACH: case ICMP_HOST_UNREACH: case ICMP_PROT_UNREACH: case ICMP_PORT_UNREACH: case ICMP_FRAG_NEEDED: case ICMP_SR_FAILED: break; } len = ip_data_length(ip_hdr(skb)); if (sizeof *icmph + sizeof *dest_unreach > len) { skb_free(skb); return 0; /* error: invalid length */ } len -= sizeof *icmph + sizeof *dest_unreach; return icmp_notify_an_error(icmph, &dest_unreach->msg[0], len, icmph->code == ICMP_FRAG_NEEDED ? ntohs(dest_unreach->mtu) : 0, icmph->code == ICMP_FRAG_NEEDED, skb); }
static int icmp_hnd_param_prob(const struct icmphdr *icmph, const struct icmpbody_param_prob *param_prob, struct sk_buff *skb) { size_t len; switch (icmph->code) { default: skb_free(skb); return 0; /* error: bad code */ case ICMP_PTR_ERROR: case ICMP_PTR_UNUSED: break; } len = ip_data_length(ip_hdr(skb)); if (sizeof *icmph + sizeof *param_prob > len) { skb_free(skb); return 0; /* error: invalid length */ } len -= sizeof *icmph + sizeof *param_prob; return icmp_notify_an_error(icmph, ¶m_prob->msg[0], len, icmph->code == ICMP_PTR_ERROR ? param_prob->ptr : 0, (icmph->code == ICMP_PTR_ERROR) && (param_prob->ptr < IP_HEADER_SIZE( (const struct iphdr *)¶m_prob->msg[0])), skb); }
static int icmp_hnd_timestamp_request(const struct icmphdr *icmph, const struct icmpbody_timestamp *tstamp_req, struct sk_buff *skb) { uint32_t msec_since_12am; struct icmpbody_timestamp *tstamp_rep; if (icmph->code != 0) { skb_free(skb); return 0; /* error: bad code */ } if (sizeof *icmph + sizeof *tstamp_req != ip_data_length(ip_hdr(skb))) { skb_free(skb); return 0; /* error: invalid length */ } msec_since_12am = (ktime_get_ns() / NSEC_PER_MSEC) % ( SEC_PER_DAY * MSEC_PER_SEC); tstamp_rep = &icmp_hdr(skb)->body[0].timestamp; tstamp_rep->orig = tstamp_req->trans; tstamp_rep->recv = tstamp_rep->trans = htonl(msec_since_12am); return icmp_send(ICMP_TIMESTAMP_REPLY, 0, tstamp_rep, sizeof *tstamp_rep, skb); }
static int icmp_send(uint8_t type, uint8_t code, const void *body, size_t body_sz, struct sk_buff *skb) { int ret; size_t size; if (ip_out_ops == NULL) { skb_free(skb); return -ENOSYS; /* error: not implemented */ } size = sizeof *icmp_hdr(skb) + body_sz; assert(ip_out_ops->make_pack != NULL); ret = ip_out_ops->make_pack(NULL, NULL, &size, &skb); if (ret != 0) { skb_free(skb); return ret; /* error: see ret */ } else if (size != sizeof *icmp_hdr(skb) + body_sz) { skb_free(skb); return -EMSGSIZE; /* error: message is too big */ } icmp_build(icmp_hdr(skb), type, code, body, body_sz); icmp_set_check_field(icmp_hdr(skb), ip_hdr(skb)); assert(ip_out_ops->snd_pack != NULL); return ip_out_ops->snd_pack(skb); }
static int icmp_hnd_echo_request(const struct icmphdr *icmph, const struct icmpbody_echo *echo_req, struct sk_buff *skb) { size_t len; struct icmpbody_echo *echo_rep; if (icmph->code != 0) { log_error("bad code 0x%x", icmph->code); skb_free(skb); return 0; /* error: bad code */ } len = ip_data_length(ip_hdr(skb)); if (sizeof *icmph + sizeof *echo_req > len) { log_error("invalid length %zu", len); skb_free(skb); return 0; /* error: invalid length */ } len -= sizeof *icmph + sizeof *echo_req; echo_rep = &icmp_hdr(skb)->body[0].echo; return icmp_send(ICMP_ECHO_REPLY, 0, echo_rep, sizeof *echo_rep + len, skb); }
static int icmp_rcv(struct sk_buff *skb) { struct icmphdr *icmph; uint16_t old_check; log_debug("%p len %zu", skb, skb->len); if (sizeof *icmph > ip_data_length(ip_hdr(skb))) { log_error("invalid length (%zu > %zu)", sizeof *icmph, ip_data_length(ip_hdr(skb))); skb_free(skb); return 0; /* error: invalid length */ } if (NULL == skb_declone(skb)) { log_error("can't declone data"); skb_free(skb); return -ENOMEM; /* error: can't declone data */ } icmph = icmp_hdr(skb); assert(icmph != NULL); old_check = icmph->check; icmp_set_check_field(icmph, ip_hdr(skb)); if (old_check != icmph->check) { log_error("bad checksum"); skb_free(skb); return 0; /* error: bad checksum */ } switch (icmph->type) { default: log_error("icmp_rcv: unknown type: %hhu\n", icmph->type); break; /* error: unknown type */ case ICMP_ECHO_REPLY: case ICMP_TIMESTAMP_REPLY: case ICMP_INFO_REPLY: break; case ICMP_DEST_UNREACH: return icmp_hnd_dest_unreach(icmph, &icmph->body[0].dest_unreach, skb); case ICMP_SOURCE_QUENCH: return icmp_hnd_source_quench(icmph, &icmph->body[0].source_quench, skb); case ICMP_REDIRECT: case ICMP_TIME_EXCEED: case ICMP_INFO_REQUEST: break; /* error: not implemented */ case ICMP_ECHO_REQUEST: return icmp_hnd_echo_request(icmph, &icmph->body[0].echo, skb); case ICMP_PARAM_PROB: return icmp_hnd_param_prob(icmph, &icmph->body[0].param_prob, skb); case ICMP_TIMESTAMP_REQUEST: return icmp_hnd_timestamp_request(icmph, &icmph->body[0].timestamp, skb); } skb_free(skb); return 0; }
struct skbuff * ip_frag(struct net_device *dev, struct skbuff *skb) { __u8 frag_num = 0; __u16 tot_len = ntohs(skb->nh.iph->tot_len); __u8 mtu = dev->mtu; __u8 half_mtu = (mtu+1)/2; frag_num = (tot_len - IPHDR_LEN + half_mtu)/(mtu - IPHDR_LEN - ETH_HLEN);/*计算分片的个数*/ __u16 i = 0; struct skbuff *skb_h = NULL,*skb_t = NULL,*skb_c = NULL; for(i = 0,skb->tail = skb->head; i<frag_num;i++) { if(i ==0){ /*第一个分片*/ skb_t = skb_alloc(mtu); /*申请内存*/ skb_t->phy.raw = skb_put(skb_t, ETH_HLEN); /*物理层*/ skb_t->nh.raw = skb_put(skb_t, IPHDR_LEN); /*网络层*/ memcpy(skb_t->head, skb->head, mtu); /*拷贝数据*/ skb_put(skb,mtu); /*增加数据长度len值*/ skb_t->nh.iph->frag_off = htons(0x2000); /*设置偏移标记值*/ skb_t->nh.iph->tot_len = htons(mtu-ETH_HLEN); /*设置IP头部总长度*/ skb_t->nh.iph->check = 0; /*设置校验和为0*/ skb_t->nh.iph->check = SIP_Chksum(skb_t->nh.raw, IPHDR_LEN);/*计算校验和*/ skb_h = skb_c =skb_t; /*头部分片指针设置*/ }else if(i==frag_num -1){ /*最后一个分片*/ skb_t = skb_alloc(mtu); /*申请内存*/ skb_t->phy.raw = skb_put(skb_t, ETH_HLEN); /*物理层*/ skb_t->nh.raw = skb_put(skb_t, IPHDR_LEN); /*网络层*/ memcpy(skb_t->head, skb->head, ETH_HLEN + IPHDR_LEN); /*拷贝数据*/ memcpy(skb_t->head + ETH_HLEN + IPHDR_LEN, skb->tail, skb->end - skb->tail);/*增加数据长度len值*/ skb_t->nh.iph->frag_off = htons(i*(mtu - ETH_HLEN - IPHDR_LEN) + IPHDR_LEN);/*设置偏移标记值*/ skb_t->nh.iph->tot_len = htons(skb->end - skb->tail + IPHDR_LEN);/*设置IP头部总长度*/ skb_t->nh.iph->check = 0; /*设置校验和为0*/ skb_t->nh.iph->check = SIP_Chksum(skb_t->nh.raw, IPHDR_LEN);/*计算校验和*/ skb_c->next=skb_t; /*挂接此分片*/ }else{ skb_t = skb_alloc(mtu); skb_t->phy.raw = skb_put(skb_t, ETH_HLEN); skb_t->nh.raw = skb_put(skb_t, IPHDR_LEN); memcpy(skb_t->head, skb->head, ETH_HLEN + IPHDR_LEN); memcpy(skb_t->head + ETH_HLEN + IPHDR_LEN, skb->tail, mtu - ETH_HLEN - IPHDR_LEN); skb_put(skb_t, mtu - ETH_HLEN - IPHDR_LEN); skb_t->nh.iph->frag_off = htons((i*(mtu - ETH_HLEN - IPHDR_LEN) + IPHDR_LEN)|0x2000); skb_t->nh.iph->tot_len = htons(mtu - ETH_HLEN); skb_t->nh.iph->check = 0; skb_t->nh.iph->check = SIP_Chksum(skb_t->nh.raw, IPHDR_LEN); skb_c->next=skb_t; skb_c = skb_t; } skb_t->ip_summed = 1; /*已经进行了IP校验和计算*/ } skb_free(skb); /*释放原来的网络数据*/ return skb_h; /*返回分片的头部指针*/ }
static int send_request(struct net_device *dev, uint16_t pro, uint8_t pln, const void *spa, const void *tpa) { int ret; struct sk_buff *skb; struct net_header_info hdr_info; skb = skb_alloc(dev->hdr_len + ARP_CALC_HEADER_SIZE(dev->addr_len, pln)); if (skb == NULL) { return -ENOMEM; } skb->dev = dev; skb->nh.raw = skb->mac.raw + dev->hdr_len; hdr_info.type = ETH_P_ARP; hdr_info.src_hw = &dev->dev_addr[0]; hdr_info.dst_hw = &dev->broadcast[0]; assert(dev->ops != NULL); assert(dev->ops->build_hdr != NULL); ret = dev->ops->build_hdr(skb, &hdr_info); if (ret != 0) { skb_free(skb); return ret; } arp_build(arp_hdr(skb), dev->type, pro, dev->addr_len, pln, ARP_OP_REQUEST, &dev->dev_addr[0], spa, &dev->broadcast[0], tpa); return net_tx(skb, NULL); }
int sock_dgram_recvmsg(struct sock *sk, struct msghdr *msg, int flags) { const unsigned long timeout = sock_calc_timeout(sk); struct sk_buff *skb; int err, nrecv; assert(sk != NULL); skb = sock_get_skb(sk, timeout, &err); if (!skb) { assert(err); return err; } nrecv = skb_iovec_buf(msg->msg_iov, msg->msg_iovlen, skb->p_data, skb->p_data_end - skb->p_data); sk->rx_data_len -= skb->p_data_end - skb->p_data; assert(sk->p_ops != NULL); if (sk->p_ops->fillmsg && msg->msg_name) { sk->p_ops->fillmsg(sk, msg, skb); } skb_free(skb); return nrecv; }
main(int argc, char **argv) { struct uld *uld; struct sk_buff *skb; int i; pcap_t *p; pcap_dumper_t *pd; struct pcap_pkthdr ph; char *ifname; ifname = NULL; if (argc == 2) { ifname = argv[1]; } uld = uld_open(ifname, 0, 0, 0, 0); if (uld == NULL) exit(1); p = pcap_open_dead(DLT_EN10MB, 65535); if (!p) fprintf(stderr, "pcap_open_dead failed\n"); pd = pcap_dump_open(p, "-"); if (!pd) fprintf(stderr, "pcap_dump_open failed\n"); for(;;) { skb = uld_skb_read(uld, 1); if (skb == NULL) continue; ph.ts.tv_sec = skb->tstamp.tv_sec; ph.ts.tv_usec = skb->tstamp.tv_nsec/1000; ph.len = ph.caplen = skb->len; pcap_dump((void *)pd, &ph, skb->data); pcap_dump_flush(pd); skb_free(skb); } }
static int icmp_notify_an_error(const struct icmphdr *icmph, const void *msg, size_t msg_sz, uint16_t extra_info, int only_raw, struct sk_buff *skb) { const struct iphdr *emb_iph; uint32_t error_info; emb_iph = msg; assert(emb_iph != NULL); if ((msg_sz < IP_MIN_HEADER_SIZE) || (IP_HEADER_SIZE(emb_iph) < IP_MIN_HEADER_SIZE) || (ntohs(emb_iph->tot_len) < IP_HEADER_SIZE(emb_iph)) || (msg_sz < IP_HEADER_SIZE(emb_iph))) { log_error("invalid length"); skb_free(skb); return 0; /* error: invalid length */ } if (!ip_check_version(emb_iph)) { log_error("not ipv4"); skb_free(skb); return 0; /* error: not ipv4 */ } if (ip_hdr(skb)->daddr != emb_iph->saddr) { log_error("not my embedded packet"); skb_free(skb); return 0; /* error: not my embedded packet */ } error_info = extra_info << 16 | icmph->code << 8 | icmph->type; raw_err(skb, error_info); if (!only_raw) { const struct net_proto *nproto; nproto = net_proto_lookup(ETH_P_IP, emb_iph->proto); if (nproto != NULL) { assert(nproto->handle_error != NULL); nproto->handle_error(skb, error_info); } } return 0; }
static int icmp_hnd_source_quench(const struct icmphdr *icmph, const struct icmpbody_source_quench *source_quench, struct sk_buff *skb) { size_t len; if (icmph->code != 0) { skb_free(skb); return 0; /* error: bad code */ } len = ip_data_length(ip_hdr(skb)); if (sizeof *icmph + sizeof *source_quench > len) { skb_free(skb); return 0; /* error: invalid length */ } len -= sizeof *icmph + sizeof *source_quench; return icmp_notify_an_error(icmph, &source_quench->msg[0], len, 0, 0, skb); }
static int udp_sendmsg(struct sock *sk, struct msghdr *msg, int flags) { int ret; size_t data_len, total_len, actual_len; struct sk_buff *skb; const struct sockaddr_in *to; const struct sockaddr *sockaddr; assert(sk); assert(sk->o_ops); assert(sk->o_ops->make_pack); assert(msg); assert(msg->msg_iov); assert(msg->msg_iov->iov_base); data_len = msg->msg_iov->iov_len; total_len = actual_len = UDP_HEADER_SIZE + data_len; skb = NULL; sockaddr = (const struct sockaddr *)msg->msg_name; ret = sk->o_ops->make_pack(sk, sockaddr, &actual_len, &skb); if (ret != 0) { return ret; } #if 0 if (actual_len < total_len) { skb_free(skb); return -EMSGSIZE; } #endif if (msg->msg_name != NULL) { to = (const struct sockaddr_in *)msg->msg_name; } else { to = (const struct sockaddr_in *)&to_inet_sock(sk)->dst_in; } assert(skb); assert(skb->h.uh); udp_build(skb->h.uh, sock_inet_get_src_port(sk), to->sin_port, total_len); memcpy(skb->h.uh + 1, msg->msg_iov->iov_base, data_len); udp4_set_check_field(skb->h.uh, skb->nh.iph); assert(sk->o_ops->snd_pack); ret = sk->o_ops->snd_pack(skb); if (0 > ret) { return ret; } return data_len; }
static int ip6_rcv(struct sk_buff *skb, struct net_device *dev) { ip6hdr_t *ip6h = ip6_hdr(skb); const struct net_proto *nproto; if (ip6h->version != 6) { dev->stats.rx_err++; skb_free(skb); return 0; /* error: invalid hdr */ } if (skb->dev->hdr_len + IP6_HEADER_SIZE + ntohs(ip6h->payload_len) > skb->len) { dev->stats.rx_length_errors++; skb_free(skb); return 0; /* error: invalid length */ } /* Check recipiant */ assert(skb->dev != NULL); assert(inetdev_get_by_dev(skb->dev) != NULL); if (0 != memcmp(&inetdev_get_by_dev(skb->dev)->ifa6_address, &skb->nh.ip6h->daddr, sizeof(struct in6_addr))) { // skb_free(skb); // return 0; /* error: not for us */ } /* Setup transport layer header */ skb->h.raw = skb->nh.raw + IP6_HEADER_SIZE; nproto = net_proto_lookup(ETH_P_IPV6, ip6h->nexthdr); if (nproto != NULL) { return nproto->handle(skb); } // printk("ipv6 packet accepted, %#x\n", ip6h->nexthdr); skb_free(skb); return 0; /* error: nobody wants this packet */ }
static int mipsnet_xmit(struct net_device *dev, struct sk_buff *skb) { struct mipsnet_regs *regs; int i; uint8_t *pdata; show_packet(skb->mac.raw, skb->len, "xmit"); regs = (struct mipsnet_regs *)dev->base_addr; pdata = skb->mac.raw; out32(skb->len, ®s->txDataCount); for(i = 0; i < skb->len; i++) { out32((uint32_t)*pdata, ®s->txDataBuffer); pdata++; } skb_free(skb); return 0; }
//TODO this function call from stack (may be place it to other file) void sock_rcv(struct sock *sk, struct sk_buff *skb, unsigned char *p_data, size_t size) { if ((sk == NULL) || (skb == NULL) || (p_data == NULL)) { return; /* error: invalid argument */ } if (sk->shutdown_flag & (SHUT_RD + 1)) { skb_free(skb); return; /* error: socket is down */ } skb->p_data = p_data; skb->p_data_end = p_data + size; skb_queue_push(&sk->rx_queue, skb); sk->rx_data_len += size; sock_notify(sk, POLLIN); }
ssize_t sip_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { struct sip_socket *socket; struct skbuff *skb; struct sockaddr_in *f = (struct sockaddr_in *)from; int len_copy = 0; socket = get_socket(s); /*获得socket类型映射*/ if (!socket) return -1; if(!socket->lastdata){ /*lastdata中没有有剩余数据*/ socket->lastdata =(struct skbuff*) SIP_SockRecv(socket->sock);/*接收数据*/ socket->lastoffset = 0; /*偏离量为0*/ } skb = socket->lastdata; /*skbuff指针*/ /*填充用户出入参数*/ *fromlen = sizeof(struct sockaddr_in); /*地址结构长度*/ f->sin_family = AF_INET; /*地址类型*/ f->sin_addr.s_addr = skb->nh.iph->saddr; /*来源IP地址*/ f->sin_port = skb->th.udph->source; /*来源端口*/ len_copy = skb->len - socket->lastoffset; /*计算lastdata中剩余的数据*/ if(len > len_copy) { /*用户缓冲区可以放下所有数据*/ memcpy(buf, /*全部拷贝到用户缓冲区*/ skb->data+socket->lastoffset, len_copy); skb_free(skb); /*释放此结构*/ socket->lastdata = NULL; /*清空网络数据结构指针*/ socket->lastoffset = 0; /*偏移量重新设置为0*/ }else{ /*用户缓冲区放不下整个数据*/ len_copy = len; /*仅拷贝缓冲区大小的数据*/ memcpy(buf, /*拷贝*/ skb+socket->lastoffset, len_copy); socket->lastoffset += len_copy; /*偏移量增加*/ } return len_copy; /*返回拷贝的值*/ }
void arp_queue_try_insert(struct sk_buff *skb) { if (skb->arp_try_times == 0) { printf("arp request too many times\n"); goto drop; } if (skb_queue_len(&arp_queue) > MAX_SKB_QUEUE_SIZE) { printf("arp queue is full\n"); goto drop; } skb->arp_try_times--; skb_queue_tail(&arp_queue, skb); return; drop: skb_free(skb); }
int sock_stream_recvmsg(struct sock *sk, struct msghdr *msg, int flags) { void *buf, *bufend, *bp; struct sk_buff *skb; unsigned long timeout; int err; assert(msg->msg_iovlen == 1); buf = msg->msg_iov->iov_base; bufend = buf + msg->msg_iov->iov_len; /* TODO I think here should be a check if stream connection is closed forcibly. * See "RETURN VALUE" http://pubs.opengroup.org/onlinepubs/009695399/functions/recvfrom.html * --Alexander */ timeout = sock_calc_timeout(sk); bp = buf; err = 0; while (bp < bufend) { size_t len; skb = sock_get_skb(sk, timeout, &err); if (!skb) { break; } len = skb_read(skb, bp, bufend - bp); bp += len; if (skb->p_data == skb->p_data_end) { skb_free(skb); } timeout = 0; } if (bp == buf) { return err; } sk->rx_data_len -= bp - buf; return bp - buf; }
int sip_close(int s) { struct sip_socket *socket; socket = get_socket(s); /*获得socket类型映射*/ if (!socket) /*失败*/ { return -1; } SIP_SockDelete(socket->sock); /*释放sock结构*/ if (socket->lastdata) { skb_free(socket->lastdata); /*释放socket上挂接的网络数据*/ } socket->lastdata = NULL; /*清空socket结构的网络数据*/ socket->sock = NULL; /*清空sock指针*/ return 0; }
static int udp_rcv(struct sk_buff *skb) { struct sock *sk; assert(skb != NULL); assert(ip_check_version(ip_hdr(skb)) || ip6_check_version(ip6_hdr(skb))); /* Check CRC */ if (MODOPS_VERIFY_CHKSUM) { uint16_t old_check; old_check = skb->h.uh->check; udp_set_check_field(skb->h.uh, skb->nh.raw); if (old_check != skb->h.uh->check) { return 0; /* error: bad checksum */ } } sk = sock_lookup(NULL, udp_sock_ops, ip_check_version(ip_hdr(skb)) ? udp4_rcv_tester : udp6_rcv_tester, skb); if (sk != NULL) { if (ip_check_version(ip_hdr(skb)) ? udp4_accept_dst(sk, skb) : udp6_accept_dst(sk, skb)) { sock_rcv(sk, skb, skb->h.raw + UDP_HEADER_SIZE, udp_data_length(udp_hdr(skb))); } else { skb_free(skb); } } else { icmp_discard(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH); } return 0; }
void arp_rcv(struct sk_buff *skb) { struct arppkt *ap; struct ethhdr *eh; unsigned int tip, sip; struct arptab *h; int hl; struct net_device *nic; hl = sizeof(struct ethhdr); skb->len -= hl; ap = (struct arppkt *) skb->data; skb->nh.arph = (struct arphdr *) skb->data; eh = (struct ethhdr *) (skb->data - hl); nic = skb->nic; /* skb->data += sizeof(struct arphdr); */ printf("--- ARP: packet received\n"); if (ap->ar_hrd != htons(ARPHRD_ETHER) || ap->ar_pro != htons(ETHERTYPE_IP) || ap->ar_hln != ETH_ALEN || ap->ar_pln != 4) goto bad; switch (ntohs(ap->ar_op)) { case ARPOP_REQUEST: tip = *(unsigned int *)ap->__ar_tip; sip = *(unsigned int *)ap->__ar_sip; if (tip != skb->nic->ip) goto drop; ap->ar_op = htons(ARPOP_REPLY); *(unsigned int *)ap->__ar_sip = skb->nic->ip; *(unsigned int *)ap->__ar_tip = sip; memcpy(ap->__ar_sha, skb->nic->dev_addr, ETH_ALEN); memcpy(ap->__ar_tha, eh->h_source, ETH_ALEN); memcpy(eh->h_dest, eh->h_source, ETH_ALEN); memcpy(eh->h_source, skb->nic->dev_addr, ETH_ALEN); skb->len +=14; skb->ip_summed = 0; skb->protocol = ETHERTYPE_ARP; dev_send(skb); goto reused; break; case ARPOP_REPLY: sip = *(unsigned int *)ap->__ar_sip; tip = *(unsigned int *)ap->__ar_tip; pthread_spin_lock(&arp_lock); h = &arp_table[arp_hash(sip)]; if (/* h->ip == sip && */ nic->ip == tip) { if (ap->__ar_sha[0] & 1) /* why? */ goto unlock_bad; memcpy(h->mac, ap->__ar_sha, ETH_ALEN); /* if (h->hold && (tv.tv_sec - h->time > ARP_MAX_HOLD)) */ /* { */ /* skb_free(h->hold); */ /* h->hold = NULL; */ /* } */ h->time = get_second(); if (h->status == ARP_STATUS_REQUEST) { h->status = ARP_STATUS_OK; pthread_spin_unlock(&arp_lock); pthread_cond_signal(&arp_queue_check); } else { /* received broadcast reply who was not requested */ h->status = ARP_STATUS_OK; pthread_spin_unlock(&arp_lock); } /* if ((skb = h->hold)) */ /* { */ /* h->hold = NULL; */ /* memcpy(eh->h_dest, h->mac, ETH_ALEN); */ /* pthread_spin_unlock(&arp_lock); */ /* /\* fragmentation? *\/ */ /* dev_send(skb); */ /* } */ /* else */ /* pthread_spin_unlock(&arp_lock); */ } else { goto unlock_bad; } break; default: goto bad; } reused: return; bad: printf("arp: packet invalid\n"); drop: skb_free(skb); return; unlock_bad: pthread_spin_unlock(&arp_lock); skb_free(skb); }
static int ip_rcv(struct sk_buff *skb, struct net_device *dev) { net_device_stats_t *stats = &dev->stats; const struct net_proto *nproto; iphdr_t *iph = ip_hdr(skb); __u16 old_check; size_t ip_len; int optlen; sk_buff_t *complete_skb; /** * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum. * Is the datagram acceptable? * 1. Length at least the size of an ip header * 2. Version of 4 * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums] * 4. Doesn't have a bogus length */ if (skb->len < dev->hdr_len + IP_MIN_HEADER_SIZE || IP_HEADER_SIZE(iph) < IP_MIN_HEADER_SIZE || skb->len < dev->hdr_len + IP_HEADER_SIZE(iph)) { DBG(printk("ip_rcv: invalid IPv4 header length\n")); stats->rx_length_errors++; skb_free(skb); return 0; /* error: invalid header length */ } if (iph->version != 4) { DBG(printk("ip_rcv: invalid IPv4 version\n")); stats->rx_err++; skb_free(skb); return 0; /* error: not ipv4 */ } old_check = iph->check; ip_set_check_field(iph); if (old_check != iph->check) { DBG(printk("ip_rcv: invalid checksum %hx(%hx)\n", ntohs(old_check), ntohs(iph->check))); stats->rx_crc_errors++; skb_free(skb); return 0; /* error: invalid crc */ } ip_len = ntohs(iph->tot_len); if (ip_len < IP_HEADER_SIZE(iph) || skb->len < dev->hdr_len + ip_len) { DBG(printk("ip_rcv: invalid IPv4 length\n")); stats->rx_length_errors++; skb_free(skb); return 0; /* error: invalid length */ } /* Setup transport layer (L4) header */ skb->h.raw = skb->nh.raw + IP_HEADER_SIZE(iph); /* Validating */ if (0 != nf_test_skb(NF_CHAIN_INPUT, NF_TARGET_ACCEPT, skb)) { DBG(printk("ip_rcv: dropped by input netfilter\n")); stats->rx_dropped++; skb_free(skb); return 0; /* error: dropped */ } /* Forwarding */ assert(skb->dev); assert(inetdev_get_by_dev(skb->dev)); if (inetdev_get_by_dev(skb->dev)->ifa_address != 0) { /** * FIXME * This check needed for BOOTP protocol * disable forwarding if interface is not set yet */ /** * Check the destination address, and if it doesn't match * any of own addresses, retransmit packet according to the routing table. */ if (!ip_is_local(iph->daddr, IP_LOCAL_BROADCAST)) { if (0 != nf_test_skb(NF_CHAIN_FORWARD, NF_TARGET_ACCEPT, skb)) { DBG(printk("ip_rcv: dropped by forward netfilter\n")); stats->rx_dropped++; skb_free(skb); return 0; /* error: dropped */ } return ip_forward(skb); } } memset(skb->cb, 0, sizeof(skb->cb)); optlen = IP_HEADER_SIZE(iph) - IP_MIN_HEADER_SIZE; if (optlen > 0) { /* NOTE : maybe it'd be better to copy skb here, * 'cause options may cause modifications * but smart people who wrote linux kernel * say that this is extremely rarely needed */ ip_options_t *opts = (ip_options_t*)(skb->cb); memset(skb->cb, 0, sizeof(skb->cb)); opts->optlen = optlen; if (ip_options_compile(skb, opts)) { DBG(printk("ip_rcv: invalid options\n")); stats->rx_err++; skb_free(skb); return 0; /* error: bad ops */ } if (ip_options_handle_srr(skb)) { DBG(printk("ip_rcv: can't handle options\n")); stats->tx_err++; skb_free(skb); return 0; /* error: can't handle ops */ } } /* It's very useful for us to have complete packet even for forwarding * (we may apply any filter, we may perform NAT etc), * but it'll break routing if different parts of a fragmented * packet will use different routes. So they can't be assembled. * See RFC 1812 for details */ if (ntohs(skb->nh.iph->frag_off) & (IP_MF | IP_OFFSET)) { if ((complete_skb = ip_defrag(skb)) == NULL) { if (skb == NULL) { return 0; /* error: */ } return 0; } else { skb = complete_skb; iph = ip_hdr(complete_skb); } } /* When a packet is received, it is passed to any raw sockets * which have been bound to its protocol or to socket with concrete protocol */ raw_rcv(skb); nproto = net_proto_lookup(ETH_P_IP, iph->proto); if (nproto != NULL) { return nproto->handle(skb); } DBG(printk("ip_rcv: unknown protocol\n")); skb_free(skb); return 0; /* error: nobody wants this packet */ }
int icmp_discard(struct sk_buff *skb, uint8_t type, uint8_t code, ...) { struct { union { struct icmpbody_dest_unreach dest_unreach; struct icmpbody_source_quench source_quench; struct icmpbody_redirect redirect; struct icmpbody_time_exceed time_exceed; struct icmpbody_param_prob param_prob; } __attribute__((packed)); char __body_msg_storage[ICMP_DISCARD_MAX_SIZE]; } __attribute__((packed)) body; va_list extra; uint8_t *body_msg; size_t body_msg_sz; if (!(ip_is_local(ip_hdr(skb)->saddr, 0) || ip_is_local(ip_hdr(skb)->daddr, 0)) || (ip_hdr(skb)->frag_off & htons(IP_OFFSET)) || (ip_data_length(ip_hdr(skb)) < ICMP_DISCARD_MIN_SIZE) || (ip_hdr(skb)->proto != IPPROTO_ICMP) || (skb->h.raw = skb->nh.raw + IP_HEADER_SIZE(ip_hdr(skb)), ICMP_TYPE_ERROR(icmp_hdr(skb)->type))) { skb_free(skb); return 0; /* error: inappropriate packet */ } switch (type) { default: assertf(0, "bad type for discard"); body_msg = (uint8_t *)&body.__body_msg_storage[0]; break; /* error: bad type for discard */ case ICMP_DEST_UNREACH: assertf(code < __ICMP_DEST_UNREACH_MAX, "incorrect code for type"); va_start(extra, code); body.dest_unreach.zero = 0; body.dest_unreach.mtu = code != ICMP_FRAG_NEEDED ? 0 : htons((uint16_t)va_arg(extra, int)); va_end(extra); body_msg = &body.dest_unreach.msg[0]; break; case ICMP_SOURCE_QUENCH: assertf(code == 0, "incorrect code for type"); body.source_quench.zero = 0; body_msg = &body.source_quench.msg[0]; break; case ICMP_REDIRECT: assertf(code < __ICMP_REDIRECT_MAX, "incorrect code for type"); va_start(extra, code); memcpy(&body.redirect.gateway, va_arg(extra, struct in_addr *), sizeof body.redirect.gateway); va_end(extra); body_msg = &body.redirect.msg[0]; break; case ICMP_TIME_EXCEED: assertf(code < __ICMP_TIME_EXCEED_MAX, "incorrect code for type"); body.time_exceed.zero = 0; body_msg = &body.time_exceed.msg[0]; break; case ICMP_PARAM_PROB: assertf(code < __ICMP_PARAM_PROB_MAX, "incorrect code for type"); va_start(extra, code); body.param_prob.ptr = code != ICMP_PTR_ERROR ? 0 : (uint8_t)va_arg(extra, int); body.param_prob.zero1 = body.param_prob.zero2 = 0; va_end(extra); body_msg = &body.param_prob.msg[0]; break; } body_msg_sz = min(ip_data_length(ip_hdr(skb)), sizeof body.__body_msg_storage); memcpy(body_msg, ip_hdr(skb), body_msg_sz); if (NULL == skb_declone(skb)) { skb_free(skb); return -ENOMEM; /* error: can't declone data */ } return icmp_send(type, code, &body, sizeof body - sizeof body.__body_msg_storage + body_msg_sz, skb); }
int net_tx(struct sk_buff *skb, struct net_header_info *hdr_info) { int ret; size_t skb_len; struct net_device *dev; assert(skb != NULL); dev = skb->dev; assert(dev != NULL); if (!(dev->flags & IFF_UP)) { log_error("net_tx: device is down\n"); skb_free(skb); return -ENETDOWN; } if (0 != nt_build_hdr(skb, hdr_info, dev)) { assert(hdr_info != NULL); ret = neighbour_send_after_resolve(hdr_info->type, hdr_info->dst_p, hdr_info->p_len, dev, skb); if (ret != 0) log_debug("net_tx: neighbour_send_after_resolve = %d\n", ret); return ret; } skb_len = skb->len; log_debug("net_tx: skb %p[%zu] type %#.6hx\n", skb, skb->len, ntohs(skb->mac.ethh->h_proto)); /* * http://www.linuxfoundation.org/collaborate/workgroups/networking/kernel_flow#Transmission_path * Search for: * dev_hard_start_xmit() calls the hard_start_xmit virtual method for the net_device. * But first, it calls dev_queue_xmit_nit(), which checks if a packet handler has been registered * for the ETH_P_ALL protocol. This is used for tcpdump. */ sock_packet_add(skb, htons(ETH_P_ALL)); skb = net_encrypt(skb); if (skb == NULL) { return 0; } assert(dev->drv_ops != NULL); assert(dev->drv_ops->xmit != NULL); ret = dev->drv_ops->xmit(dev, skb); if (ret != 0) { log_debug("net_tx: xmit = %d\n", ret); skb_free(skb); dev->stats.tx_err++; return ret; } dev->stats.tx_packets++; dev->stats.tx_bytes += skb_len; return 0; }
#include "sip.h" inline int IP_IS_BROADCAST(struct net_device *dev, __be32 ip) { int retval = 1; if((ip == IP_ADDR_ANY_VALUE) /*IP地址为本地任意IP地址*/ ||(~ip == IP_ADDR_ANY_VALUE)) /*或者为按位取反IP地址*/ { DBGPRINT(DBG_LEVEL_NOTES, "IP is ANY ip\n"); retval = 1; /*是广播地址*/ goto EXITin_addr_isbroadcast; /*退出*/ }else if(ip == dev->ip_host.s_addr) { /*IP地址为本地地址*/ DBGPRINT(DBG_LEVEL_NOTES, "IP is local ip\n"); retval = 0; /*不是广播地址*/ goto EXITin_addr_isbroadcast; /*退出*/ }else if(((ip&dev->ip_netmask.s_addr) /*IP地址为本子网内地址*/ == (dev->ip_host.s_addr &dev->ip_netmask.s_addr)) && ((ip & ~dev->ip_netmask.s_addr) /*与广播地址同网段*/ ==(IP_ADDR_BROADCAST_VALUE & ~dev->ip_netmask.s_addr))){ DBGPRINT(DBG_LEVEL_NOTES, "IP is ANY ip\n"); retval =1; /*是广播地址*/ goto EXITin_addr_isbroadcast; /*退出*/ }else{ /*不是广播IP地址*/ retval = 0; } EXITin_addr_isbroadcast: return retval; } #define IP_FREE_REASS(ipr) \ do{ \ struct skbuff *skb=NULL,*skb_prev=NULL; \ for(skb_prev = skb = ipr->skb; \ skb != NULL; \ skb_prev = skb, \ skb = skb->next, \ skb_free(skb_prev)); \ free(ipr); \ }while(0); #define IPREASS_TIMEOUT 3 /*IP分组重组的超时时间为3秒*/ static struct sip_reass *ip_reass_list = NULL; /*IP重组的链表*/ struct skbuff *sip_reassemble(struct skbuff* skb) { struct sip_iphdr *fraghdr = skb->nh.iph; int retval = 0; __u16 offset, len; int found = 0; offset = (fraghdr->frag_off & 0x1FFF)<<3; /*取得IP分组偏移地址,32位长*/ len = fraghdr->tot_len - fraghdr->ihl<<2; /*IP分组的数据长度*/ struct sip_reass *ipr = NULL,*ipr_prev = NULL; for(ipr_prev = ipr= ip_reass_list; ipr != NULL; ) { if(time(NULL) -ipr->timer > IPREASS_TIMEOUT) /*此分组是超时?*/ { if(ipr_prev == NULL) /*第一个分片?*/ { ipr_prev = ipr; /*更新守护的指针为本分组*/ ip_reass_list->next = ipr = ipr->next; /*将超时的分片从重组链表上取下来*/ ipr = ipr->next; /*更新当前的分组指针*/ IP_FREE_REASS(ipr_prev); /*释放资源*/ ipr_prev->next =NULL; /*重置指针为空*/ continue; /*继续查找合适的分组*/ } else /*不是第一个分组*/ { ipr_prev->next = ipr->next; /*从分片链表上摘除当前链*/ IP_FREE_REASS(ipr); /*释放当前重组链*/ ipr = ipr_prev->next; /*更新当前链的指针*/ continue; /*继续查找*/ } } /*分片是否输入此条链*/ if(ipr->iphdr.daddr == fraghdr->daddr /*目的IP地址匹配*/ &&ipr->iphdr.saddr == fraghdr->saddr /*源IP地址匹配*/ &&ipr->iphdr.id == fraghdr->id) /*分片的ID匹配*/ { found = 1; /*属于这条链*/ break; } } if(!found) /*没有找到合适的分组链?*/ { ipr_prev = NULL; /*初始化为空*/ ipr = (struct sip_reass*)malloc(sizeof(struct sip_reass));/*申请一个分组数据结构*/ if(!ipr) /*申请失败*/ { retval = -1; /*返回值-1*/ goto freeskb; /*退出*/ } memset(ipr, 0, sizeof(struct sip_reass)); /*初始化分组结构*/ ipr->next = ip_reass_list; /*将当前分组结构挂接到分组链的头部*/ ip_reass_list = ipr; memcpy(&ipr->iphdr, skb->nh.raw, sizeof(IPHDR_LEN));/*拷贝IP的数据头部,便于之后的分片匹配*/ }else{ /*找到合适的分组链*/ if(((fraghdr->frag_off & 0x1FFF) == 0) /*当前数据位于分片第一个*/ &&((ipr->iphdr.frag_off & 0x1FFF) != 0)) /*分组链上的头部不是第一个分片*/ { memcpy(&ipr->iphdr, fraghdr, IPHDR_LEN); /*更新重组中的IP头部结构*/ } } /* 检查是否为最后一个分组*/ if( (fraghdr->frag_off & htons(0x2000)) == 0) { /*没有更多分组*/ #define IP_REASS_FLAG_LASTFRAG 0x01 ipr->flags |= IP_REASS_FLAG_LASTFRAG; /*设置最后分组标志*/ ipr->datagram_len = offset + len; /*设置IP数据报文的全长*/ } /*将当前的数据放到重组链上,并更新状态*/ struct skbuff *skb_prev=NULL, *skb_cur=NULL; int finish =0; void *pos = NULL; __u32 length = 0; #define FRAG_OFFSET(iph) (ntohs(iph->frag_off & 0x1FFF)<<3) #define FRAG_LENGTH(iph) (ntohs(iph->tot_len) - IPHDR_LEN) for(skb_prev =NULL, skb_cur=ipr->skb,length = 0,found = 0; skb_cur != NULL && !found; skb_prev=skb_cur,skb_cur = skb_cur->next) { if(skb_prev !=NULL) /*不是第一个分片*/ { if((offset < FRAG_OFFSET(skb_cur->nh.iph)) /*接收数据的偏移值位于前后两个之间*/ &&(offset > FRAG_OFFSET(skb_prev->nh.iph))) { skb->next = skb_cur; /*将接收到的数据放到此位置*/ skb_prev->next = skb; if(offset + len > FRAG_OFFSET(skb_cur->nh.iph)) /*当前数据与后面的分片数据覆盖?*/ { __u16 modify = FRAG_OFFSET(skb_cur->nh.iph) - offset + IPHDR_LEN;/*计算当前链的数据长度修改值*/ skb->nh.iph->tot_len = htons(modify); /*更新当前链长度*/ } if(FRAG_OFFSET(skb_prev->nh.iph) /*前面的分片长度覆盖当前数据?*/ + FRAG_LENGTH(skb_prev->nh.iph) > FRAG_OFFSET(skb_cur->nh.iph)) { __u16 modify = FRAG_OFFSET(skb_prev->nh.iph) - offset + IPHDR_LEN;/*计算前面数据长度的更改之*/ skb_prev->nh.iph->tot_len = htons(modify); /*修改前一片的数据长度*/ } found = 1; /*找到合适的分片插入位置*/ } } else /*为重组链上的头部*/ { if(offset < FRAG_OFFSET(skb_cur->nh.iph)){ /*当前链的偏移量小于第一个分片的偏移长度*/ skb->next = ipr->skb; /*挂接到重组链的头部*/ ipr->skb = skb; if(offset + len + IPHDR_LEN /*查看是否覆盖后面分片的数据*/ > FRAG_OFFSET(skb_cur->nh.iph)) { __u16 modify = FRAG_OFFSET(skb_cur->nh.iph) - offset + IPHDR_LEN;/*修改分片的数据长度*/ if(!offset) /*偏离量为0*/ modify -= IPHDR_LEN; /*包含头部,所以数据段长度需要减去IP头部长度*/ skb->nh.iph->tot_len = htons(modify); /*设置分片中修改后的长度*/ } } } length += skb_cur->nh.iph->tot_len - IPHDR_LEN; /*当前链表中的数据长度*/ } /*重新计算重组链上的总数据长度*/ for(skb_cur=ipr->skb,length = 0; skb_cur != NULL; skb_cur = skb_cur->next) { length += skb_cur->nh.iph->tot_len - IPHDR_LEN; } length += IPHDR_LEN; /*全部的IP分片都已经接收到后进行数据报文的重新组合 数据拷贝到一个新的数据结构中,原来的数据接收都释放掉 并从分组链中取出,将重组后的数据结构指针返回*/ if(length == ipr->datagram_len ) /*分组全部接收到?*/ { ipr->datagram_len += IPHDR_LEN; /*计算数据报文的实际长度长度*/ skb = skb_alloc(ipr->datagram_len + ETH_HLEN); /*申请空间*/ skb->phy.raw = skb_put(skb, ETH_HLEN); /*物理层*/ skb->nh.raw = skb_put(skb, IPHDR_LEN); /*网络层*/ memcpy(skb->nh.raw, & ipr->iphdr, sizeof(ipr->iphdr)); /*向新数据结构中拷贝IP头*/ skb->nh.iph->tot_len = htons(ipr->datagram_len); /*新结构中的tot_len*/ for(skb_prev=skb_cur=ipr->skb;skb_cur != NULL;) /*遍历重组数据链*/ { int size = skb_cur->end - skb_cur->tail; /*计算拷贝数据源的长度*/ pos = skb_put(skb, size); /*计算拷贝目的地址位置*/ memcpy(pos, /*将一个分片拷贝到新结构中*/ skb_cur->tail, skb_cur->nh.iph->tot_len - skb_cur->nh.iph->ihl<<2); } /*一下从重组链中摘除数据并释放,然后设置新结构中的几个IP头部参数*/ ipr_prev->next = ipr->next; /*将此数据报文从重组链中摘除*/ IP_FREE_REASS(ipr); /*释放此报文的重组连*/ skb->nh.iph->check = 0; /*设置校验值为0*/ skb->nh.iph->frag_off = 0; /*偏移值为0*/ skb->nh.iph->check = SIP_Chksum(skb->nh.raw, skb->nh.iph->tot_len);/*计算IP头部校验和*/ } normal: return skb; freeskb: skb_free(skb); return NULL; }
int ip_input(struct net_device *dev, struct skbuff *skb) { DBGPRINT(DBG_LEVEL_TRACE,"==>ip_input\n"); struct sip_iphdr *iph = skb->nh.iph; int retval = 0; printf("len = %d, version = %d, hlen = %d\n", skb->len, iph->version, iph->ihl<<2); if(skb->len < 0) /*网络数据长度不合法*/ { skb_free(skb); /*释放结构*/ retval = -1; /*设置返回值*/ goto EXITip_input; /*退出*/ } if(iph->version != 4) /*IP版本不合适,不是IPv4*/ { skb_free(skb); retval = -1; goto EXITip_input; } __u16 hlen = iph->ihl<<2; /*计算IP头部长度*/ if(hlen < IPHDR_LEN) /*长度国小*/ { skb_free(skb); retval = -1; goto EXITip_input; } printf("tol_len = %d\n", skb->tot_len); if(skb->tot_len - ETH_HLEN < ntohs(iph->tot_len)) /*计算总长度是否合法*/ { skb_free(skb); retval = -1; goto EXITip_input; } if(SIP_Chksum(skb->nh.raw, IPHDR_LEN)) /*计算IP头部的校验和,是否正确,为0*/ { DBGPRINT(DBG_LEVEL_ERROR, "IP check sum error\n"); skb_free(skb); retval= -1; goto EXITip_input; } else /*校验和合法*/ { skb->ip_summed = CHECKSUM_HW; /*设置IP校验标记*/ DBGPRINT(DBG_LEVEL_NOTES, "IP check sum success\n"); } if((iph->daddr != dev->ip_host.s_addr /*不是发往本地*/ && !IP_IS_BROADCAST(dev, iph->daddr) /*目的地址不是广播地址*/ ||IP_IS_BROADCAST(dev, iph->saddr))) /*源地址不是广播地址*/ { DBGPRINT(DBG_LEVEL_NOTES, "IP address INVALID\n"); skb_free( skb); retval= -1; goto EXITip_input; } if((ntohs(iph->frag_off) & 0x3FFF) !=0) /*有偏移,是一个分片*/ { printf("call sip_reassemble \n"); skb = sip_reassemble(skb); /*进行分片重组*/ if(!skb){ /*重组不成功*/ retval = 0; goto EXITip_input; } } switch(iph->protocol) /*IP协议类型*/ { case IPPROTO_ICMP: /*ICMP协议*/ skb->th.icmph = /*ICMP头部指针获取*/ (struct sip_icmphdr*)skb_put(skb, sizeof(struct sip_icmphdr)); icmp_input(dev, skb); /*转给ICMP模块处理*/ printf("ip IPPROTO_ICMP = %d\n",iph->protocol); break; case IPPROTO_UDP: /*UDP协议*/ skb->th.udph = /*UDP头部指针获取*/ (struct sip_udphdr*)skb_put(skb, sizeof(struct sip_udphdr)); SIP_UDPInput(dev, skb); /*转给UDP模块处理*/ printf("ip IPPROTO_UDP = %d\n",iph->protocol); break; default: break; } EXITip_input: DBGPRINT(DBG_LEVEL_TRACE,"<==ip_input\n"); return retval; }