static int packet_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { char name[15]; struct device *dev; /* * Check legality */ if(addr_len!=sizeof(struct sockaddr)) return -EINVAL; strncpy(name,uaddr->sa_data,14); name[14]=0; /* * Lock the device chain while we sanity check * the bind request. */ dev_lock_list(); dev=dev_get(name); if(dev==NULL) { dev_unlock_list(); return -ENODEV; } if(!(dev->flags&IFF_UP)) { dev_unlock_list(); return -ENETDOWN; } /* * Perform the request. */ memcpy(sk->protinfo.af_packet.device_name,name,15); /* * Rewrite an existing hook if present. */ if(sk->protinfo.af_packet.prot_hook) { dev_remove_pack(sk->protinfo.af_packet.prot_hook); sk->protinfo.af_packet.prot_hook->dev=dev; sk->protinfo.af_packet.bound_dev=dev; dev_add_pack(sk->protinfo.af_packet.prot_hook); } else { int err=packet_attach(sk, dev); if(err) { dev_unlock_list(); return err; } } /* * Now the notifier is set up right this lot is safe. */ dev_unlock_list(); return 0; }
static int econet_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) { struct sock *sk = sock->sk; struct sockaddr_ec *saddr=(struct sockaddr_ec *)msg->msg_name; struct device *dev; struct ec_addr addr; struct ec_device *edev; int err; unsigned char port, cb; struct sk_buff *skb; struct ec_cb *eb; #ifdef CONFIG_ECONET_NATIVE unsigned short proto = 0; #endif #ifdef CONFIG_ECONET_AUNUDP struct msghdr udpmsg; struct iovec iov[msg->msg_iovlen+1]; struct aunhdr ah; struct sockaddr_in udpdest; __kernel_size_t size; int i; mm_segment_t oldfs; #endif /* * Check the flags. */ if (msg->msg_flags&~MSG_DONTWAIT) return(-EINVAL); /* * Get and verify the address. */ if (saddr == NULL) { addr.station = sk->protinfo.af_econet->station; addr.net = sk->protinfo.af_econet->net; port = sk->protinfo.af_econet->port; cb = sk->protinfo.af_econet->cb; } else { if (msg->msg_namelen < sizeof(struct sockaddr_ec)) return -EINVAL; addr.station = saddr->addr.station; addr.net = saddr->addr.net; port = saddr->port; cb = saddr->cb; } /* Look for a device with the right network number. */ for (edev = edevlist; edev && (edev->net != addr.net); edev = edev->next); /* Bridge? What's that? */ if (edev == NULL) return -ENETUNREACH; dev = edev->dev; if (dev->type == ARPHRD_ECONET) { /* Real hardware Econet. We're not worthy etc. */ #ifdef CONFIG_ECONET_NATIVE dev_lock_list(); skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, msg->msg_flags & MSG_DONTWAIT, &err); if (skb==NULL) goto out_unlock; skb_reserve(skb, (dev->hard_header_len+15)&~15); skb->nh.raw = skb->data; eb = (struct ec_cb *)&skb->cb; eb->cookie = saddr->cookie; eb->sec = *saddr; eb->sent = ec_tx_done; if (dev->hard_header) { int res; err = -EINVAL; res = dev->hard_header(skb, dev, ntohs(proto), &addr, NULL, len); if (sock->type != SOCK_DGRAM) { skb->tail = skb->data; skb->len = 0; } else if (res < 0) goto out_free; } /* Copy the data. Returns -EFAULT on error */ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); skb->protocol = proto; skb->dev = dev; skb->priority = sk->priority; if (err) goto out_free; err = -ENETDOWN; if (!(dev->flags & IFF_UP)) goto out_free; /* * Now send it */ dev_unlock_list(); dev_queue_xmit(skb); return(len); out_free: kfree_skb(skb); out_unlock: dev_unlock_list(); #else err = -EPROTOTYPE; #endif return err; } #ifdef CONFIG_ECONET_AUNUDP /* AUN virtual Econet. */ if (udpsock == NULL) return -ENETDOWN; /* No socket - can't send */ /* Make up a UDP datagram and hand it off to some higher intellect. */ memset(&udpdest, 0, sizeof(udpdest)); udpdest.sin_family = AF_INET; udpdest.sin_port = htons(AUN_PORT); /* At the moment we use the stupid Acorn scheme of Econet address y.x maps to IP a.b.c.x. This should be replaced with something more flexible and more aware of subnet masks. */ { struct in_device *idev = (struct in_device *)dev->ip_ptr; unsigned long network = ntohl(idev->ifa_list->ifa_address) & 0xffffff00; /* !!! */ udpdest.sin_addr.s_addr = htonl(network | addr.station); } ah.port = port; ah.cb = cb & 0x7f; ah.code = 2; /* magic */ ah.pad = 0; /* tack our header on the front of the iovec */ size = sizeof(struct aunhdr); iov[0].iov_base = (void *)&ah; iov[0].iov_len = size; for (i = 0; i < msg->msg_iovlen; i++) { void *base = msg->msg_iov[i].iov_base; size_t len = msg->msg_iov[i].iov_len; /* Check it now since we switch to KERNEL_DS later. */ if ((err = verify_area(VERIFY_READ, base, len)) < 0) return err; iov[i+1].iov_base = base; iov[i+1].iov_len = len; size += len; } /* Get a skbuff (no data, just holds our cb information) */ if ((skb = sock_alloc_send_skb(sk, 0, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; eb = (struct ec_cb *)&skb->cb; eb->cookie = saddr->cookie; eb->timeout = (5*HZ); eb->start = jiffies; ah.handle = aun_seq; eb->seq = (aun_seq++); eb->sec = *saddr; skb_queue_tail(&aun_queue, skb); udpmsg.msg_name = (void *)&udpdest; udpmsg.msg_namelen = sizeof(udpdest); udpmsg.msg_iov = &iov[0]; udpmsg.msg_iovlen = msg->msg_iovlen + 1; udpmsg.msg_control = NULL; udpmsg.msg_controllen = 0; udpmsg.msg_flags=0; oldfs = get_fs(); set_fs(KERNEL_DS); /* More privs :-) */ err = sock_sendmsg(udpsock, &udpmsg, size); set_fs(oldfs); #else err = -EPROTOTYPE; #endif return err; }