static void igmp_send_report(struct device *dev, unsigned long address, int type) { struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC); int tmp; struct igmphdr *ih; if(skb==NULL) return; if (type != IGMP_HOST_LEAVE_MESSAGE) tmp=ip_build_header(skb, dev->pa_addr, address, &dev, IPPROTO_IGMP, NULL, 28 , 0, 1, NULL); else tmp=ip_build_header(skb, dev->pa_addr, IGMP_ALL_ROUTER, &dev, IPPROTO_IGMP, NULL, 28, 0, 1, NULL); if(tmp<0) { kfree_skb(skb, FREE_WRITE); return; } ih=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr)); ih->type=type; ih->code=0; ih->csum=0; ih->group=address; ih->csum=ip_compute_csum((void *)ih,sizeof(struct igmphdr)); /* Checksum fill */ ip_queue_xmit(NULL,dev,skb,1); }
/* 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); }
static void igmp_send_report(struct device *dev, unsigned long address, int type) { struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC); int tmp; struct igmphdr *igh; if(skb==NULL) return; tmp=ip_build_header(skb, INADDR_ANY, address, &dev, IPPROTO_IGMP, NULL, skb->mem_len, 0, 1); if(tmp<0) { kfree_skb(skb, FREE_WRITE); return; } igh=(struct igmphdr *)(skb->data+tmp); skb->len=tmp+sizeof(*igh); igh->csum=0; igh->unused=0; igh->type=type; igh->group=address; igh->csum=ip_compute_csum((void *)igh,sizeof(*igh)); ip_queue_xmit(NULL,dev,skb,1); }
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 */ }