/** * llc_lookup_dgram - Finds dgram socket for the local sap/mac * @sap: SAP * @laddr: address of local LLC (MAC + SAP) * * Search socket list of the SAP and finds connection using the local * mac, and local sap. Returns pointer for socket found, %NULL otherwise. */ static struct sock *llc_lookup_dgram(struct llc_sap *sap, const struct llc_addr *laddr) { struct sock *rc; struct hlist_nulls_node *node; int slot = llc_sk_laddr_hashfn(sap, laddr); struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot]; rcu_read_lock_bh(); again: sk_nulls_for_each_rcu(rc, node, laddr_hb) { if (llc_dgram_match(sap, laddr, rc)) { /* Extra checks required by SLAB_DESTROY_BY_RCU */ if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) goto again; if (unlikely(llc_sk(rc)->sap != sap || !llc_dgram_match(sap, laddr, rc))) { sock_put(rc); continue; } goto found; } } rc = NULL; /* * if the nulls value we got at the end of this lookup is * not the expected one, we must restart lookup. * We probably met an item that was moved to another chain. */ if (unlikely(get_nulls_value(node) != slot)) goto again; found: rcu_read_unlock_bh(); return rc; }
int display_bytes_array(void) { struct bytes tmp; int i; rcu_read_lock_bh(); tmp = *rcu_dereference(bytes_to_skip); if (!tmp.count) { log_info("Byte array list is empty"); goto end; } for (i = 0; i < tmp.count; i++) { if (i + 1 != tmp.count) printk("%u, ", tmp.array[i]); else printk("%u\n", tmp.array[i]); } log_info("Array length: %d", tmp.count); end: rcu_read_unlock_bh(); return 0; }
/* * N.B. The flags may be moved into the flowi at some future stage. */ static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *flp, int flags) { unsigned hash = dn_hash(flp->fld_src, flp->fld_dst); struct dn_route *rt = NULL; if (!(flags & MSG_TRYHARD)) { rcu_read_lock_bh(); for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt; rt = rcu_dereference(rt->u.rt_next)) { if ((flp->fld_dst == rt->fl.fld_dst) && (flp->fld_src == rt->fl.fld_src) && #ifdef CONFIG_DECNET_ROUTE_FWMARK (flp->fld_fwmark == rt->fl.fld_fwmark) && #endif (rt->fl.iif == 0) && (rt->fl.oif == flp->oif)) { rt->u.dst.lastuse = jiffies; dst_hold(&rt->u.dst); rt->u.dst.__use++; rcu_read_unlock_bh(); *pprt = &rt->u.dst; return 0; } } rcu_read_unlock_bh(); } return dn_route_output_slow(pprt, flp, flags); }
static int pcrypt_do_parallel(struct padata_priv *padata, unsigned int *cb_cpu, struct padata_pcrypt *pcrypt) { unsigned int cpu_index, cpu, i; struct pcrypt_cpumask *cpumask; cpu = *cb_cpu; rcu_read_lock_bh(); cpumask = rcu_dereference(pcrypt->cb_cpumask); if (cpumask_test_cpu(cpu, cpumask->mask)) goto out; if (!cpumask_weight(cpumask->mask)) goto out; cpu_index = cpu % cpumask_weight(cpumask->mask); cpu = cpumask_first(cpumask->mask); for (i = 0; i < cpu_index; i++) cpu = cpumask_next(cpu, cpumask->mask); *cb_cpu = cpu; out: rcu_read_unlock_bh(); return padata_do_parallel(pcrypt->pinst, padata, cpu); }
/* modelled after ip6_finish_output2 */ static int vrf_finish_output6(struct net *net, struct sock *sk, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct net_device *dev = dst->dev; struct neighbour *neigh; struct in6_addr *nexthop; int ret; skb->protocol = htons(ETH_P_IPV6); skb->dev = dev; rcu_read_lock_bh(); nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr); neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop); if (unlikely(!neigh)) neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false); if (!IS_ERR(neigh)) { ret = dst_neigh_output(dst, neigh, skb); rcu_read_unlock_bh(); return ret; } rcu_read_unlock_bh(); IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); kfree_skb(skb); return -EINVAL; }
/** * Copies this module's current configuration to "clone". * * @param[out] clone a copy of the current config will be placed here. Must be already allocated. * @return zero on success, nonzero on failure. */ int filtering_clone_config(struct filtering_config *clone) { rcu_read_lock_bh(); *clone = *rcu_dereference_bh(config); rcu_read_unlock_bh(); return 0; }
int flush_bytes_array(void) { struct bytes *tmp, *old; rcu_read_lock_bh(); if (!(rcu_dereference_bh(bytes_to_skip)->array)) { log_info("Byte array list is empty nothing to flush"); rcu_read_unlock_bh(); return 0; } rcu_read_unlock_bh(); tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) { log_err("Could not allocate struct bytes."); return -ENOMEM; } old = bytes_to_skip; *tmp = *bytes_to_skip; /* Delete. */ tmp->array = NULL; tmp->count = 0; rcu_assign_pointer(bytes_to_skip, tmp); synchronize_rcu_bh(); if (old->array) kfree(old->array); kfree(old); return 0; }
static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success) { struct vhost_net_ubuf_ref *ubufs = ubuf->ctx; struct vhost_virtqueue *vq = ubufs->vq; int cnt; rcu_read_lock_bh(); /* set len to mark this desc buffers done DMA */ vq->heads[ubuf->desc].len = success ? VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN; cnt = vhost_net_ubuf_put(ubufs); /* * Trigger polling thread if guest stopped submitting new buffers: * in this case, the refcount after decrement will eventually reach 1. * We also trigger polling periodically after each 16 packets * (the value 16 here is more or less arbitrary, it's tuned to trigger * less than 10% of times). */ if (cnt <= 1 || !(cnt % 16)) vhost_poll_queue(&vq->poll); rcu_read_unlock_bh(); }
/** * Use this function to safely obtain the configuration value which dictates whether IPv4 nodes * should be allowed to initiate conversations with IPv6 nodes. * * @return whether IPv4 nodes should be allowed to initiate conversations with IPv6 nodes. */ static bool drop_external_connections(void) { bool result; rcu_read_lock_bh(); result = rcu_dereference_bh(config)->drop_external_tcp; rcu_read_unlock_bh(); return result; }
/** * Use this function to safely obtain the configuration value which dictates whether Jool should * drop all informational ICMP packets that are traveling from IPv6 to IPv4. * * @return whether Jool should drop all ICMPv6 info packets. */ static bool filter_icmpv6_info(void) { bool result; rcu_read_lock_bh(); result = rcu_dereference_bh(config)->drop_icmp6_info; rcu_read_unlock_bh(); return result; }
/** * Use this function to safely obtain the configuration value which dictates whether Jool should * be applying "address-dependent filtering" (Look that up in the RFC). * * @return whether Jool should apply "address-dependent filtering". */ static bool address_dependent_filtering(void) { bool result; rcu_read_lock_bh(); result = rcu_dereference_bh(config)->drop_by_addr; rcu_read_unlock_bh(); return result; }
struct llc_sap *llc_sap_find(unsigned char sap_value) { struct llc_sap *sap; rcu_read_lock_bh(); sap = __llc_sap_find(sap_value); if (sap) llc_sap_hold(sap); rcu_read_unlock_bh(); return sap; }
static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label) { struct ip6_flowlabel *fl; rcu_read_lock_bh(); fl = __fl_lookup(net, label); if (fl && !atomic_inc_not_zero(&fl->users)) fl = NULL; rcu_read_unlock_bh(); return fl; }
static struct nfulnl_instance * instance_lookup_get(struct nfnl_log_net *log, u_int16_t group_num) { struct nfulnl_instance *inst; rcu_read_lock_bh(); inst = __instance_lookup(log, group_num); if (inst && !refcount_inc_not_zero(&inst->use)) inst = NULL; rcu_read_unlock_bh(); return inst; }
static struct nfulnl_instance * instance_lookup_get(u_int16_t group_num) { struct nfulnl_instance *inst; rcu_read_lock_bh(); inst = __instance_lookup(group_num); if (inst && !atomic_inc_not_zero(&inst->use)) inst = NULL; rcu_read_unlock_bh(); return inst; }
/** * padata_do_parallel - padata parallelization function * * @pinst: padata instance * @padata: object to be parallelized * @cb_cpu: cpu the serialization callback function will run on, * must be in the serial cpumask of padata(i.e. cpumask.cbcpu). * * The parallelization callback function will run with BHs off. * Note: Every object which is parallelized by padata_do_parallel * must be seen by padata_do_serial. */ int padata_do_parallel(struct padata_instance *pinst, struct padata_priv *padata, int cb_cpu) { int target_cpu, err; struct padata_parallel_queue *queue; struct parallel_data *pd; rcu_read_lock_bh(); pd = rcu_dereference(pinst->pd); err = -EINVAL; if (!(pinst->flags & PADATA_INIT) || pinst->flags & PADATA_INVALID) goto out; if (!cpumask_test_cpu(cb_cpu, pd->cpumask.cbcpu)) goto out; err = -EBUSY; if ((pinst->flags & PADATA_RESET)) goto out; if (atomic_read(&pd->refcnt) >= MAX_OBJ_NUM) goto out; err = 0; atomic_inc(&pd->refcnt); padata->pd = pd; padata->cb_cpu = cb_cpu; if (unlikely(atomic_read(&pd->seq_nr) == pd->max_seq_nr)) atomic_set(&pd->seq_nr, -1); padata->seq_nr = atomic_inc_return(&pd->seq_nr); target_cpu = padata_cpu_hash(padata); queue = per_cpu_ptr(pd->pqueue, target_cpu); spin_lock(&queue->parallel.lock); list_add_tail(&padata->list, &queue->parallel.list); spin_unlock(&queue->parallel.lock); queue_work_on(target_cpu, pinst->wq, &queue->work); out: rcu_read_unlock_bh(); return err; }
int sk_detach_filter(struct sock *sk) { int ret = -ENOENT; struct sk_filter *filter; rcu_read_lock_bh(); filter = rcu_dereference_bh(sk->sk_filter); if (filter) { rcu_assign_pointer(sk->sk_filter, NULL); sk_filter_delayed_uncharge(sk, filter); ret = 0; } rcu_read_unlock_bh(); return ret; }
void ieee80211_requeue(struct ieee80211_local *local, int queue) { struct netdev_queue *txq = netdev_get_tx_queue(local->mdev, queue); struct sk_buff_head list; spinlock_t *root_lock; struct Qdisc *qdisc; u32 len; rcu_read_lock_bh(); qdisc = rcu_dereference(txq->qdisc); if (!qdisc || !qdisc->dequeue) goto out_unlock; skb_queue_head_init(&list); root_lock = qdisc_root_lock(qdisc); spin_lock(root_lock); for (len = qdisc->q.qlen; len > 0; len--) { struct sk_buff *skb = qdisc->dequeue(qdisc); if (skb) __skb_queue_tail(&list, skb); } spin_unlock(root_lock); for (len = list.qlen; len > 0; len--) { struct sk_buff *skb = __skb_dequeue(&list); u16 new_queue; BUG_ON(!skb); new_queue = ieee80211_select_queue(local->mdev, skb); skb_set_queue_mapping(skb, new_queue); txq = netdev_get_tx_queue(local->mdev, new_queue); qdisc = rcu_dereference(txq->qdisc); root_lock = qdisc_root_lock(qdisc); spin_lock(root_lock); qdisc_enqueue_root(skb, qdisc); spin_unlock(root_lock); } out_unlock: rcu_read_unlock_bh(); }
/* modelled after ip_finish_output2 */ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct rtable *rt = (struct rtable *)dst; struct net_device *dev = dst->dev; unsigned int hh_len = LL_RESERVED_SPACE(dev); struct neighbour *neigh; u32 nexthop; int ret = -EINVAL; nf_reset(skb); /* Be paranoid, rather than too clever. */ if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { struct sk_buff *skb2; skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev)); if (!skb2) { ret = -ENOMEM; goto err; } if (skb->sk) skb_set_owner_w(skb2, skb->sk); consume_skb(skb); skb = skb2; } rcu_read_lock_bh(); nexthop = (__force u32)rt_nexthop(rt, ip_hdr(skb)->daddr); neigh = __ipv4_neigh_lookup_noref(dev, nexthop); if (unlikely(!neigh)) neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); if (!IS_ERR(neigh)) { sock_confirm_neigh(skb, neigh); ret = neigh_output(neigh, skb); rcu_read_unlock_bh(); return ret; } rcu_read_unlock_bh(); err: vrf_tx_error(skb->dev, skb); return ret; }
/** * sk_filter - run a packet through a socket filter * @sk: sock associated with &sk_buff * @skb: buffer to filter * * Run the filter code and then cut skb->data to correct size returned by * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller * than pkt_len we keep whole skb->data. This is the socket level * wrapper to sk_run_filter. It returns 0 if the packet should * be accepted or -EPERM if the packet should be tossed. * */ int sk_filter(struct sock *sk, struct sk_buff *skb) { int err; struct sk_filter *filter; err = security_sock_rcv_skb(sk, skb); if (err) return err; rcu_read_lock_bh(); filter = rcu_dereference_bh(sk->sk_filter); if (filter) { unsigned int pkt_len = SK_RUN_FILTER(filter, skb); err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; } rcu_read_unlock_bh(); return err; }
/* * For routers, this is called from dn_fib_dump, but for endnodes its * called directly from the rtnetlink dispatch table. */ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) { struct dn_route *rt; int h, s_h; int idx, s_idx; if (NLMSG_PAYLOAD(cb->nlh, 0) < sizeof(struct rtmsg)) return -EINVAL; if (!(((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)) return 0; s_h = cb->args[0]; s_idx = idx = cb->args[1]; for(h = 0; h <= dn_rt_hash_mask; h++) { if (h < s_h) continue; if (h > s_h) s_idx = 0; rcu_read_lock_bh(); for(rt = rcu_dereference(dn_rt_hash_table[h].chain), idx = 0; rt; rt = rcu_dereference(rt->u.rt_next), idx++) { if (idx < s_idx) continue; skb->dst = dst_clone(&rt->u.dst); if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1, NLM_F_MULTI) <= 0) { dst_release(xchg(&skb->dst, NULL)); rcu_read_unlock_bh(); goto done; } dst_release(xchg(&skb->dst, NULL)); } rcu_read_unlock_bh(); } done: cb->args[0] = h; cb->args[1] = idx; return skb->len; }
struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label) { struct ipv6_fl_socklist *sfl; struct ipv6_pinfo *np = inet6_sk(sk); label &= IPV6_FLOWLABEL_MASK; rcu_read_lock_bh(); for_each_sk_fl_rcu(np, sfl) { struct ip6_flowlabel *fl = sfl->fl; if (fl->label == label) { fl->lastuse = jiffies; atomic_inc(&fl->users); rcu_read_unlock_bh(); return fl; } } rcu_read_unlock_bh(); return NULL; }
bool skb_compare(struct sk_buff *expected, struct sk_buff *actual) { struct bytes *skip_byte; unsigned char *expected_ptr, *actual_ptr; unsigned int i, min_len, skip_count; int errors = 0; if (expected->len != actual->len) { print_error_table_hdr(errors); log_info(" Length\t%d\t %d", expected->len, actual->len); errors++; } expected_ptr = skb_network_header(expected); actual_ptr = skb_network_header(actual); min_len = (expected->len < actual->len) ? expected->len : actual->len; rcu_read_lock_bh(); skip_byte = rcu_dereference_bh(bytes_to_skip); skip_count = 0; for (i = 0; i < min_len; i++) { if (skip_count < skip_byte->count && skip_byte->array[skip_count] == i) { skip_count++; continue; } if (expected_ptr[i] != actual_ptr[i]) { print_error_table_hdr(errors); log_info(" byte %u\t0x%x\t 0x%x", i, expected_ptr[i], actual_ptr[i]); errors++; if (errors >= 8) break; } } rcu_read_unlock_bh(); return !errors; }
/** * sk_attach_filter - attach a socket filter * @fprog: the filter program * @sk: the socket to use * * Attach the user's filter code. We first run some sanity checks on * it to make sure it does not explode on us later. If an error * occurs or there is insufficient memory for the filter a negative * errno code is returned. On success the return is zero. */ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) { struct sk_filter *fp, *old_fp; unsigned int fsize = sizeof(struct sock_filter) * fprog->len; int err; /* Make sure new filter is there and in the right amounts. */ if (fprog->filter == NULL) return -EINVAL; fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL); if (!fp) return -ENOMEM; if (copy_from_user(fp->insns, fprog->filter, fsize)) { sock_kfree_s(sk, fp, fsize+sizeof(*fp)); return -EFAULT; } atomic_set(&fp->refcnt, 1); fp->len = fprog->len; fp->bpf_func = sk_run_filter; err = sk_chk_filter(fp->insns, fp->len); if (err) { sk_filter_uncharge(sk, fp); return err; } bpf_jit_compile(fp); rcu_read_lock_bh(); old_fp = rcu_dereference_bh(sk->sk_filter); rcu_assign_pointer(sk->sk_filter, fp); rcu_read_unlock_bh(); if (old_fp) sk_filter_delayed_uncharge(sk, old_fp); return 0; }
static struct neighbour *hwaddr_neighbour(struct rtable *rt, struct hwaddr_entry *entry) { #if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0) struct neighbour *neigh = rt->dst.neighbour; #else struct neighbour *neigh = NULL; __be32 next = 0; rcu_read_lock_bh(); next = rt_nexthop(rt, entry->h_remote); neigh = __ipv4_neigh_lookup_noref(rt->dst.dev, next); if (IS_ERR_OR_NULL(neigh)) neigh = __neigh_create(&arp_tbl, &next, rt->dst.dev, false); rcu_read_unlock_bh(); #endif if (IS_ERR(neigh)) return NULL; return neigh; }
static int vrf_finish_direct(struct net *net, struct sock *sk, struct sk_buff *skb) { struct net_device *vrf_dev = skb->dev; if (!list_empty(&vrf_dev->ptype_all) && likely(skb_headroom(skb) >= ETH_HLEN)) { struct ethhdr *eth = skb_push(skb, ETH_HLEN); ether_addr_copy(eth->h_source, vrf_dev->dev_addr); eth_zero_addr(eth->h_dest); eth->h_proto = skb->protocol; rcu_read_lock_bh(); dev_queue_xmit_nit(skb, vrf_dev); rcu_read_unlock_bh(); skb_pull(skb, ETH_HLEN); } return 1; }
static int mem_check(struct sock *sk) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_fl_socklist *sfl; int room = FL_MAX_SIZE - atomic_read(&fl_size); int count = 0; if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK) return 0; rcu_read_lock_bh(); for_each_sk_fl_rcu(np, sfl) count++; rcu_read_unlock_bh(); if (room <= 0 || ((count >= FL_MAX_PER_SOCK || (count > 0 && room < FL_MAX_SIZE/2) || room < FL_MAX_SIZE/4) && !capable(CAP_NET_ADMIN))) return -ENOBUFS; return 0; }
int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq, int flags) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_fl_socklist *sfl; if (flags & IPV6_FL_F_REMOTE) { freq->flr_label = np->rcv_flowinfo & IPV6_FLOWLABEL_MASK; return 0; } if (np->repflow) { freq->flr_label = np->flow_label; return 0; } rcu_read_lock_bh(); for_each_sk_fl_rcu(np, sfl) { if (sfl->fl->label == (np->flow_label & IPV6_FLOWLABEL_MASK)) { spin_lock_bh(&ip6_fl_lock); freq->flr_label = sfl->fl->label; freq->flr_dst = sfl->fl->dst; freq->flr_share = sfl->fl->share; freq->flr_expires = (sfl->fl->expires - jiffies) / HZ; freq->flr_linger = sfl->fl->linger / HZ; spin_unlock_bh(&ip6_fl_lock); rcu_read_unlock_bh(); return 0; } } rcu_read_unlock_bh(); return -ENOENT; }
/** * sk_filter - run a packet through a socket filter * @sk: sock associated with &sk_buff * @skb: buffer to filter * * Run the filter code and then cut skb->data to correct size returned by * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller * than pkt_len we keep whole skb->data. This is the socket level * wrapper to sk_run_filter. It returns 0 if the packet should * be accepted or -EPERM if the packet should be tossed. * */ int sk_filter(struct sock *sk, struct sk_buff *skb) { int err; struct sk_filter *filter; err = security_sock_rcv_skb(sk, skb); if (err) return err; err = provenance_sock_rcv_skb(sk, skb); if (err) return err; rcu_read_lock_bh(); filter = rcu_dereference(sk->sk_filter); if (filter) { unsigned int pkt_len = sk_run_filter(skb, filter->insns, filter->len); err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; } rcu_read_unlock_bh(); return err; }
unsigned int arpt_do_table(struct sk_buff *skb, unsigned int hook, const struct net_device *in, const struct net_device *out, struct xt_table *table) { static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); unsigned int verdict = NF_DROP; const struct arphdr *arp; bool hotdrop = false; struct arpt_entry *e, *back; const char *indev, *outdev; void *table_base; const struct xt_table_info *private; struct xt_target_param tgpar; if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return NF_DROP; indev = in ? in->name : nulldevname; outdev = out ? out->name : nulldevname; rcu_read_lock_bh(); private = rcu_dereference(table->private);