patch-2.3.4 linux/net/decnet/dn_raw.c
Next file: linux/net/decnet/dn_route.c
Previous file: linux/net/decnet/dn_nsp_out.c
Back to the patch index
Back to the overall index
- Lines: 384
- Date:
Wed May 26 09:36:36 1999
- Orig file:
v2.3.3/linux/net/decnet/dn_raw.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.3/linux/net/decnet/dn_raw.c linux/net/decnet/dn_raw.c
@@ -0,0 +1,383 @@
+/*
+ * DECnet An implementation of the DECnet protocol suite for the LINUX
+ * operating system. DECnet is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * DECnet Raw Sockets Interface
+ *
+ * Author: Steve Whitehouse <SteveW@ACM.org>
+ *
+ *
+ * Changes:
+ * Steve Whitehouse - connect() function.
+ */
+
+#include <linux/config.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <net/sock.h>
+#include <net/dn.h>
+#include <net/dn_raw.h>
+
+static struct sock *dn_raw_nsp_sklist = NULL;
+static struct sock *dn_raw_routing_sklist = NULL;
+#ifdef CONFIG_DECNET_MOP
+static struct sock *dn_raw_mop_sklist = NULL;
+#endif /* CONFIG_DECNET_MOP */
+
+static void dn_raw_autobind(struct sock *sk)
+{
+
+ switch(sk->protocol) {
+ case DNPROTO_NSP:
+ sklist_insert_socket(&dn_raw_nsp_sklist, sk);
+ break;
+ case DNPROTO_ROU:
+ sklist_insert_socket(&dn_raw_routing_sklist, sk);
+ break;
+#ifdef CONFIG_DECNET_MOP
+ case DNPROTO_MOP:
+ sklist_insert_socket(&dn_raw_mop_sklist, sk);
+#endif /* CONFIG_DECNET_MOP */
+ default:
+ printk(KERN_DEBUG "dn_raw_autobind: Unknown protocol\n");
+ return;
+ }
+
+ sk->zapped = 0;
+}
+
+static int dn_raw_release(struct socket *sock, struct socket *peer)
+{
+ struct sock *sk = sock->sk;
+
+ if (sk == NULL)
+ return 0;
+
+ if (!sk->dead) sk->state_change(sk);
+
+ sk->dead = 1;
+ sk->socket = NULL;
+ sock->sk = NULL;
+
+ switch(sk->protocol) {
+ case DNPROTO_NSP:
+ sklist_destroy_socket(&dn_raw_nsp_sklist, sk);
+ break;
+ case DNPROTO_ROU:
+ sklist_destroy_socket(&dn_raw_routing_sklist, sk);
+ break;
+#ifdef CONFIG_DECNET_MOP
+ case DNPROTO_MOP:
+ sklist_destroy_socket(&dn_raw_mop_sklist, sk);
+ break;
+#endif /* CONFIG_DECNET_MOP */
+ }
+
+ return 0;
+}
+
+/*
+ * Bind does odd things with raw sockets. Its basically used to filter
+ * the incomming packets, but this differs with the different layers
+ * at which you extract packets.
+ *
+ * For Routing layer sockets, the object name is a host ordered unsigned
+ * short which is a mask for the 16 different types of possible routing
+ * packet. I'd like to also select by destination address of the packets
+ * but alas, this is rather too dificult to do at the moment.
+ */
+static int dn_raw_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+ struct sock *sk = sock->sk;
+ struct sockaddr_dn *addr = (struct sockaddr_dn *)uaddr;
+
+ if (addr_len != sizeof(struct sockaddr_dn))
+ return -EINVAL;
+
+ if (sk->zapped == 0)
+ return -EINVAL;
+
+ switch(sk->protocol) {
+ case DNPROTO_ROU:
+ if (addr->sdn_objnamel && (addr->sdn_objnamel != 2))
+ return -EINVAL;
+ /* Fall through here */
+ case DNPROTO_NSP:
+ if (addr->sdn_add.a_len && (addr->sdn_add.a_len != 2))
+ return -EINVAL;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ if (addr->sdn_objnamel > (DN_MAXOBJL-1))
+ return -EINVAL;
+
+ if (addr->sdn_add.a_len > DN_MAXADDL)
+ return -EINVAL;
+
+
+ memcpy(&sk->protinfo.dn.addr, addr, sizeof(struct sockaddr_dn));
+
+ dn_raw_autobind(sk);
+
+ return 0;
+}
+
+/*
+ * This is to allow send() and write() to work. You set the destination address
+ * with this function.
+ */
+static int dn_raw_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct dn_scp *scp = &sk->protinfo.dn;
+ struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
+
+ if (addr_len != sizeof(struct sockaddr_dn))
+ return -EINVAL;
+
+ if (saddr->sdn_family != AF_DECnet)
+ return -EINVAL;
+
+ if (saddr->sdn_objnamel > (DN_MAXOBJL-1))
+ return -EINVAL;
+
+ if (saddr->sdn_add.a_len > DN_MAXADDL)
+ return -EINVAL;
+
+ if (sk->zapped)
+ dn_raw_autobind(sk);
+
+ memcpy(&scp->peer, saddr, sizeof(struct sockaddr_dn));
+
+ return 0;
+}
+
+/*
+ * TBD.
+ */
+static int dn_raw_sendmsg(struct socket *sock, struct msghdr *hdr, int size,
+ struct scm_cookie *scm)
+{
+ struct sock *sk = sock->sk;
+
+ if (sk->zapped)
+ dn_raw_autobind(sk);
+
+ if (sk->protocol != DNPROTO_NSP)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+/*
+ * This works fine, execpt that it doesn't report the originating address
+ * or anything at the moment.
+ */
+static int dn_raw_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+ int flags, struct scm_cookie *scm)
+{
+ struct sock *sk = sock->sk;
+ struct sk_buff *skb;
+ int err = 0;
+ int copied = 0;
+
+ if (sk->zapped)
+ dn_raw_autobind(sk);
+
+ if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err)) == NULL)
+ goto out;
+
+ copied = skb->len;
+
+ if (copied > size) {
+ copied = size;
+ msg->msg_flags |= MSG_TRUNC;
+ }
+
+ if ((err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied)) != 0) {
+ if (flags & MSG_PEEK)
+ atomic_dec(&skb->users);
+ else
+ skb_queue_head(&sk->receive_queue, skb);
+
+ goto out;
+ }
+
+ skb_free_datagram(sk, skb);
+
+out:
+ return copied ? copied : err;
+}
+
+struct proto_ops dn_raw_proto_ops = {
+ AF_DECnet,
+
+ sock_no_dup,
+ dn_raw_release,
+ dn_raw_bind,
+ dn_raw_connect,
+ sock_no_socketpair,
+ sock_no_accept,
+ sock_no_getname,
+ datagram_poll,
+ sock_no_ioctl,
+ sock_no_listen,
+ sock_no_shutdown,
+ sock_no_setsockopt,
+ sock_no_getsockopt,
+ sock_no_fcntl,
+ dn_raw_sendmsg,
+ dn_raw_recvmsg
+};
+
+#ifdef CONFIG_PROC_FS
+int dn_raw_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
+ struct sock *sk;
+
+ cli();
+ for(sk = dn_raw_nsp_sklist; sk; sk = sk->next) {
+ len += sprintf(buffer+len, "NSP\n");
+
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+
+ if (pos > offset + length)
+ goto all_done;
+
+ }
+
+ for(sk = dn_raw_routing_sklist; sk; sk = sk->next) {
+ len += sprintf(buffer+len, "ROU\n");
+
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+
+ if (pos > offset + length)
+ goto all_done;
+ }
+
+#ifdef CONFIG_DECNET_MOP
+ for(sk = dn_raw_mop_sklist; sk; sk = sk->next) {
+ len += sprintf(buffer+len, "MOP\n");
+
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+
+ if (pos > offset + length)
+ goto all_done;
+ }
+#endif /* CONFIG_DECNET_MOP */
+
+all_done:
+ sti();
+
+ *start = buffer + (offset - begin);
+ len -= (offset - begin);
+
+ if (len > length) len = length;
+
+ return(len);
+}
+#endif /* CONFIG_PROC_FS */
+
+void dn_raw_rx_nsp(struct sk_buff *skb)
+{
+ struct sock *sk;
+ struct sk_buff *skb2;
+ unsigned long cpuflags;
+
+ save_flags(cpuflags);
+ cli();
+ for(sk = dn_raw_nsp_sklist; sk != NULL; sk = sk->next) {
+ if (skb->len > sock_rspace(sk))
+ continue;
+ if (sk->dead)
+ continue;
+ if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
+ skb_set_owner_r(skb2, sk);
+ __skb_queue_tail(&sk->receive_queue, skb2);
+ sk->data_ready(sk, skb->len);
+ }
+ }
+ restore_flags(cpuflags);
+}
+
+void dn_raw_rx_routing(struct sk_buff *skb)
+{
+ struct sock *sk;
+ struct sk_buff *skb2;
+ struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
+ unsigned long cpuflags;
+ unsigned short rt_flagmask;
+ unsigned short objnamel;
+ struct dn_scp *scp;
+
+ save_flags(cpuflags);
+ cli();
+ for(sk = dn_raw_routing_sklist; sk != NULL; sk = sk->next) {
+ if (skb->len > sock_rspace(sk))
+ continue;
+ if (sk->dead)
+ continue;
+ scp = &sk->protinfo.dn;
+
+ rt_flagmask = *(unsigned short *)scp->addr.sdn_objname;
+ objnamel = dn_ntohs(scp->addr.sdn_objnamel);
+
+ if ((objnamel == 2) && (!((1 << (cb->rt_flags & 0x0f)) & rt_flagmask)))
+ continue;
+
+ if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
+ skb_set_owner_r(skb2, sk);
+ __skb_queue_tail(&sk->receive_queue, skb2);
+ sk->data_ready(sk, skb->len);
+ }
+ }
+ restore_flags(cpuflags);
+}
+
+#ifdef CONFIG_DECNET_MOP
+void dn_raw_rx_mop(struct sk_buff *skb)
+{
+ struct sock *sk;
+ struct sk_buff *skb2;
+ unsigned long cpuflags;
+
+ save_flags(cpuflags);
+ cli();
+ for(sk = dn_raw_mop_sklist; sk != NULL; sk = sk->next) {
+ if (skb->len > sock_rspace(sk))
+ continue;
+ if (sk->dead)
+ continue;
+ if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
+ skb_set_owner_r(skb2, sk);
+ __skb_queue_tail(&sk->receive_queue, skb2);
+ sk->data_ready(sk, skb->len);
+ }
+ }
+ restore_flags(cpuflags);
+}
+#endif /* CONFIG_DECNET_MOP */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)