patch-2.1.124 linux/net/ipv4/raw.c
Next file: linux/net/ipv4/route.c
Previous file: linux/net/ipv4/proc.c
Back to the patch index
Back to the overall index
- Lines: 111
- Date:
Sun Oct 4 10:19:40 1998
- Orig file:
v2.1.123/linux/net/ipv4/raw.c
- Orig date:
Sat Sep 5 16:46:42 1998
diff -u --recursive --new-file v2.1.123/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
@@ -5,7 +5,7 @@
*
* RAW - implementation of IP "raw" sockets.
*
- * Version: $Id: raw.c,v 1.37 1998/08/26 12:04:07 davem Exp $
+ * Version: $Id: raw.c,v 1.38 1998/10/03 09:37:45 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -143,26 +143,53 @@
return s;
}
-/*
- * Raw_err does not currently get called by the icmp module - FIXME:
- */
-
void raw_err (struct sock *sk, struct sk_buff *skb)
{
int type = skb->h.icmph->type;
int code = skb->h.icmph->code;
+ u32 info = 0;
+ int err = 0;
+ int harderr = 0;
+
+ /* Report error on raw socket, if:
+ 1. User requested ip_recverr.
+ 2. Socket is connected (otherwise the error indication
+ is useless without ip_recverr and error is hard.
+ */
+ if (!sk->ip_recverr && sk->state != TCP_ESTABLISHED)
+ return;
- if (sk->ip_recverr) {
- struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2 && sock_queue_err_skb(sk, skb2))
- kfree_skb(skb);
+ switch (type) {
+ default:
+ case ICMP_TIME_EXCEEDED:
+ err = EHOSTUNREACH;
+ break;
+ case ICMP_SOURCE_QUENCH:
+ return;
+ case ICMP_PARAMETERPROB:
+ err = EPROTO;
+ info = ntohl(skb->h.icmph->un.gateway)>>24;
+ harderr = 1;
+ break;
+ case ICMP_DEST_UNREACH:
+ err = EHOSTUNREACH;
+ if (code > NR_ICMP_UNREACH)
+ break;
+ err = icmp_err_convert[code].errno;
+ harderr = icmp_err_convert[code].fatal;
+ if (code == ICMP_FRAG_NEEDED) {
+ harderr = (sk->ip_pmtudisc != IP_PMTUDISC_DONT);
+ err = EMSGSIZE;
+ info = ntohs(skb->h.icmph->un.frag.mtu);
+ }
}
- if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
- if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
- sk->err = EMSGSIZE;
- sk->error_report(sk);
- }
+ if (sk->ip_recverr)
+ ip_icmp_error(sk, skb, err, 0, info, (u8 *)(skb->h.icmph + 1));
+
+ if (sk->ip_recverr || harderr) {
+ sk->err = err;
+ sk->error_report(sk);
}
}
@@ -170,7 +197,7 @@
{
/* Charge it to the socket. */
- if (__sock_queue_rcv_skb(sk,skb)<0)
+ if (sock_queue_rcv_skb(sk,skb)<0)
{
ip_statistics.IpInDiscards++;
kfree_skb(skb);
@@ -443,23 +470,12 @@
if (flags & MSG_OOB)
return -EOPNOTSUPP;
-
- if (sk->shutdown & RCV_SHUTDOWN)
- return(0);
if (addr_len)
*addr_len=sizeof(*sin);
- if (sk->ip_recverr && (skb = skb_dequeue(&sk->error_queue)) != NULL) {
- err = sock_error(sk);
- if (msg->msg_controllen == 0) {
- skb_free_datagram(sk, skb);
- return err;
- }
- put_cmsg(msg, SOL_IP, IP_RECVERR, skb->len, skb->data);
- skb_free_datagram(sk, skb);
- return 0;
- }
+ if (flags & MSG_ERRQUEUE)
+ return ip_recv_error(sk, msg, len);
skb=skb_recv_datagram(sk,flags,noblock,&err);
if(skb==NULL)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov