summaryrefslogtreecommitdiffstats
path: root/net/ipv6/udp.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /net/ipv6/udp.c
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r--net/ipv6/udp.c109
1 files changed, 66 insertions, 43 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index b3045c694..e167c7e78 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -7,7 +7,7 @@
*
* Based on linux/ipv4/udp.c
*
- * $Id: udp.c,v 1.43 1999/07/02 11:26:44 davem Exp $
+ * $Id: udp.c,v 1.45 1999/08/20 11:06:32 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -41,6 +41,7 @@
#include <net/addrconf.h>
#include <net/ip.h>
#include <net/udp.h>
+#include <net/inet_common.h>
#include <net/checksum.h>
@@ -51,7 +52,7 @@ struct udp_mib udp_stats_in6;
*/
static int udp_v6_get_port(struct sock *sk, unsigned short snum)
{
- SOCKHASH_LOCK_WRITE();
+ write_lock_bh(&udp_hash_lock);
if (snum == 0) {
int best_size_so_far, best, result, i;
@@ -112,11 +113,11 @@ gotit:
}
sk->num = snum;
- SOCKHASH_UNLOCK_WRITE();
+ write_unlock_bh(&udp_hash_lock);
return 0;
fail:
- SOCKHASH_UNLOCK_WRITE();
+ write_unlock_bh(&udp_hash_lock);
return 1;
}
@@ -124,7 +125,7 @@ static void udp_v6_hash(struct sock *sk)
{
struct sock **skp = &udp_hash[sk->num & (UDP_HTABLE_SIZE - 1)];
- SOCKHASH_LOCK_WRITE();
+ write_lock_bh(&udp_hash_lock);
if ((sk->next = *skp) != NULL)
(*skp)->pprev = &sk->next;
*skp = sk;
@@ -132,20 +133,22 @@ static void udp_v6_hash(struct sock *sk)
sk->prot->inuse++;
if(sk->prot->highestinuse < sk->prot->inuse)
sk->prot->highestinuse = sk->prot->inuse;
- SOCKHASH_UNLOCK_WRITE();
+ sock_hold(sk);
+ write_unlock_bh(&udp_hash_lock);
}
static void udp_v6_unhash(struct sock *sk)
{
- SOCKHASH_LOCK_WRITE();
+ write_lock_bh(&udp_hash_lock);
if (sk->pprev) {
if (sk->next)
sk->next->pprev = sk->pprev;
*sk->pprev = sk->next;
sk->pprev = NULL;
sk->prot->inuse--;
+ __sock_put(sk);
}
- SOCKHASH_UNLOCK_WRITE();
+ write_unlock_bh(&udp_hash_lock);
}
static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
@@ -155,11 +158,10 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
unsigned short hnum = ntohs(dport);
int badness = -1;
- SOCKHASH_LOCK_READ();
+ read_lock(&udp_hash_lock);
for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
if((sk->num == hnum) &&
- (sk->family == PF_INET6) &&
- !(sk->dead && (sk->state == TCP_CLOSE))) {
+ (sk->family == PF_INET6)) {
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
int score = 0;
if(sk->dport) {
@@ -191,7 +193,9 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
}
}
}
- SOCKHASH_UNLOCK_READ();
+ if (result)
+ sock_hold(result);
+ read_unlock(&udp_hash_lock);
return result;
}
@@ -219,7 +223,7 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (addr_len < sizeof(*usin))
return -EINVAL;
- if (usin->sin6_family && usin->sin6_family != AF_INET6)
+ if (usin->sin6_family != AF_INET6)
return -EAFNOSUPPORT;
fl.fl6_flowlabel = 0;
@@ -334,13 +338,7 @@ ipv4_connected:
static void udpv6_close(struct sock *sk, long timeout)
{
- bh_lock_sock(sk);
-
- /* See for explanation: raw_close in ipv4/raw.c */
- sk->state = TCP_CLOSE;
- udp_v6_unhash(sk);
- sk->dead = 1;
- destroy_sock(sk);
+ inet_sock_release(sk);
}
#ifndef HAVE_CSUM_COPY_USER
@@ -383,6 +381,19 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
copied);
} else if (copied > msg->msg_iov[0].iov_len || (msg->msg_flags&MSG_TRUNC)) {
if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) {
+ /* Clear queue. */
+ if (flags&MSG_PEEK) {
+ int clear = 0;
+ spin_lock_irq(&sk->receive_queue.lock);
+ if (skb == skb_peek(&sk->receive_queue)) {
+ __skb_unlink(skb, &sk->receive_queue);
+ clear = 1;
+ }
+ spin_unlock_irq(&sk->receive_queue.lock);
+ if (clear)
+ kfree_skb(skb);
+ }
+
/* Error for blocking case is chosen to masquerade
as some normal condition.
*/
@@ -426,7 +437,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
if (skb->protocol == __constant_htons(ETH_P_IP)) {
ipv6_addr_set(&sin6->sin6_addr, 0, 0,
__constant_htonl(0xffff), skb->nh.iph->saddr);
- if (sk->ip_cmsg_flags)
+ if (sk->protinfo.af_inet.cmsg_flags)
ip_cmsg_recv(msg, skb);
} else {
memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
@@ -448,7 +459,7 @@ void udpv6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
struct inet6_skb_parm *opt,
int type, int code, unsigned char *buff, __u32 info)
{
- struct device *dev = skb->dev;
+ struct net_device *dev = skb->dev;
struct in6_addr *saddr = &hdr->saddr;
struct in6_addr *daddr = &hdr->daddr;
struct sock *sk;
@@ -467,16 +478,19 @@ void udpv6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
if (!icmpv6_err_convert(type, code, &err) &&
!sk->net_pinfo.af_inet6.recverr)
- return;
+ goto out;
- if (sk->bsdism && sk->state!=TCP_ESTABLISHED)
- return;
+ if (sk->bsdism && sk->state!=TCP_ESTABLISHED &&
+ !sk->net_pinfo.af_inet6.recverr)
+ goto out;
if (sk->net_pinfo.af_inet6.recverr)
ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
sk->err = err;
sk->error_report(sk);
+out:
+ sock_put(sk);
}
static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
@@ -511,8 +525,7 @@ static struct sock *udp_v6_mcast_next(struct sock *sk,
struct sock *s = sk;
unsigned short num = ntohs(loc_port);
for(; s; s = s->next) {
- if((s->num == num) &&
- !(s->dead && (s->state == TCP_CLOSE))) {
+ if(s->num == num) {
struct ipv6_pinfo *np = &s->net_pinfo.af_inet6;
if(s->dport) {
if(s->dport != rmt_port)
@@ -549,6 +562,7 @@ static void udpv6_mcast_deliver(struct udphdr *uh,
struct sk_buff *buff;
int dif;
+ read_lock(&udp_hash_lock);
sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
dif = skb->dev->ifindex;
sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
@@ -573,13 +587,14 @@ static void udpv6_mcast_deliver(struct udphdr *uh,
free_skb:
kfree_skb(skb);
}
+ read_unlock(&udp_hash_lock);
}
int udpv6_rcv(struct sk_buff *skb, unsigned long len)
{
struct sock *sk;
struct udphdr *uh;
- struct device *dev = skb->dev;
+ struct net_device *dev = skb->dev;
struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
u32 ulen;
@@ -663,11 +678,17 @@ int udpv6_rcv(struct sk_buff *skb, unsigned long len)
kfree_skb(skb);
return(0);
}
+ if (0/*sk->user_callback &&
+ sk->user_callback(sk->user_data, skb) == 0*/) {
+ udp_stats_in6.UdpInDatagrams++;
+ sock_put(sk);
+ return(0);
+ }
/* deliver */
udpv6_queue_rcv_skb(sk, skb);
-
+ sock_put(sk);
return(0);
discard:
@@ -764,9 +785,6 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
if (ulen < 0 || ulen > INT_MAX - sizeof(struct udphdr))
return -EMSGSIZE;
- if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT))
- return -EINVAL;
-
fl.fl6_flowlabel = 0;
if (sin6) {
@@ -886,6 +904,9 @@ static struct inet6_protocol udpv6_protocol =
"UDPv6" /* name */
};
+#define LINE_LEN 190
+#define LINE_FMT "%-190s\n"
+
static void get_udp6_sock(struct sock *sp, char *tmpbuf, int i)
{
struct in6_addr *dest, *src;
@@ -901,7 +922,7 @@ static void get_udp6_sock(struct sock *sp, char *tmpbuf, int i)
timer_expires = (timer_active == 2 ? sp->timer.expires : jiffies);
sprintf(tmpbuf,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
- "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
+ "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p",
i,
src->s6_addr32[0], src->s6_addr32[1],
src->s6_addr32[2], src->s6_addr32[3], srcp,
@@ -910,8 +931,9 @@ static void get_udp6_sock(struct sock *sp, char *tmpbuf, int i)
sp->state,
atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
timer_active, timer_expires-jiffies, 0,
- sp->socket->inode->i_uid, timer_active ? sp->timeout : 0,
- sp->socket ? sp->socket->inode->i_ino : 0);
+ sp->socket->inode->i_uid, 0,
+ sp->socket ? sp->socket->inode->i_ino : 0,
+ atomic_read(&sp->refcnt), sp);
}
int udp6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
@@ -919,10 +941,10 @@ int udp6_get_info(char *buffer, char **start, off_t offset, int length, int dumm
int len = 0, num = 0, i;
off_t pos = 0;
off_t begin;
- char tmpbuf[150];
+ char tmpbuf[LINE_LEN+2];
- if (offset < 149)
- len += sprintf(buffer, "%-148s\n",
+ if (offset < LINE_LEN+1)
+ len += sprintf(buffer, LINE_FMT,
" sl " /* 6 */
"local_address " /* 38 */
"remote_address " /* 38 */
@@ -930,25 +952,25 @@ int udp6_get_info(char *buffer, char **start, off_t offset, int length, int dumm
" uid timeout inode"); /* 21 */
/*----*/
/*144 */
- pos = 149;
- SOCKHASH_LOCK_READ();
+ pos = LINE_LEN+1;
+ read_lock(&udp_hash_lock);
for (i = 0; i < UDP_HTABLE_SIZE; i++) {
struct sock *sk;
for (sk = udp_hash[i]; sk; sk = sk->next, num++) {
if (sk->family != PF_INET6)
continue;
- pos += 149;
+ pos += LINE_LEN+1;
if (pos < offset)
continue;
get_udp6_sock(sk, tmpbuf, i);
- len += sprintf(buffer+len, "%-148s\n", tmpbuf);
+ len += sprintf(buffer+len, LINE_FMT, tmpbuf);
if(len >= length)
goto out;
}
}
out:
- SOCKHASH_UNLOCK_READ();
+ read_unlock(&udp_hash_lock);
begin = len - (pos - offset);
*start = buffer + begin;
len -= begin;
@@ -962,6 +984,7 @@ out:
struct proto udpv6_prot = {
udpv6_close, /* close */
udpv6_connect, /* connect */
+ udp_disconnect, /* disconnect */
NULL, /* accept */
NULL, /* retransmit */
NULL, /* write_wakeup */