static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) { struct ip6_tnl_parm *p = &t->parms; int ret = 0; if (p->flags & IP6_TNL_F_CAP_XMIT) { struct net_device *ldev = NULL; if (p->link) ldev = dev_get_by_index(p->link); if (unlikely(!ipv6_chk_addr(&p->laddr, ldev, 0))) printk(KERN_WARNING "%s xmit: Local address not yet configured!\n", p->name); else if (!ipv6_addr_is_multicast(&p->raddr) && unlikely(ipv6_chk_addr(&p->raddr, NULL, 0))) printk(KERN_WARNING "%s xmit: Routing loop! " "Remote address found on this node!\n", p->name); else ret = 1; if (ldev) dev_put(ldev); } return ret; }
static int ipip_tunnel_init(struct device *dev) { struct device *tdev = NULL; struct ip_tunnel *tunnel; struct iphdr *iph; tunnel = (struct ip_tunnel*)dev->priv; iph = &tunnel->parms.iph; ipip_tunnel_init_gen(dev); if (iph->daddr) { struct rtable *rt; if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) { tdev = rt->u.dst.dev; ip_rt_put(rt); } dev->flags |= IFF_POINTOPOINT; } if (!tdev && tunnel->parms.link) tdev = dev_get_by_index(tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); dev->mtu = tdev->mtu - sizeof(struct iphdr); } dev->iflink = tunnel->parms.link; return 0; }
static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen) { struct inet6_ifaddr *ifp; struct inet6_dev *idev; struct device *dev; int scope; if ((dev = dev_get_by_index(ifindex)) == NULL) return -ENODEV; if ((idev = ipv6_get_idev(dev)) == NULL) return -ENXIO; scope = ipv6_addr_scope(pfx); for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) { if (ifp->scope == scope && ifp->prefix_len == plen && (!memcmp(pfx, &ifp->addr, sizeof(struct in6_addr)))) { ipv6_del_addr(ifp); /* If the last address is deleted administratively, disable IPv6 on this interface. */ if (idev->addr_list == NULL) addrconf_ifdown(idev->dev, 1); return 0; } } return -EADDRNOTAVAIL; }
static void ip6_frag_expire(unsigned long data) { struct frag_queue *fq = (struct frag_queue *) data; spin_lock(&fq->lock); if (fq->last_in & COMPLETE) goto out; fq_kill(fq); IP6_INC_STATS_BH(Ip6ReasmTimeout); IP6_INC_STATS_BH(Ip6ReasmFails); /* Send error only if the first segment arrived. */ if (fq->last_in&FIRST_IN && fq->fragments) { struct net_device *dev = dev_get_by_index(fq->iif); /* But use as source device on which LAST ARRIVED segment was received. And do not use fq->dev pointer directly, device might already disappeared. */ if (dev) { fq->fragments->dev = dev; icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); dev_put(dev); } } out: spin_unlock(&fq->lock); fq_put(fq); }
/* * Manual configuration of address on an interface */ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen) { struct inet6_ifaddr *ifp; struct inet6_dev *idev; struct device *dev; int scope; if ((dev = dev_get_by_index(ifindex)) == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) return -ENETDOWN; if ((idev = addrconf_add_dev(dev)) == NULL) return -ENOBUFS; scope = ipv6_addr_scope(pfx); if ((ifp = ipv6_add_addr(idev, pfx, scope)) == NULL) return -ENOMEM; ifp->prefix_len = plen; ifp->flags |= ADDR_PERMANENT; addrconf_dad_start(ifp); return 0; }
static inline bool copy_to_dev_skbs(struct pfq_sock *so, struct gc_queue_buff *queue, unsigned long long mask, int cpu, int gid) { if (so->egress_index) { struct net_device *dev; bool ret; dev = dev_get_by_index(&init_net, so->egress_index); if (dev == NULL) { if (printk_ratelimit()) { printk(KERN_INFO "[PFQ] egress endpoint index (%d)\n", so->egress_index); return false; } } ret = pfq_lazy_queue_xmit_by_mask(queue, mask, dev, so->egress_queue); dev_put(dev); return ret != 0; } return false; }
static int raw_release(struct socket *sock) { struct sock *sk = sock->sk; struct raw_opt *ro = raw_sk(sk); struct net_device *dev = NULL; DBG("socket %p, sk %p, refcnt %d\n", sock, sk, atomic_read(&sk->sk_refcnt)); if (ro->bound && ro->ifindex) dev = dev_get_by_index(ro->ifindex); /* remove current filters & unregister */ if (ro->bound) raw_remove_filters(dev, sk); if (ro->count > 1) kfree(ro->filter); /* remove current error mask */ if (ro->err_mask && ro->bound) can_rx_unregister(dev, 0, ro->err_mask | CAN_ERR_FLAG, raw_rcv, sk); if (dev) { can_dev_unregister(dev, raw_notifier, sk); dev_put(dev); } sock_put(sk); return 0; }
static int packet_mc_drop(struct sock *sk, struct packet_mreq *mreq) { struct packet_mclist *ml, **mlp; rtnl_lock(); for (mlp = &pkt_sk(sk)->mclist; (ml = *mlp) != NULL; mlp = &ml->next) { if (ml->ifindex == mreq->mr_ifindex && ml->type == mreq->mr_type && ml->alen == mreq->mr_alen && memcmp(ml->addr, mreq->mr_address, ml->alen) == 0) { if (--ml->count == 0) { struct net_device *dev; *mlp = ml->next; dev = dev_get_by_index(ml->ifindex); if (dev) { packet_dev_mc(dev, ml, -1); dev_put(dev); } kfree(ml); } rtnl_unlock(); return 0; } } rtnl_unlock(); return -EADDRNOTAVAIL; }
static int packet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct net_device *dev; struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr; if (peer) return -EOPNOTSUPP; sll->sll_family = AF_PACKET; sll->sll_ifindex = po->ifindex; sll->sll_protocol = po->num; dev = dev_get_by_index(po->ifindex); if (dev) { sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; memcpy(sll->sll_addr, dev->dev_addr, dev->addr_len); dev_put(dev); } else { sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ sll->sll_halen = 0; } *uaddr_len = sizeof(*sll); return 0; }
/* Requests from userspace */ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) { struct net_device *dev; if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { char name[IFNAMSIZ + 1]; nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], sizeof(name)); dev = dev_get_by_name(&init_net, name); } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) { dev = dev_get_by_index(&init_net, nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); } else { return NULL; } if (!dev) return NULL; /* Check on mtu is currently a hacked solution because lowpan * and wpan have the same ARPHRD type. */ if (dev->type != ARPHRD_IEEE802154 || dev->mtu != IEEE802154_MTU) { dev_put(dev); return NULL; } return dev; }
void ipv6_sock_mc_close(struct sock *sk) { struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; struct ipv6_mc_socklist *mc_lst; MDBG3((KERN_DEBUG "ipv6_sock_mc_close(sk=%p)\n", sk)); write_lock_bh(&ipv6_sk_mc_lock); while ((mc_lst = np->ipv6_mc_list) != NULL) { struct net_device *dev; np->ipv6_mc_list = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); dev = dev_get_by_index(mc_lst->ifindex); if (dev) { ipv6_dev_mc_dec(dev, &mc_lst->addr); dev_put(dev); } sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); write_lock_bh(&ipv6_sk_mc_lock); } write_unlock_bh(&ipv6_sk_mc_lock); }
/* * Oops, a fragment queue timed out. Kill it and send an ICMP reply. */ static void ip_expire(unsigned long arg) { struct ipq *qp; struct net *net; qp = container_of((struct inet_frag_queue *) arg, struct ipq, q); net = container_of(qp->q.net, struct net, ipv4.frags); spin_lock(&qp->q.lock); if (qp->q.last_in & INET_FRAG_COMPLETE) goto out; ipq_kill(qp); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { struct sk_buff *head = qp->q.fragments; /* Send an ICMP "Fragment Reassembly Timeout" message. */ if ((head->dev = dev_get_by_index(net, qp->iif)) != NULL) { icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); dev_put(head->dev); } } out: spin_unlock(&qp->q.lock); ipq_put(qp); }
/** * mipv6_mn_send_home_na - send NA when returning home * @haddr: home address to advertise * * After returning home, MN must advertise all its valid addresses in * home link to all nodes. **/ void mipv6_mn_send_home_na(struct in6_addr *haddr) { struct net_device *dev = NULL; struct in6_addr mc_allnodes; struct mn_info *hinfo = NULL; read_lock_bh(&mn_info_lock); hinfo = mipv6_mn_get_info(haddr); hinfo->is_at_home = 1; if (!hinfo) { read_unlock_bh(&mn_info_lock); return; } dev = dev_get_by_index(hinfo->ifindex); read_unlock_bh(&mn_info_lock); if (dev == NULL) { DEBUG((DBG_ERROR, "Send home_na: device not found.")); return; } ipv6_addr_all_nodes(&mc_allnodes); if (ipv6_get_lladdr(dev, haddr) == 0) ndisc_send_na(dev, NULL, &mc_allnodes, haddr, 0, 0, 1, 1); ndisc_send_na(dev, NULL, &mc_allnodes, haddr, 0, 0, 1, 1); dev_put(dev); }
/* * socket leave on multicast group */ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) { struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; struct ipv6_mc_socklist *mc_lst, **lnk; #ifdef CONFIG_IPV6_MLD6_DEBUG char abuf[128]; in6_ntop(addr, abuf); MDBG3((KERN_DEBUG "ipv6_sock_mc_drop(sk=%p, ifindex=%d, addr=%s)\n", sk, ifindex, abuf)); #endif write_lock_bh(&ipv6_sk_mc_lock); for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { if ((ifindex == 0 || mc_lst->ifindex == ifindex) && ipv6_addr_cmp(&mc_lst->addr, addr) == 0) { struct net_device *dev; *lnk = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); /* Note: mc_lst->ifindex != 0 */ if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) { ipv6_dev_mc_dec(dev, &mc_lst->addr); dev_put(dev); } sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); return 0; } } write_unlock_bh(&ipv6_sk_mc_lock); return -ENOENT; }
static void netlink_rcv_cb(struct sk_buff *skb) { struct nlmsghdr *nlh; struct net_device *dev; u32 mlen; void *msg; int ifindex; if (skb->len >= NLMSG_SPACE(0)) { nlh = (struct nlmsghdr *)skb->data; if (skb->len < nlh->nlmsg_len || nlh->nlmsg_len > ND_MAX_MSG_LEN) { printk(KERN_ERR "Invalid length (%d,%d)\n", skb->len, nlh->nlmsg_len); return; } memcpy(&ifindex, ND_NLMSG_IFIDX(nlh), ND_IFINDEX_LEN); msg = ND_NLMSG_DATA(nlh); mlen = ND_NLMSG_R_LEN(nlh); if (rcv_cb) { dev = dev_get_by_index(&init_net, ifindex); if (dev) { rcv_cb(dev, nlh->nlmsg_type, msg, mlen); dev_put(dev); } else printk(KERN_ERR "dev_get_by_index(%d) " "is not found.\n", ifindex); } else printk(KERN_ERR "Unregistered Callback\n"); } }
/** * mipv6_mn_move_homeaddr - Move home address from one interface to another. * @ifindex: interface index to which home address is moved * @haddr: home address * * When an interface is stopped home addresses on that if need to be * moved to another interface. **/ int mipv6_mn_move_homeaddr(int ifindex, struct in6_addr *haddr) { struct in6_ifreq ifreq; #ifdef CONFIG_IPV6_MOBILITY_DEBUG struct net_device *dev = NULL; #endif DEBUG_FUNC(); /* TODO!! */ ifreq.ifr6_prefixlen = 64; ipv6_addr_copy(&ifreq.ifr6_addr, haddr); addrconf_del_ifaddr((void *)&ifreq); ifreq.ifr6_ifindex = ifindex; addrconf_add_ifaddr((void *)&ifreq); #ifdef CONFIG_IPV6_MOBILITY_DEBUG dev = dev_get_by_index(ifindex); if (dev) { DEBUG((DBG_INFO, "Moved HA to %s", dev->name)); dev_put(dev); } #endif return 0; }
bool copy_to_endpoint_skbs(struct pfq_sock *so, struct pfq_non_intrusive_skb *skbs, unsigned long long skbs_mask, int cpu, int gid) { if (so->egress_index) { struct net_device *dev; struct sk_buff *skb; bool ret; int n; pfq_non_intrusive_for_each(skb, n, skbs) { atomic_inc(&skb->users); } dev = dev_get_by_index(&init_net, so->egress_index); if (dev == NULL) { if (printk_ratelimit()) { printk(KERN_INFO "[PFQ] egress endpoint index (%d)\n", so->egress_index); return false; } } ret = pfq_queue_xmit_by_mask(skbs, skbs_mask, dev, so->egress_queue); dev_put(dev); return ret; }
static int raw_release(struct socket *sock) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); unregister_netdevice_notifier(&ro->notifier); lock_sock(sk); /* remove current filters & unregister */ if (ro->bound) { if (ro->ifindex) { struct net_device *dev; dev = dev_get_by_index(&init_net, ro->ifindex); if (dev) { raw_disable_allfilters(dev, sk); dev_put(dev); } } else raw_disable_allfilters(NULL, sk); } if (ro->count > 1) kfree(ro->filter); ro->ifindex = 0; ro->bound = 0; ro->count = 0; release_sock(sk); sock_put(sk); return 0; }
/* * socket leave on multicast group */ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) { struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; struct ipv6_mc_socklist *mc_lst, **lnk; write_lock_bh(&ipv6_sk_mc_lock); for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { if (mc_lst->ifindex == ifindex && ipv6_addr_cmp(&mc_lst->addr, addr) == 0) { struct net_device *dev; *lnk = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); if ((dev = dev_get_by_index(ifindex)) != NULL) { ipv6_dev_mc_dec(dev, &mc_lst->addr); dev_put(dev); } sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); return 0; } } write_unlock_bh(&ipv6_sk_mc_lock); return -ENOENT; }
void ipv6_sock_ac_close(struct sock *sk) { struct ipv6_pinfo *np = inet6_sk(sk); struct net_device *dev = NULL; struct ipv6_ac_socklist *pac; int prev_index; write_lock_bh(&ipv6_sk_ac_lock); pac = np->ipv6_ac_list; np->ipv6_ac_list = NULL; write_unlock_bh(&ipv6_sk_ac_lock); prev_index = 0; while (pac) { struct ipv6_ac_socklist *next = pac->acl_next; if (pac->acl_ifindex != prev_index) { if (dev) dev_put(dev); dev = dev_get_by_index(&init_net, pac->acl_ifindex); prev_index = pac->acl_ifindex; } if (dev) ipv6_dev_ac_dec(dev, &pac->acl_addr); sock_kfree_s(sk, pac, sizeof(*pac)); pac = next; } if (dev) dev_put(dev); }
/* * socket leave an anycast group */ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr) { struct ipv6_pinfo *np = inet6_sk(sk); struct net_device *dev; struct ipv6_ac_socklist *pac, *prev_pac; write_lock_bh(&ipv6_sk_ac_lock); prev_pac = NULL; for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { if ((ifindex == 0 || pac->acl_ifindex == ifindex) && ipv6_addr_equal(&pac->acl_addr, addr)) break; prev_pac = pac; } if (!pac) { write_unlock_bh(&ipv6_sk_ac_lock); return -ENOENT; } if (prev_pac) prev_pac->acl_next = pac->acl_next; else np->ipv6_ac_list = pac->acl_next; write_unlock_bh(&ipv6_sk_ac_lock); dev = dev_get_by_index(&init_net, pac->acl_ifindex); if (dev) { ipv6_dev_ac_dec(dev, &pac->acl_addr); dev_put(dev); } sock_kfree_s(sk, pac, sizeof(*pac)); return 0; }
/* Requests from userspace */ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) { struct net_device *dev; if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { char name[IFNAMSIZ + 1]; nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], sizeof(name)); dev = dev_get_by_name(&init_net, name); } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) dev = dev_get_by_index(&init_net, nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); else return NULL; if (!dev) return NULL; if (dev->type != ARPHRD_IEEE802154) { dev_put(dev); return NULL; } return dev; }
static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr; struct sock *sk=sock->sk; struct net_device *dev = NULL; int err; /* * Check legality */ if (addr_len < sizeof(struct sockaddr_ll)) return -EINVAL; if (sll->sll_family != AF_PACKET) return -EINVAL; if (sll->sll_ifindex) { err = -ENODEV; dev = dev_get_by_index(sll->sll_ifindex); if (dev == NULL) goto out; } err = packet_do_bind(sk, dev, sll->sll_protocol ? : pkt_sk(sk)->num); if (dev) dev_put(dev); out: return err; }
/* * Create a Phonet header for the skb and send it out. Returns * non-zero error code if failed. The skb is freed then. */ int pn_skb_send(struct sock *sk, struct sk_buff *skb, const struct sockaddr_pn *target) { struct net *net = sock_net(sk); struct net_device *dev; struct pn_sock *pn = pn_sk(sk); int err; u16 src, dst; u8 daddr, saddr, res; src = pn->sobject; if (target != NULL) { dst = pn_sockaddr_get_object(target); res = pn_sockaddr_get_resource(target); } else { dst = pn->dobject; res = pn->resource; } daddr = pn_addr(dst); err = -EHOSTUNREACH; if (sk->sk_bound_dev_if) dev = dev_get_by_index(net, sk->sk_bound_dev_if); else if (phonet_address_lookup(net, daddr) == 0) { dev = phonet_device_get(net); skb->pkt_type = PACKET_LOOPBACK; } else if (dst == 0) { /* Resource routing (small race until phonet_rcv()) */ struct sock *sk = pn_find_sock_by_res(net, res); if (sk) { sock_put(sk); dev = phonet_device_get(net); skb->pkt_type = PACKET_LOOPBACK; } else dev = phonet_route_output(net, daddr); } else dev = phonet_route_output(net, daddr); if (!dev || !(dev->flags & IFF_UP)) goto drop; saddr = phonet_address_get(dev, daddr); if (saddr == PN_NO_ADDR) goto drop; if (!pn_addr(src)) src = pn_object(saddr, pn_obj(src)); err = pn_send(skb, dev, dst, src, res, 0); dev_put(dev); return err; drop: printk(KERN_DEBUG "pn_skb_send DROP\n"); kfree_skb(skb); if (dev) dev_put(dev); return err; }
static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); struct sk_buff *skb; struct net_device *dev; int ifindex; int err; if (msg->msg_name) { struct sockaddr_can *addr = (struct sockaddr_can *)msg->msg_name; if (addr->can_family != AF_CAN) return -EINVAL; ifindex = addr->can_ifindex; } else ifindex = ro->ifindex; if (size != sizeof(struct can_frame)) return -EINVAL; dev = dev_get_by_index(&init_net, ifindex); if (!dev) return -ENXIO; skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) goto put_dev; err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); if (err < 0) goto free_skb; err = sock_tx_timestamp(msg, sk, skb_tx(skb)); if (err < 0) goto free_skb; skb->dev = dev; skb->sk = sk; err = can_send(skb, ro->loopback); dev_put(dev); if (err) goto send_failed; return size; free_skb: kfree_skb(skb); put_dev: dev_put(dev); send_failed: return err; }
static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { struct ifinfomsg *ifm; struct nlattr *tb[IFLA_MAX+1]; struct net_device *dev = NULL; struct sk_buff *nskb; char *iw_buf = NULL, *iw = NULL; int iw_buf_len = 0; int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); if (err < 0) return err; ifm = nlmsg_data(nlh); if (ifm->ifi_index >= 0) { dev = dev_get_by_index(ifm->ifi_index); if (dev == NULL) return -ENODEV; } else return -EINVAL; #ifdef CONFIG_NET_WIRELESS_RTNETLINK if (tb[IFLA_WIRELESS]) { /* Call Wireless Extensions. We need to know the size before * we can alloc. Various stuff checked in there... */ err = wireless_rtnetlink_get(dev, nla_data(tb[IFLA_WIRELESS]), nla_len(tb[IFLA_WIRELESS]), &iw_buf, &iw_buf_len); if (err < 0) goto errout; iw += IW_EV_POINT_OFF; } #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL); if (nskb == NULL) { err = -ENOBUFS; goto errout; } err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0); if (err < 0) { /* -EMSGSIZE implies BUG in if_nlmsg_size */ WARN_ON(err == -EMSGSIZE); kfree_skb(nskb); goto errout; } err = rtnl_unicast(nskb, NETLINK_CB(skb).pid); errout: kfree(iw_buf); dev_put(dev); return err; }
/* This cleans up af_inet6 a bit. -DaveM */ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr; __u32 v4addr = 0; int addr_type; /* Check these errors. */ if (sk->state != TCP_CLOSE || (addr_len < sizeof(struct sockaddr_in6))) return -EINVAL; addr_type = ipv6_addr_type(&addr->sin6_addr); /* Check if the address belongs to the host. */ if (addr_type == IPV6_ADDR_MAPPED) { /* Raw sockets are IPv6 only */ return(-EADDRNOTAVAIL); } else { if (addr_type != IPV6_ADDR_ANY) { if (addr_type & IPV6_ADDR_LINKLOCAL) { if (addr_len >= sizeof(struct sockaddr_in6) && addr->sin6_scope_id) { /* Override any existing binding, * if another one is supplied by user. */ sk->bound_dev_if = addr->sin6_scope_id; } /* Binding to link-local address requires an interface */ if (!sk->bound_dev_if) return(-EINVAL); if (!dev_get_by_index(sk->bound_dev_if)) return(-ENODEV); } /* ipv4 addr of the socket is invalid. Only the * unpecified and mapped address have a v4 equivalent. */ v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { if (ipv6_chk_addr(&addr->sin6_addr, NULL, 0) == NULL) return(-EADDRNOTAVAIL); } } } sk->rcv_saddr = v4addr; sk->saddr = v4addr; memcpy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr, sizeof(struct in6_addr)); if (!(addr_type & IPV6_ADDR_MULTICAST)) memcpy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr, sizeof(struct in6_addr)); return 0; }
int mgt_response( unsigned int src_id, unsigned int src_seq, unsigned int dev_type, unsigned int dev_seq, unsigned int op, int oid, void *data, unsigned long len) { int i; int err = 0; struct net_device *dev; struct resp_rec *pr; mgt_response_t resp_oid = NULL; mgt_response_t resp_def = NULL; #ifdef DRIVER_DEBUG printk (KERN_ERR "mgt_response(%d, %d, %d, %d, %d, %x, <data>, %d)\n", src_id, src_seq, dev_type, dev_seq, op, oid, (unsigned int)len ); #endif if ( mgt_resp_table_init != -1 ) { if ( ! (dev = dev_get_by_index( dev_seq ) ) ) return -1; for ( i = 0, pr = resp_table; ( pr->resp != NULL ) && ( i < RESP_TABLE_SZ ); i++, pr++ ) { if ( ( pr->src_seq == 0 ) && ( strncmp ( pr->name, dev->name, IFNAMSIZ ) == 0 ) ) { mgt_resp_table_init++; pr->src_seq = dev_seq; } } if ( i == mgt_resp_table_init ) { mgt_resp_table_init = -1; } dev_put( dev ); } for ( i = 0, pr = resp_table; i < RESP_TABLE_SZ; i++, pr++ ) { if ( ( pr->src_id == src_id ) && ( pr->src_seq == src_seq ) && ( pr->resp != NULL ) ) { if ( pr->oid == oid ) { resp_oid = pr->resp; break; } else if ( pr->oid == 0 ) { resp_def = pr->resp; } } } /* only one response allowed (indication); specific handlers have priority over default handler */ if ( resp_oid ) { if ( (*resp_oid)( src_id, src_seq, dev_type, dev_seq, op, oid, data, len ) < 0) err = -EPFNOSUPPORT; } else if ( cnf_hndl ) { if ( ( *cnf_hndl )( src_id, src_seq, dev_type, dev_seq, op, oid, data, len ) < 0 ) err = -EPFNOSUPPORT; } return err; }
int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) { struct net_device *dev = NULL; struct ipv6_mc_socklist *mc_lst; struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; int err; if (!(ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST)) return -EINVAL; mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL); if (mc_lst == NULL) return -ENOMEM; mc_lst->next = NULL; memcpy(&mc_lst->addr, addr, sizeof(struct in6_addr)); mc_lst->ifindex = ifindex; if (ifindex == 0) { struct rt6_info *rt; rt = rt6_lookup(addr, NULL, 0, 0); if (rt) { dev = rt->rt6i_dev; dev_hold(dev); dst_release(&rt->u.dst); } } else dev = dev_get_by_index(ifindex); if (dev == NULL) { sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); return -ENODEV; } /* * now add/increase the group membership on the device */ err = ipv6_dev_mc_inc(dev, addr); if (err) { sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); dev_put(dev); return err; } write_lock_bh(&ipv6_sk_mc_lock); mc_lst->next = np->ipv6_mc_list; np->ipv6_mc_list = mc_lst; write_unlock_bh(&ipv6_sk_mc_lock); dev_put(dev); return 0; }
static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size) { struct sock *sk = sock->sk; struct raw_opt *ro = raw_sk(sk); struct sk_buff *skb; struct net_device *dev; int ifindex; int err; DBG("socket %p, sk %p\n", sock, sk); if (msg->msg_name) { struct sockaddr_can *addr = (struct sockaddr_can *)msg->msg_name; if (addr->can_family != AF_CAN) return -EINVAL; ifindex = addr->can_ifindex; } else ifindex = ro->ifindex; dev = dev_get_by_index(ifindex); if (!dev) { DBG("device %d not found\n", ifindex); return -ENXIO; } skb = alloc_skb(size, GFP_KERNEL); if (!skb) { dev_put(dev); return -ENOMEM; } err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); if (err < 0) { kfree_skb(skb); dev_put(dev); return err; } skb->dev = dev; skb->sk = sk; DBG("sending skbuff to interface %d\n", ifindex); DBG_SKB(skb); err = can_send(skb, ro->loopback); dev_put(dev); if (err) return err; return size; }