static int __init br_init(void) { int err; br_stp_sap = llc_sap_open(LLC_SAP_BSPAN, br_stp_rcv); if (!br_stp_sap) { printk(KERN_ERR "bridge: can't register sap for STP\n"); return -EADDRINUSE; } br_fdb_init(); err = br_netfilter_init(); if (err) goto err_out1; err = register_netdevice_notifier(&br_device_notifier); if (err) goto err_out2; br_netlink_init(); brioctl_set(br_ioctl_deviceless_stub); br_handle_frame_hook = br_handle_frame; br_fdb_get_hook = br_fdb_get; br_fdb_put_hook = br_fdb_put; return 0; err_out2: br_netfilter_fini(); err_out1: llc_sap_put(br_stp_sap); return err; }
/** * llc_sap_remove_socket - removes a socket from SAP * @sap: SAP * @sk: socket * * This function removes a connection from the hash tables of a SAP if * the connection was in this list. */ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) { struct llc_sock *llc = llc_sk(sk); spin_lock_bh(&sap->sk_lock); sk_nulls_del_node_init_rcu(sk); hlist_del(&llc->dev_hash_node); sap->sk_count--; spin_unlock_bh(&sap->sk_lock); llc_sap_put(sap); }
void stp_proto_unregister(const struct stp_proto *proto) { mutex_lock(&stp_proto_mutex); if (is_zero_ether_addr(proto->group_address)) rcu_assign_pointer(stp_proto, NULL); else rcu_assign_pointer(garp_protos[proto->group_address[5] - GARP_ADDR_MIN], NULL); synchronize_rcu(); if (--sap_registered == 0) llc_sap_put(sap); mutex_unlock(&stp_proto_mutex); }
static int __init br_init(void) { int err; br_stp_sap = llc_sap_open(LLC_SAP_BSPAN, br_stp_rcv); if (!br_stp_sap) { printk(KERN_ERR "bridge: can't register sap for STP\n"); return -EADDRINUSE; } //网桥数据库初始化,分配slab缓冲区 err = br_fdb_init(); if (err) goto err_out; //netfilter钩子初始 err = br_netfilter_init(); if (err) goto err_out1; ////在netdev_chain通知链表上注册 err = register_netdevice_notifier(&br_device_notifier); if (err) goto err_out2; err = br_netlink_init(); if (err) goto err_out3; //设置ioctl钩子函数:br_ioctl_hook //通过brctl addbr br0命令建立网桥,此处用户空间调用的brctl命令最终对应到内核中的br_ioctl_deviceless_stub处理函数 brioctl_set(br_ioctl_deviceless_stub); //设置报文处理钩子函数 br_handle_frame_hook = br_handle_frame; //网桥数据库处理钩子 br_fdb_get_hook = br_fdb_get; br_fdb_put_hook = br_fdb_put; return 0; err_out3: unregister_netdevice_notifier(&br_device_notifier); err_out2: br_netfilter_fini(); err_out1: br_fdb_fini(); err_out: llc_sap_put(br_stp_sap); return err; }
static void __exit br_deinit(void) { rcu_assign_pointer(br_stp_sap->rcv_func, NULL); br_netlink_fini(); br_netfilter_fini(); unregister_netdevice_notifier(&br_device_notifier); brioctl_set(NULL); br_cleanup_bridges(); synchronize_net(); llc_sap_put(br_stp_sap); br_fdb_get_hook = NULL; br_fdb_put_hook = NULL; br_handle_frame_hook = NULL; br_fdb_fini(); }
/** * llc_ui_autoport - provide dynamically allocate SAP number * * Provide the caller with a dynamically allocated SAP number according * to the rules that are set in this function. Returns: 0, upon failure, * SAP number otherwise. */ static int llc_ui_autoport(void) { struct llc_sap *sap; int i, tries = 0; while (tries < LLC_SAP_DYN_TRIES) { for (i = llc_ui_sap_last_autoport; i < LLC_SAP_DYN_STOP; i += 2) { sap = llc_sap_find(i); if (!sap) { llc_ui_sap_last_autoport = i + 2; goto out; } llc_sap_put(sap); } llc_ui_sap_last_autoport = LLC_SAP_DYN_START; tries++; } i = 0; out: return i; }
/** * llc_rcv - 802.2 entry point from net lower layers * @skb: received pdu * @dev: device that receive pdu * @pt: packet type * * When the system receives a 802.2 frame this function is called. It * checks SAP and connection of received pdu and passes frame to * llc_{station,sap,conn}_rcv for sending to proper state machine. If * the frame is related to a busy connection (a connection is sending * data now), it queues this frame in the connection's backlog. */ int llc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct llc_sap *sap; struct llc_pdu_sn *pdu; int dest; int (*rcv)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); void (*sta_handler)(struct sk_buff *skb); void (*sap_handler)(struct llc_sap *sap, struct sk_buff *skb); if (!net_eq(dev_net(dev), &init_net)) goto drop; /* * When the interface is in promisc. mode, drop all the crap that it * receives, do not try to analyse it. */ if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) { dprintk("%s: PACKET_OTHERHOST\n", __func__); goto drop; } skb = skb_share_check(skb, GFP_ATOMIC); if (unlikely(!skb)) goto out; if (unlikely(!llc_fixup_skb(skb))) goto drop; pdu = llc_pdu_sn_hdr(skb); if (unlikely(!pdu->dsap)) /* NULL DSAP, refer to station */ goto handle_station; sap = llc_sap_find(pdu->dsap); if (unlikely(!sap)) {/* unknown SAP */ dprintk("%s: llc_sap_find(%02X) failed!\n", __func__, pdu->dsap); goto drop; } /* * First the upper layer protocols that don't need the full * LLC functionality */ rcv = rcu_dereference(sap->rcv_func); dest = llc_pdu_type(skb); sap_handler = dest ? ACCESS_ONCE(llc_type_handlers[dest - 1]) : NULL; if (unlikely(!sap_handler)) { if (rcv) rcv(skb, dev, pt, orig_dev); else kfree_skb(skb); } else { if (rcv) { struct sk_buff *cskb = skb_clone(skb, GFP_ATOMIC); if (cskb) rcv(cskb, dev, pt, orig_dev); } sap_handler(sap, skb); } llc_sap_put(sap); out: return 0; drop: kfree_skb(skb); goto out; handle_station: sta_handler = ACCESS_ONCE(llc_station_handler); if (!sta_handler) goto drop; sta_handler(skb); goto out; }
void unregister_8022_client(struct datalink_proto *proto) { llc_sap_put(proto->sap); kfree(proto); }