int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { struct arp *arp; struct arp_table *tbl; int ret; PRINTK ("<<\n"); arp = skb->h.arp; print_arp(arp); /* if this test doesn't pass, something fishy is going on. */ if (arp->hlen != dev->addr_len || dev->type !=NET16( arp->hrd)) { free_skb(skb, FREE_READ); return (0); } /* for now we will only deal with ip addresses. */ if (arp->pro != NET16(ARP_IP_PROT) || arp->plen != 4) { free_skb (skb, FREE_READ); return (0); } /* now look up the ip address in the table. */ tbl = arp_lookup (*arp_sourcep(arp)); if (tbl != NULL) { memcpy (tbl->hard, arp+1, arp->hlen); tbl->hlen = arp->hlen; tbl->last_used = timer_seq; } if (!my_ip_addr(*arp_targetp(arp))) { free_skb (skb, FREE_READ); return (0); } if (tbl == NULL) create_arp (*arp_sourcep(arp), arp_sourceh(arp), arp->hlen); /* now see if we can send anything. */ send_arp_q(); if (arp->op != NET16(ARP_REQUEST)) { free_skb (skb, FREE_READ); return (0); } /* now we need to create a new packet. */ ret = arp_response(arp, dev); free_skb (skb, FREE_READ); return (ret); }
/* this should be the easiest of all, all we do is copy it into a buffer. */ int packet_rcv (struct sk_buff *skb, struct device *dev, struct packet_type *pt) { volatile struct sock *sk; sk = pt->data; skb->dev = dev; skb->len += dev->hard_header_len; /* now see if we are in use. */ cli(); if (sk->inuse) { sti(); /* drop any packets if we can't currently deal with them. Assume that the other end will retransmit if it was important. */ skb->sk = NULL; free_skb (skb, FREE_READ); return (0); } sk->inuse = 1; sti (); skb->sk = sk; /* charge it too the socket. */ if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX) { skb->sk = NULL; free_skb (skb, FREE_READ); return (0); } sk->rmem_alloc += skb->mem_len; /* now just put it onto the queue. */ if (sk->rqueue == NULL) { sk->rqueue = skb; skb->next = skb; skb->prev = skb; } else { skb->next = sk->rqueue; skb->prev = sk->rqueue->prev; skb->prev->next = skb; skb->next->prev = skb; } wake_up (sk->sleep); release_sock (sk); return (0); }
void RecvRoutine() { //char recv[1532]; int i,len; /*len=ReceivePacket(recv); printf("\n\r-===Recieve packet size:%d===-\n\r",len); for (i=0;i<len;i++) { printf(" %2x", recv[i]); if ((i>1)&&((i%16)==0)) printf("\n\r"); }*///uncomment test code to see more detail about our packet struct sk_buff *skb; struct ethhdr *eth_hdr; skb = alloc_skb(ETH_FRAME_LEN); len=ReceivePacket((char *)skb->data); skb->len=len; if (startTFTP==true) { eth_hdr = (struct ethhdr *)(skb->data); skb_pull(skb, ETH_HLEN); if (ntohs(eth_hdr->h_proto) == ETH_P_ARP) arp_rcv_packet(skb); else if(ntohs(eth_hdr->h_proto) == ETH_P_IP) ip_rcv_packet(skb); }else free_skb(skb); }
static int console_hup(int s, int ifindex) { int rc; uint8_t *p; struct sk_buff *skb = alloc_skb(64); p = skb_put(skb, 0); *p++ = EGETTY_HUP; *p++ = conf.console; p = skb_put(skb, 2); rc = console_send(s, ifindex, skb); if(rc == -1) { printf("sendto failed: %s\n", strerror(errno)); free_skb(skb); return -1; } free_skb(skb); return 0; }
void unlock_skb (struct sk_buff *skb, int rw) { if (skb->lock != 1) { printk ("*** bug unlocking non-locked sk_buff. \n"); } skb->lock = 0; if (skb->free) free_skb (skb, rw); }
/* this will do terrible things if len + ipheader + devheader > dev->mtu */ static int packet_sendto (volatile struct sock *sk, unsigned char *from, int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len) { struct sk_buff *skb; struct device *dev; struct sockaddr saddr; /* check the flags. */ if (flags) return (-EINVAL); if (len < 0) return (-EINVAL); /* get and verify the address. */ if (usin) { if (addr_len < sizeof (saddr)) return (-EINVAL); verify_area (usin, sizeof (saddr)); memcpy_fromfs (&saddr, usin, sizeof(saddr)); } else return (-EINVAL); skb = sk->prot->wmalloc (sk, len+sizeof (*skb) + sk->prot->max_header, 0); /* this shouldn't happen, but it could. */ if (skb == NULL) { PRINTK ("packet_sendto: write buffer full?\n"); print_sk (sk); return (-EAGAIN); } skb->mem_addr = skb; skb->mem_len = len + sizeof (*skb) +sk->prot->max_header; skb->sk = sk; skb->free = 1; saddr.sa_data[13] = 0; dev = get_dev (saddr.sa_data); if (dev == NULL) { sk->prot->wfree (sk, skb->mem_addr, skb->mem_len); return (-ENXIO); } verify_area (from, len); memcpy_fromfs (skb+1, from, len); skb->len = len; skb->next = NULL; if (dev->up) dev->queue_xmit (skb, dev, sk->priority); else free_skb (skb, FREE_WRITE); return (len); }
/* sends an icmp message in response to a packet. */ void icmp_reply (struct sk_buff *skb_in, int type, int code, struct device *dev) { struct sk_buff *skb; struct ip_header *iph; int offset; struct icmp_header *icmph; int len; /* get some memory for the replay. */ len = sizeof (*skb) + 8 /* amount of header to return. */ + sizeof (struct icmp_header) + 64 /* enough for an ip header. */ + dev->hard_header_len; skb = malloc (len); if (skb == NULL) return; skb->mem_addr = skb; skb->mem_len = len; len -= sizeof (*skb); /* find the ip header. */ iph = (struct ip_header *)(skb_in+1); iph = (struct ip_header *)((unsigned char *)iph + dev->hard_header_len); /* Build Layer 2-3 headers for message back to source */ offset = ip_build_header( skb, iph->daddr, iph->saddr, &dev, IP_ICMP, NULL, len ); if (offset < 0) { skb->sk = NULL; free_skb (skb, FREE_READ); return; } /* Readjust length according to actual IP header size */ skb->len = offset + sizeof (struct icmp_header) + 8; icmph = (struct icmp_header *)((unsigned char *)(skb+1) + offset); icmph->type = type; icmph->code = code; icmph->checksum = 0; /* we don't need to compute this. */ icmph->un.gateway = 0; /* might as well 0 it. */ memcpy (icmph+1, iph+1, 8); /* send it and free it. */ ip_queue_xmit (NULL, dev, skb, 1); }
void icmpv4_incoming(struct sk_buff *skb) { struct iphdr *iphdr = ip_hdr(skb); struct icmp_v4 *icmp = (struct icmp_v4 *) iphdr->data; //TODO: Check csum switch (icmp->type) { case ICMP_V4_ECHO: icmpv4_reply(skb); return; case ICMP_V4_DST_UNREACHABLE: print_err("ICMPv4 received 'dst unreachable' code %d, " "check your routes and firewall rules\n", icmp->code); goto drop_pkt; default: print_err("ICMPv4 did not match supported types\n"); goto drop_pkt; } drop_pkt: free_skb(skb); return; }
void icmpv4_reply(struct sk_buff *skb) { struct iphdr *iphdr = ip_hdr(skb); struct icmp_v4 *icmp; struct sock sk; memset(&sk, 0, sizeof(struct sock)); uint16_t icmp_len = iphdr->len - (iphdr->ihl * 4); skb_reserve(skb, ETH_HDR_LEN + IP_HDR_LEN + icmp_len); skb_push(skb, icmp_len); icmp = (struct icmp_v4 *)skb->data; icmp->type = ICMP_V4_REPLY; icmp->csum = 0; icmp->csum = checksum(icmp, icmp_len, 0); skb->protocol = ICMPV4; sk.daddr = iphdr->saddr; ip_output(&sk, skb); free_skb(skb); }
int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, unsigned long daddr, unsigned short len, unsigned long saddr, int redo, struct ip_protocol *protocol ) { int size, offset; struct icmp_header *icmph, *icmphr; struct sk_buff *skb; unsigned char *buff; /* drop broadcast packets. */ if ((daddr & 0xff000000) == 0 || (daddr & 0xff000000) == 0xff000000) { skb1->sk = NULL; free_skb (skb1, FREE_READ); return (0); } buff = skb1->h.raw; icmph = (struct icmp_header *)buff; /* Validate the packet first */ if( icmph->checksum ) { /* Checksums Enabled? */ if( ip_compute_csum( (unsigned char *)icmph, len ) ) { /* Failed checksum! */ PRINTK("\nICMP ECHO failed checksum!"); skb1->sk = NULL; free_skb (skb1, FREE_READ); return (0); } } print_icmph(icmph); /* Parse the ICMP message */ switch( icmph->type ) { case ICMP_DEST_UNREACH: case ICMP_SOURCE_QUENCH: { struct ip_header *iph; struct ip_protocol *ipprot; unsigned char hash; int err; err = icmph->type << 8 | icmph->code; /* we need to cause the socket to be closed and the error message to be set appropriately. */ iph = (struct ip_header *)(icmph+1); /* get the protocol(s) */ hash = iph->protocol & (MAX_IP_PROTOS -1 ); for (ipprot = ip_protos[hash]; ipprot != NULL; ipprot=ipprot->next) { /* pass it off to everyone who wants it. */ ipprot->err_handler (err, (unsigned char *)iph+4*iph->ihl, iph->daddr, iph->saddr, ipprot); } skb1->sk = NULL; free_skb (skb1, FREE_READ); return (0); } case ICMP_REDIRECT: { /* we need to put a new route in the routing table. */ struct rtable *rt; /* we will add a new route. */ struct ip_header *iph; iph = (struct ip_header *)(icmph+1); rt = malloc (sizeof (*rt)); if (rt != NULL) { rt->net = iph->daddr; /* assume class C network. Technically this is incorrect, but will give it a try. */ if ((icmph->code & 1) == 0) rt->net &= 0x00ffffff; rt->dev = dev; rt->router = icmph->un.gateway; add_route (rt); } skb1->sk = NULL; free_skb (skb1, FREE_READ); return (0); } case ICMP_ECHO: /* Allocate an sk_buff response buffer (assume 64 byte IP header) */ size = sizeof( struct sk_buff ) + dev->hard_header_len + 64 + len; skb = malloc( size ); if (skb == NULL) { skb1->sk = NULL; free_skb (skb1, FREE_READ); return (0); } skb->sk = NULL; skb->mem_addr = skb; skb->mem_len = size; /* Build Layer 2-3 headers for message back to source */ offset = ip_build_header( skb, daddr, saddr, &dev, IP_ICMP, opt, len ); if (offset < 0) { /* Problems building header */ PRINTK("\nCould not build IP Header for ICMP ECHO Response"); free_s (skb->mem_addr, skb->mem_len); skb1->sk = NULL; free_skb (skb1, FREE_READ); return( 0 ); /* just toss the received packet */ } /* Readjust length according to actual IP header size */ skb->len = offset + len; /* Build ICMP_ECHO Response message */ icmphr = (struct icmp_header *)( (char *)( skb + 1 ) + offset ); memcpy( (char *)icmphr, (char *)icmph, len ); icmphr->type = ICMP_ECHOREPLY; icmphr->code = 0; icmphr->checksum = 0; if( icmph->checksum ) { /* Calculate Checksum */ icmphr->checksum = ip_compute_csum( (void *)icmphr, len ); } /* Ship it out - free it when done */ ip_queue_xmit( (volatile struct sock *)NULL, dev, skb, 1 ); skb1->sk = NULL; free_skb (skb1, FREE_READ); return( 0 ); default: PRINTK("\nUnsupported ICMP type = x%x", icmph->type ); skb1->sk = NULL; free_skb (skb1, FREE_READ); return( 0 ); /* just toss the packet */ } /* should be unecessary, but just in case. */ skb1->sk = NULL; free_skb (skb1, FREE_READ); return( 0 ); /* just toss the packet */ }
int packet_recvfrom (volatile struct sock *sk, unsigned char *to, int len, int noblock, unsigned flags, struct sockaddr_in *sin, int *addr_len) { /* this should be easy, if there is something there we return it, otherwise we block. */ int copied=0; struct sk_buff *skb; struct sockaddr *saddr; saddr = (struct sockaddr *)sin; if (len == 0) return (0); if (len < 0) return (-EINVAL); if (addr_len) { verify_area (addr_len, sizeof(*addr_len)); put_fs_long (sizeof (*saddr), addr_len); } sk->inuse = 1; while (sk->rqueue == NULL) { if (noblock) { release_sock (sk); return (-EAGAIN); } release_sock (sk); cli(); if (sk->rqueue == NULL) { interruptible_sleep_on (sk->sleep); if (current->signal & ~current->blocked) { return (-ERESTARTSYS); } } sti(); } skb = sk->rqueue; if (!(flags & MSG_PEEK)) { if (skb->next == skb ) { sk->rqueue = NULL; } else { sk->rqueue = sk->rqueue ->next; skb->prev->next = skb->next; skb->next->prev = skb->prev; } } copied = min (len, skb->len); verify_area (to, copied); memcpy_tofs (to, skb+1, copied); /* copy the address. */ if (saddr) { struct sockaddr addr; addr.sa_family = skb->dev->type; memcpy (addr.sa_data,skb->dev->name, 14); verify_area (saddr, sizeof (*saddr)); memcpy_tofs(saddr, &addr, sizeof (*saddr)); } if (!(flags & MSG_PEEK)) { free_skb (skb, FREE_READ); } release_sock (sk); return (copied); }
void destroy_sock(volatile struct sock *sk) { struct sk_buff *skb; PRINTK ("destroying socket %X\n",sk); /* just to be safe. */ sk->inuse = 1; remove_sock (sk); /* now we can no longer get new packets. */ delete_timer((struct timer *)&sk->time_wait); /* cleanup up the write buffer. */ for (skb = sk->wfront; skb != NULL; ) { struct sk_buff *skb2; skb2=skb->next; free_skb(skb, FREE_WRITE); skb=skb2; } sk->wfront = NULL; if (sk->rqueue != NULL) { skb = sk->rqueue; do { struct sk_buff *skb2; skb2=skb->next; /* this will take care of closing sockets that were listening and didn't accept everything. */ if (skb->sk != NULL && skb->sk != sk) { skb->sk->dead = 1; skb->sk->prot->close (skb->sk, 0); } free_skb(skb, FREE_READ); skb=skb2; } while (skb != sk->rqueue); } sk->rqueue = NULL; /* now we need to clean up the send head. */ for (skb = sk->send_head; skb != NULL; ) { struct sk_buff *skb2; /* we need to remove skb from the transmit queue. */ cli(); /* see if it's in a transmit queue. */ if (skb->next != NULL) { if (skb->next != skb) { skb->next->prev = skb->prev; skb->prev->next = skb->next; } else { int i; for (i = 0; i < DEV_NUMBUFFS; i++) { if (skb->dev && skb->dev->buffs[i] == skb) { skb->dev->buffs[i]= NULL; break; } } } } sti(); skb2=skb->link3; free_skb(skb, FREE_WRITE); skb=skb2; } sk->send_head = NULL; /* and now the backlog. */ if (sk->back_log != NULL) { /* this should never happen. */ printk ("cleaning back_log. \n"); cli(); skb = sk->back_log; do { struct sk_buff *skb2; skb2=skb->next; free_skb(skb, FREE_READ); skb=skb2; } while (skb != sk->back_log); sti(); } sk->back_log = NULL; /* now if everything is gone we can free the socket structure, otherwise we need to keep it around until everything is gone. */ if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0) { free_s ((void *)sk,sizeof (*sk)); } else { /* this should never happen. */ /* actually it can if an ack has just been sent. */ PRINTK ("possible memory leak in socket = %X\n", sk); print_sk (sk); sk->destroy = 1; sk->ack_backlog = 0; sk->inuse = 0; sk->time_wait.len = SOCK_DESTROY_TIME; sk->timeout = TIME_DESTROY; reset_timer ((struct timer *)&sk->time_wait); } }