Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[IrDA]: Netlink layer.

First IrDA configuration netlink layer implementation.
Currently, we only support the set/get mode commands.

Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Samuel Ortiz and committed by
David S. Miller
89da1ecf 8c644623

+247 -5
+27
include/linux/irda.h
··· 216 216 #define ifr_dtr ifr_ifru.ifru_line.dtr 217 217 #define ifr_rts ifr_ifru.ifru_line.rts 218 218 219 + 220 + /* IrDA netlink definitions */ 221 + #define IRDA_NL_NAME "irda" 222 + #define IRDA_NL_VERSION 1 223 + 224 + enum irda_nl_commands { 225 + IRDA_NL_CMD_UNSPEC, 226 + IRDA_NL_CMD_SET_MODE, 227 + IRDA_NL_CMD_GET_MODE, 228 + 229 + __IRDA_NL_CMD_AFTER_LAST 230 + }; 231 + #define IRDA_NL_CMD_MAX (__IRDA_NL_CMD_AFTER_LAST - 1) 232 + 233 + enum nl80211_attrs { 234 + IRDA_NL_ATTR_UNSPEC, 235 + IRDA_NL_ATTR_IFNAME, 236 + IRDA_NL_ATTR_MODE, 237 + 238 + __IRDA_NL_ATTR_AFTER_LAST 239 + }; 240 + #define IRDA_NL_ATTR_MAX (__IRDA_NL_ATTR_AFTER_LAST - 1) 241 + 242 + /* IrDA modes */ 243 + #define IRDA_MODE_PRIMARY 0x1 244 + #define IRDA_MODE_SECONDARY 0x2 245 + 219 246 #endif /* KERNEL_IRDA_H */ 220 247 221 248
+3
include/net/irda/irda.h
··· 125 125 extern int irsock_init(void); 126 126 extern void irsock_cleanup(void); 127 127 128 + extern int irda_nl_register(void); 129 + extern void irda_nl_unregister(void); 130 + 128 131 extern int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, 129 132 struct packet_type *ptype, 130 133 struct net_device *orig_dev);
+2
include/net/irda/irlap.h
··· 208 208 int xbofs_delay; /* Nr of XBOF's used to MTT */ 209 209 int bofs_count; /* Negotiated extra BOFs */ 210 210 int next_bofs; /* Negotiated extra BOFs after next frame */ 211 + 212 + int mode; /* IrLAP mode (primary, secondary or monitor) */ 211 213 }; 212 214 213 215 /*
+1 -1
net/irda/Makefile
··· 10 10 irda-y := iriap.o iriap_event.o irlmp.o irlmp_event.o irlmp_frame.o \ 11 11 irlap.o irlap_event.o irlap_frame.o timer.o qos.o irqueue.o \ 12 12 irttp.o irda_device.o irias_object.o wrapper.o af_irda.o \ 13 - discovery.o parameters.o irmod.o 13 + discovery.o parameters.o irnetlink.o irmod.o 14 14 irda-$(CONFIG_PROC_FS) += irproc.o 15 15 irda-$(CONFIG_SYSCTL) += irsysctl.o
+44 -4
net/irda/irmod.c
··· 88 88 */ 89 89 static int __init irda_init(void) 90 90 { 91 + int ret = 0; 92 + 91 93 IRDA_DEBUG(0, "%s()\n", __FUNCTION__); 92 94 93 95 /* Lower layer of the stack */ 94 96 irlmp_init(); 95 97 irlap_init(); 96 98 99 + /* Driver/dongle support */ 100 + irda_device_init(); 101 + 97 102 /* Higher layers of the stack */ 98 103 iriap_init(); 99 104 irttp_init(); 100 - irsock_init(); 105 + ret = irsock_init(); 106 + if (ret < 0) 107 + goto out_err_1; 101 108 102 109 /* Add IrDA packet type (Start receiving packets) */ 103 110 dev_add_pack(&irda_packet_type); ··· 114 107 irda_proc_register(); 115 108 #endif 116 109 #ifdef CONFIG_SYSCTL 117 - irda_sysctl_register(); 110 + ret = irda_sysctl_register(); 111 + if (ret < 0) 112 + goto out_err_2; 118 113 #endif 119 114 120 - /* Driver/dongle support */ 121 - irda_device_init(); 115 + ret = irda_nl_register(); 116 + if (ret < 0) 117 + goto out_err_3; 122 118 123 119 return 0; 120 + 121 + out_err_3: 122 + #ifdef CONFIG_SYSCTL 123 + irda_sysctl_unregister(); 124 + #endif 125 + out_err_2: 126 + #ifdef CONFIG_PROC_FS 127 + irda_proc_unregister(); 128 + #endif 129 + 130 + /* Remove IrDA packet type (stop receiving packets) */ 131 + dev_remove_pack(&irda_packet_type); 132 + 133 + /* Remove higher layers */ 134 + irsock_cleanup(); 135 + out_err_1: 136 + irttp_cleanup(); 137 + iriap_cleanup(); 138 + 139 + /* Remove lower layers */ 140 + irda_device_cleanup(); 141 + irlap_cleanup(); /* Must be done before irlmp_cleanup()! DB */ 142 + 143 + /* Remove middle layer */ 144 + irlmp_cleanup(); 145 + 146 + 147 + return ret; 124 148 } 125 149 126 150 /* ··· 163 125 static void __exit irda_cleanup(void) 164 126 { 165 127 /* Remove External APIs */ 128 + irda_nl_unregister(); 129 + 166 130 #ifdef CONFIG_SYSCTL 167 131 irda_sysctl_unregister(); 168 132 #endif
+170
net/irda/irnetlink.c
··· 1 + /* 2 + * IrDA netlink layer, for stack configuration. 3 + * 4 + * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz> 5 + * 6 + * Partly based on the 802.11 nelink implementation 7 + * (see net/wireless/nl80211.c) which is: 8 + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 9 + * 10 + * This program is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License version 2 as 12 + * published by the Free Software Foundation. 13 + * 14 + */ 15 + 16 + #include <linux/socket.h> 17 + #include <linux/irda.h> 18 + #include <net/sock.h> 19 + #include <net/irda/irda.h> 20 + #include <net/irda/irlap.h> 21 + #include <net/genetlink.h> 22 + 23 + 24 + 25 + static struct genl_family irda_nl_family = { 26 + .id = GENL_ID_GENERATE, 27 + .name = IRDA_NL_NAME, 28 + .hdrsize = 0, 29 + .version = IRDA_NL_VERSION, 30 + .maxattr = IRDA_NL_CMD_MAX, 31 + }; 32 + 33 + static struct net_device * ifname_to_netdev(struct genl_info *info) 34 + { 35 + char * ifname; 36 + 37 + if (!info->attrs[IRDA_NL_ATTR_IFNAME]) 38 + return NULL; 39 + 40 + ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]); 41 + 42 + IRDA_DEBUG(5, "%s(): Looking for %s\n", __FUNCTION__, ifname); 43 + 44 + return dev_get_by_name(ifname); 45 + } 46 + 47 + static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info) 48 + { 49 + struct net_device * dev; 50 + struct irlap_cb * irlap; 51 + u32 mode; 52 + 53 + if (!info->attrs[IRDA_NL_ATTR_MODE]) 54 + return -EINVAL; 55 + 56 + mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]); 57 + 58 + IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __FUNCTION__, mode); 59 + 60 + dev = ifname_to_netdev(info); 61 + if (!dev) 62 + return -ENODEV; 63 + 64 + irlap = (struct irlap_cb *)dev->atalk_ptr; 65 + if (!irlap) { 66 + dev_put(dev); 67 + return -ENODEV; 68 + } 69 + 70 + irlap->mode = mode; 71 + 72 + dev_put(dev); 73 + 74 + return 0; 75 + } 76 + 77 + static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info) 78 + { 79 + struct net_device * dev; 80 + struct irlap_cb * irlap; 81 + struct sk_buff *msg; 82 + void *hdr; 83 + int ret = -ENOBUFS; 84 + 85 + dev = ifname_to_netdev(info); 86 + if (!dev) 87 + return -ENODEV; 88 + 89 + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 90 + if (!msg) { 91 + dev_put(dev); 92 + return -ENOMEM; 93 + } 94 + 95 + irlap = (struct irlap_cb *)dev->atalk_ptr; 96 + if (!irlap) { 97 + ret = -ENODEV; 98 + goto err_out; 99 + } 100 + 101 + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, 102 + &irda_nl_family, 0, IRDA_NL_CMD_GET_MODE); 103 + if (IS_ERR(hdr)) { 104 + ret = PTR_ERR(hdr); 105 + goto err_out; 106 + } 107 + 108 + if(nla_put_string(msg, IRDA_NL_ATTR_IFNAME, 109 + dev->name)); 110 + goto err_out; 111 + 112 + if(nla_put_u32(msg, IRDA_NL_ATTR_MODE, irlap->mode)) 113 + goto err_out; 114 + 115 + genlmsg_end(msg, hdr); 116 + 117 + return genlmsg_unicast(msg, info->snd_pid); 118 + 119 + err_out: 120 + nlmsg_free(msg); 121 + dev_put(dev); 122 + 123 + return ret; 124 + } 125 + 126 + static struct nla_policy irda_nl_policy[IRDA_NL_ATTR_MAX + 1] = { 127 + [IRDA_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, 128 + .len = IFNAMSIZ-1 }, 129 + [IRDA_NL_ATTR_MODE] = { .type = NLA_U32 }, 130 + }; 131 + 132 + static struct genl_ops irda_nl_ops[] = { 133 + { 134 + .cmd = IRDA_NL_CMD_SET_MODE, 135 + .doit = irda_nl_set_mode, 136 + .policy = irda_nl_policy, 137 + .flags = GENL_ADMIN_PERM, 138 + }, 139 + { 140 + .cmd = IRDA_NL_CMD_GET_MODE, 141 + .doit = irda_nl_get_mode, 142 + .policy = irda_nl_policy, 143 + /* can be retrieved by unprivileged users */ 144 + }, 145 + 146 + }; 147 + 148 + int irda_nl_register(void) 149 + { 150 + int err, i; 151 + 152 + err = genl_register_family(&irda_nl_family); 153 + if (err) 154 + return err; 155 + 156 + for (i = 0; i < ARRAY_SIZE(irda_nl_ops); i++) { 157 + err = genl_register_ops(&irda_nl_family, &irda_nl_ops[i]); 158 + if (err) 159 + goto err_out; 160 + } 161 + return 0; 162 + err_out: 163 + genl_unregister_family(&irda_nl_family); 164 + return err; 165 + } 166 + 167 + void irda_nl_unregister(void) 168 + { 169 + genl_unregister_family(&irda_nl_family); 170 + }