| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * net/tipc/discover.c | 
|  | 3 | * | 
|  | 4 | * Copyright (c) 2003-2006, 2014-2018, Ericsson AB | 
|  | 5 | * Copyright (c) 2005-2006, 2010-2011, Wind River Systems | 
|  | 6 | * All rights reserved. | 
|  | 7 | * | 
|  | 8 | * Redistribution and use in source and binary forms, with or without | 
|  | 9 | * modification, are permitted provided that the following conditions are met: | 
|  | 10 | * | 
|  | 11 | * 1. Redistributions of source code must retain the above copyright | 
|  | 12 | *    notice, this list of conditions and the following disclaimer. | 
|  | 13 | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | 14 | *    notice, this list of conditions and the following disclaimer in the | 
|  | 15 | *    documentation and/or other materials provided with the distribution. | 
|  | 16 | * 3. Neither the names of the copyright holders nor the names of its | 
|  | 17 | *    contributors may be used to endorse or promote products derived from | 
|  | 18 | *    this software without specific prior written permission. | 
|  | 19 | * | 
|  | 20 | * Alternatively, this software may be distributed under the terms of the | 
|  | 21 | * GNU General Public License ("GPL") version 2 as published by the Free | 
|  | 22 | * Software Foundation. | 
|  | 23 | * | 
|  | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
|  | 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
|  | 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | 
|  | 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 
|  | 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 
|  | 30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 
|  | 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 
|  | 32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
|  | 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 
|  | 34 | * POSSIBILITY OF SUCH DAMAGE. | 
|  | 35 | */ | 
|  | 36 |  | 
|  | 37 | #include "core.h" | 
|  | 38 | #include "node.h" | 
|  | 39 | #include "discover.h" | 
|  | 40 |  | 
|  | 41 | /* min delay during bearer start up */ | 
|  | 42 | #define TIPC_DISC_INIT	msecs_to_jiffies(125) | 
|  | 43 | /* max delay if bearer has no links */ | 
|  | 44 | #define TIPC_DISC_FAST	msecs_to_jiffies(1000) | 
|  | 45 | /* max delay if bearer has links */ | 
|  | 46 | #define TIPC_DISC_SLOW	msecs_to_jiffies(60000) | 
|  | 47 | /* indicates no timer in use */ | 
|  | 48 | #define TIPC_DISC_INACTIVE	0xffffffff | 
|  | 49 |  | 
|  | 50 | /** | 
|  | 51 | * struct tipc_discoverer - information about an ongoing link setup request | 
|  | 52 | * @bearer_id: identity of bearer issuing requests | 
|  | 53 | * @net: network namespace instance | 
|  | 54 | * @dest: destination address for request messages | 
|  | 55 | * @domain: network domain to which links can be established | 
|  | 56 | * @num_nodes: number of nodes currently discovered (i.e. with an active link) | 
|  | 57 | * @lock: spinlock for controlling access to requests | 
|  | 58 | * @skb: request message to be (repeatedly) sent | 
|  | 59 | * @timer: timer governing period between requests | 
|  | 60 | * @timer_intv: current interval between requests (in ms) | 
|  | 61 | */ | 
|  | 62 | struct tipc_discoverer { | 
|  | 63 | u32 bearer_id; | 
|  | 64 | struct tipc_media_addr dest; | 
|  | 65 | struct net *net; | 
|  | 66 | u32 domain; | 
|  | 67 | int num_nodes; | 
|  | 68 | spinlock_t lock; | 
|  | 69 | struct sk_buff *skb; | 
|  | 70 | struct timer_list timer; | 
|  | 71 | unsigned long timer_intv; | 
|  | 72 | }; | 
|  | 73 |  | 
|  | 74 | /** | 
|  | 75 | * tipc_disc_init_msg - initialize a link setup message | 
|  | 76 | * @net: the applicable net namespace | 
|  | 77 | * @type: message type (request or response) | 
|  | 78 | * @b: ptr to bearer issuing message | 
|  | 79 | */ | 
|  | 80 | static void tipc_disc_init_msg(struct net *net, struct sk_buff *skb, | 
|  | 81 | u32 mtyp,  struct tipc_bearer *b) | 
|  | 82 | { | 
|  | 83 | struct tipc_net *tn = tipc_net(net); | 
|  | 84 | u32 dest_domain = b->domain; | 
|  | 85 | struct tipc_msg *hdr; | 
|  | 86 |  | 
|  | 87 | hdr = buf_msg(skb); | 
|  | 88 | tipc_msg_init(tn->trial_addr, hdr, LINK_CONFIG, mtyp, | 
|  | 89 | MAX_H_SIZE, dest_domain); | 
|  | 90 | msg_set_size(hdr, MAX_H_SIZE + NODE_ID_LEN); | 
|  | 91 | msg_set_non_seq(hdr, 1); | 
|  | 92 | msg_set_node_sig(hdr, tn->random); | 
|  | 93 | msg_set_node_capabilities(hdr, TIPC_NODE_CAPABILITIES); | 
|  | 94 | msg_set_dest_domain(hdr, dest_domain); | 
|  | 95 | msg_set_bc_netid(hdr, tn->net_id); | 
|  | 96 | b->media->addr2msg(msg_media_addr(hdr), &b->addr); | 
|  | 97 | msg_set_node_id(hdr, tipc_own_id(net)); | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst, | 
|  | 101 | u32 src, u32 sugg_addr, | 
|  | 102 | struct tipc_media_addr *maddr, | 
|  | 103 | struct tipc_bearer *b) | 
|  | 104 | { | 
|  | 105 | struct tipc_msg *hdr; | 
|  | 106 | struct sk_buff *skb; | 
|  | 107 |  | 
|  | 108 | skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC); | 
|  | 109 | if (!skb) | 
|  | 110 | return; | 
|  | 111 | hdr = buf_msg(skb); | 
|  | 112 | tipc_disc_init_msg(net, skb, mtyp, b); | 
|  | 113 | msg_set_sugg_node_addr(hdr, sugg_addr); | 
|  | 114 | msg_set_dest_domain(hdr, dst); | 
|  | 115 | tipc_bearer_xmit_skb(net, b->identity, skb, maddr); | 
|  | 116 | } | 
|  | 117 |  | 
|  | 118 | /** | 
|  | 119 | * disc_dupl_alert - issue node address duplication alert | 
|  | 120 | * @b: pointer to bearer detecting duplication | 
|  | 121 | * @node_addr: duplicated node address | 
|  | 122 | * @media_addr: media address advertised by duplicated node | 
|  | 123 | */ | 
|  | 124 | static void disc_dupl_alert(struct tipc_bearer *b, u32 node_addr, | 
|  | 125 | struct tipc_media_addr *media_addr) | 
|  | 126 | { | 
|  | 127 | char media_addr_str[64]; | 
|  | 128 |  | 
|  | 129 | tipc_media_addr_printf(media_addr_str, sizeof(media_addr_str), | 
|  | 130 | media_addr); | 
|  | 131 | pr_warn("Duplicate %x using %s seen on <%s>\n", node_addr, | 
|  | 132 | media_addr_str, b->name); | 
|  | 133 | } | 
|  | 134 |  | 
|  | 135 | /* tipc_disc_addr_trial(): - handle an address uniqueness trial from peer | 
|  | 136 | * Returns true if message should be dropped by caller, i.e., if it is a | 
|  | 137 | * trial message or we are inside trial period. Otherwise false. | 
|  | 138 | */ | 
|  | 139 | static bool tipc_disc_addr_trial_msg(struct tipc_discoverer *d, | 
|  | 140 | struct tipc_media_addr *maddr, | 
|  | 141 | struct tipc_bearer *b, | 
|  | 142 | u32 dst, u32 src, | 
|  | 143 | u32 sugg_addr, | 
|  | 144 | u8 *peer_id, | 
|  | 145 | int mtyp) | 
|  | 146 | { | 
|  | 147 | struct net *net = d->net; | 
|  | 148 | struct tipc_net *tn = tipc_net(net); | 
|  | 149 | bool trial = time_before(jiffies, tn->addr_trial_end); | 
|  | 150 | u32 self = tipc_own_addr(net); | 
|  | 151 |  | 
|  | 152 | if (mtyp == DSC_TRIAL_FAIL_MSG) { | 
|  | 153 | if (!trial) | 
|  | 154 | return true; | 
|  | 155 |  | 
|  | 156 | /* Ignore if somebody else already gave new suggestion */ | 
|  | 157 | if (dst != tn->trial_addr) | 
|  | 158 | return true; | 
|  | 159 |  | 
|  | 160 | /* Otherwise update trial address and restart trial period */ | 
|  | 161 | tn->trial_addr = sugg_addr; | 
|  | 162 | msg_set_prevnode(buf_msg(d->skb), sugg_addr); | 
|  | 163 | tn->addr_trial_end = jiffies + msecs_to_jiffies(1000); | 
|  | 164 | return true; | 
|  | 165 | } | 
|  | 166 |  | 
|  | 167 | /* Apply trial address if we just left trial period */ | 
|  | 168 | if (!trial && !self) { | 
|  | 169 | tipc_sched_net_finalize(net, tn->trial_addr); | 
|  | 170 | msg_set_prevnode(buf_msg(d->skb), tn->trial_addr); | 
|  | 171 | msg_set_type(buf_msg(d->skb), DSC_REQ_MSG); | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | /* Accept regular link requests/responses only after trial period */ | 
|  | 175 | if (mtyp != DSC_TRIAL_MSG) | 
|  | 176 | return trial; | 
|  | 177 |  | 
|  | 178 | sugg_addr = tipc_node_try_addr(net, peer_id, src); | 
|  | 179 | if (sugg_addr) | 
|  | 180 | tipc_disc_msg_xmit(net, DSC_TRIAL_FAIL_MSG, src, | 
|  | 181 | self, sugg_addr, maddr, b); | 
|  | 182 | return true; | 
|  | 183 | } | 
|  | 184 |  | 
|  | 185 | /** | 
|  | 186 | * tipc_disc_rcv - handle incoming discovery message (request or response) | 
|  | 187 | * @net: applicable net namespace | 
|  | 188 | * @skb: buffer containing message | 
|  | 189 | * @b: bearer that message arrived on | 
|  | 190 | */ | 
|  | 191 | void tipc_disc_rcv(struct net *net, struct sk_buff *skb, | 
|  | 192 | struct tipc_bearer *b) | 
|  | 193 | { | 
|  | 194 | struct tipc_net *tn = tipc_net(net); | 
|  | 195 | struct tipc_msg *hdr = buf_msg(skb); | 
|  | 196 | u16 caps = msg_node_capabilities(hdr); | 
|  | 197 | bool legacy = tn->legacy_addr_format; | 
|  | 198 | u32 sugg = msg_sugg_node_addr(hdr); | 
|  | 199 | u32 signature = msg_node_sig(hdr); | 
|  | 200 | u8 peer_id[NODE_ID_LEN] = {0,}; | 
|  | 201 | u32 dst = msg_dest_domain(hdr); | 
|  | 202 | u32 net_id = msg_bc_netid(hdr); | 
|  | 203 | struct tipc_media_addr maddr; | 
|  | 204 | u32 src = msg_prevnode(hdr); | 
|  | 205 | u32 mtyp = msg_type(hdr); | 
|  | 206 | bool dupl_addr = false; | 
|  | 207 | bool respond = false; | 
|  | 208 | u32 self; | 
|  | 209 | int err; | 
|  | 210 |  | 
|  | 211 | skb_linearize(skb); | 
|  | 212 | hdr = buf_msg(skb); | 
|  | 213 |  | 
|  | 214 | if (caps & TIPC_NODE_ID128) | 
|  | 215 | memcpy(peer_id, msg_node_id(hdr), NODE_ID_LEN); | 
|  | 216 | else | 
|  | 217 | sprintf(peer_id, "%x", src); | 
|  | 218 |  | 
|  | 219 | err = b->media->msg2addr(b, &maddr, msg_media_addr(hdr)); | 
|  | 220 | kfree_skb(skb); | 
|  | 221 | if (err || maddr.broadcast) { | 
|  | 222 | pr_warn_ratelimited("Rcv corrupt discovery message\n"); | 
|  | 223 | return; | 
|  | 224 | } | 
|  | 225 | /* Ignore discovery messages from own node */ | 
|  | 226 | if (!memcmp(&maddr, &b->addr, sizeof(maddr))) | 
|  | 227 | return; | 
|  | 228 | if (net_id != tn->net_id) | 
|  | 229 | return; | 
|  | 230 | if (tipc_disc_addr_trial_msg(b->disc, &maddr, b, dst, | 
|  | 231 | src, sugg, peer_id, mtyp)) | 
|  | 232 | return; | 
|  | 233 | self = tipc_own_addr(net); | 
|  | 234 |  | 
|  | 235 | /* Message from somebody using this node's address */ | 
|  | 236 | if (in_own_node(net, src)) { | 
|  | 237 | disc_dupl_alert(b, self, &maddr); | 
|  | 238 | return; | 
|  | 239 | } | 
|  | 240 | if (!tipc_in_scope(legacy, dst, self)) | 
|  | 241 | return; | 
|  | 242 | if (!tipc_in_scope(legacy, b->domain, src)) | 
|  | 243 | return; | 
|  | 244 | tipc_node_check_dest(net, src, peer_id, b, caps, signature, | 
|  | 245 | &maddr, &respond, &dupl_addr); | 
|  | 246 | if (dupl_addr) | 
|  | 247 | disc_dupl_alert(b, src, &maddr); | 
|  | 248 | if (!respond) | 
|  | 249 | return; | 
|  | 250 | if (mtyp != DSC_REQ_MSG) | 
|  | 251 | return; | 
|  | 252 | tipc_disc_msg_xmit(net, DSC_RESP_MSG, src, self, 0, &maddr, b); | 
|  | 253 | } | 
|  | 254 |  | 
|  | 255 | /* tipc_disc_add_dest - increment set of discovered nodes | 
|  | 256 | */ | 
|  | 257 | void tipc_disc_add_dest(struct tipc_discoverer *d) | 
|  | 258 | { | 
|  | 259 | spin_lock_bh(&d->lock); | 
|  | 260 | d->num_nodes++; | 
|  | 261 | spin_unlock_bh(&d->lock); | 
|  | 262 | } | 
|  | 263 |  | 
|  | 264 | /* tipc_disc_remove_dest - decrement set of discovered nodes | 
|  | 265 | */ | 
|  | 266 | void tipc_disc_remove_dest(struct tipc_discoverer *d) | 
|  | 267 | { | 
|  | 268 | int intv, num; | 
|  | 269 |  | 
|  | 270 | spin_lock_bh(&d->lock); | 
|  | 271 | d->num_nodes--; | 
|  | 272 | num = d->num_nodes; | 
|  | 273 | intv = d->timer_intv; | 
|  | 274 | if (!num && (intv == TIPC_DISC_INACTIVE || intv > TIPC_DISC_FAST))  { | 
|  | 275 | d->timer_intv = TIPC_DISC_INIT; | 
|  | 276 | mod_timer(&d->timer, jiffies + d->timer_intv); | 
|  | 277 | } | 
|  | 278 | spin_unlock_bh(&d->lock); | 
|  | 279 | } | 
|  | 280 |  | 
|  | 281 | /* tipc_disc_timeout - send a periodic link setup request | 
|  | 282 | * Called whenever a link setup request timer associated with a bearer expires. | 
|  | 283 | * - Keep doubling time between sent request until limit is reached; | 
|  | 284 | * - Hold at fast polling rate if we don't have any associated nodes | 
|  | 285 | * - Otherwise hold at slow polling rate | 
|  | 286 | */ | 
|  | 287 | static void tipc_disc_timeout(struct timer_list *t) | 
|  | 288 | { | 
|  | 289 | struct tipc_discoverer *d = from_timer(d, t, timer); | 
|  | 290 | struct tipc_net *tn = tipc_net(d->net); | 
|  | 291 | struct tipc_media_addr maddr; | 
|  | 292 | struct sk_buff *skb = NULL; | 
|  | 293 | struct net *net = d->net; | 
|  | 294 | u32 bearer_id; | 
|  | 295 |  | 
|  | 296 | spin_lock_bh(&d->lock); | 
|  | 297 |  | 
|  | 298 | /* Stop searching if only desired node has been found */ | 
|  | 299 | if (tipc_node(d->domain) && d->num_nodes) { | 
|  | 300 | d->timer_intv = TIPC_DISC_INACTIVE; | 
|  | 301 | goto exit; | 
|  | 302 | } | 
|  | 303 |  | 
|  | 304 | /* Did we just leave trial period ? */ | 
|  | 305 | if (!time_before(jiffies, tn->addr_trial_end) && !tipc_own_addr(net)) { | 
|  | 306 | mod_timer(&d->timer, jiffies + TIPC_DISC_INIT); | 
|  | 307 | spin_unlock_bh(&d->lock); | 
|  | 308 | tipc_sched_net_finalize(net, tn->trial_addr); | 
|  | 309 | return; | 
|  | 310 | } | 
|  | 311 |  | 
|  | 312 | /* Adjust timeout interval according to discovery phase */ | 
|  | 313 | if (time_before(jiffies, tn->addr_trial_end)) { | 
|  | 314 | d->timer_intv = TIPC_DISC_INIT; | 
|  | 315 | } else { | 
|  | 316 | d->timer_intv *= 2; | 
|  | 317 | if (d->num_nodes && d->timer_intv > TIPC_DISC_SLOW) | 
|  | 318 | d->timer_intv = TIPC_DISC_SLOW; | 
|  | 319 | else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST) | 
|  | 320 | d->timer_intv = TIPC_DISC_FAST; | 
|  | 321 | msg_set_type(buf_msg(d->skb), DSC_REQ_MSG); | 
|  | 322 | msg_set_prevnode(buf_msg(d->skb), tn->trial_addr); | 
|  | 323 | } | 
|  | 324 |  | 
|  | 325 | mod_timer(&d->timer, jiffies + d->timer_intv); | 
|  | 326 | memcpy(&maddr, &d->dest, sizeof(maddr)); | 
|  | 327 | skb = skb_clone(d->skb, GFP_ATOMIC); | 
|  | 328 | bearer_id = d->bearer_id; | 
|  | 329 | exit: | 
|  | 330 | spin_unlock_bh(&d->lock); | 
|  | 331 | if (skb) | 
|  | 332 | tipc_bearer_xmit_skb(net, bearer_id, skb, &maddr); | 
|  | 333 | } | 
|  | 334 |  | 
|  | 335 | /** | 
|  | 336 | * tipc_disc_create - create object to send periodic link setup requests | 
|  | 337 | * @net: the applicable net namespace | 
|  | 338 | * @b: ptr to bearer issuing requests | 
|  | 339 | * @dest: destination address for request messages | 
|  | 340 | * @dest_domain: network domain to which links can be established | 
|  | 341 | * | 
|  | 342 | * Returns 0 if successful, otherwise -errno. | 
|  | 343 | */ | 
|  | 344 | int tipc_disc_create(struct net *net, struct tipc_bearer *b, | 
|  | 345 | struct tipc_media_addr *dest, struct sk_buff **skb) | 
|  | 346 | { | 
|  | 347 | struct tipc_net *tn = tipc_net(net); | 
|  | 348 | struct tipc_discoverer *d; | 
|  | 349 |  | 
|  | 350 | d = kmalloc(sizeof(*d), GFP_ATOMIC); | 
|  | 351 | if (!d) | 
|  | 352 | return -ENOMEM; | 
|  | 353 | d->skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC); | 
|  | 354 | if (!d->skb) { | 
|  | 355 | kfree(d); | 
|  | 356 | return -ENOMEM; | 
|  | 357 | } | 
|  | 358 | tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b); | 
|  | 359 |  | 
|  | 360 | /* Do we need an address trial period first ? */ | 
|  | 361 | if (!tipc_own_addr(net)) { | 
|  | 362 | tn->addr_trial_end = jiffies + msecs_to_jiffies(1000); | 
|  | 363 | msg_set_type(buf_msg(d->skb), DSC_TRIAL_MSG); | 
|  | 364 | } | 
|  | 365 | memcpy(&d->dest, dest, sizeof(*dest)); | 
|  | 366 | d->net = net; | 
|  | 367 | d->bearer_id = b->identity; | 
|  | 368 | d->domain = b->domain; | 
|  | 369 | d->num_nodes = 0; | 
|  | 370 | d->timer_intv = TIPC_DISC_INIT; | 
|  | 371 | spin_lock_init(&d->lock); | 
|  | 372 | timer_setup(&d->timer, tipc_disc_timeout, 0); | 
|  | 373 | mod_timer(&d->timer, jiffies + d->timer_intv); | 
|  | 374 | b->disc = d; | 
|  | 375 | *skb = skb_clone(d->skb, GFP_ATOMIC); | 
|  | 376 | return 0; | 
|  | 377 | } | 
|  | 378 |  | 
|  | 379 | /** | 
|  | 380 | * tipc_disc_delete - destroy object sending periodic link setup requests | 
|  | 381 | * @d: ptr to link duest structure | 
|  | 382 | */ | 
|  | 383 | void tipc_disc_delete(struct tipc_discoverer *d) | 
|  | 384 | { | 
|  | 385 | del_timer_sync(&d->timer); | 
|  | 386 | kfree_skb(d->skb); | 
|  | 387 | kfree(d); | 
|  | 388 | } | 
|  | 389 |  | 
|  | 390 | /** | 
|  | 391 | * tipc_disc_reset - reset object to send periodic link setup requests | 
|  | 392 | * @net: the applicable net namespace | 
|  | 393 | * @b: ptr to bearer issuing requests | 
|  | 394 | * @dest_domain: network domain to which links can be established | 
|  | 395 | */ | 
|  | 396 | void tipc_disc_reset(struct net *net, struct tipc_bearer *b) | 
|  | 397 | { | 
|  | 398 | struct tipc_discoverer *d = b->disc; | 
|  | 399 | struct tipc_media_addr maddr; | 
|  | 400 | struct sk_buff *skb; | 
|  | 401 |  | 
|  | 402 | spin_lock_bh(&d->lock); | 
|  | 403 | tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b); | 
|  | 404 | d->net = net; | 
|  | 405 | d->bearer_id = b->identity; | 
|  | 406 | d->domain = b->domain; | 
|  | 407 | d->num_nodes = 0; | 
|  | 408 | d->timer_intv = TIPC_DISC_INIT; | 
|  | 409 | memcpy(&maddr, &d->dest, sizeof(maddr)); | 
|  | 410 | mod_timer(&d->timer, jiffies + d->timer_intv); | 
|  | 411 | skb = skb_clone(d->skb, GFP_ATOMIC); | 
|  | 412 | spin_unlock_bh(&d->lock); | 
|  | 413 | if (skb) | 
|  | 414 | tipc_bearer_xmit_skb(net, b->identity, skb, &maddr); | 
|  | 415 | } |