1 /* 2 * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: 3 * 4 * Marek Lindner, Simon Wunderlich 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of version 2 of the GNU General Public 8 * License as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 * 02110-1301, USA 19 * 20 */ 21 22 #include "main.h" 23 #include "soft-interface.h" 24 #include "hard-interface.h" 25 #include "routing.h" 26 #include "send.h" 27 #include "bat_debugfs.h" 28 #include "translation-table.h" 29 #include "types.h" 30 #include "hash.h" 31 #include "gateway_common.h" 32 #include "gateway_client.h" 33 #include "send.h" 34 #include "bat_sysfs.h" 35 #include <linux/slab.h> 36 #include <linux/ethtool.h> 37 #include <linux/etherdevice.h> 38 #include <linux/if_vlan.h> 39 #include "unicast.h" 40 #include "routing.h" 41 42 43 static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); 44 static void bat_get_drvinfo(struct net_device *dev, 45 struct ethtool_drvinfo *info); 46 static u32 bat_get_msglevel(struct net_device *dev); 47 static void bat_set_msglevel(struct net_device *dev, u32 value); 48 static u32 bat_get_link(struct net_device *dev); 49 static u32 bat_get_rx_csum(struct net_device *dev); 50 static int bat_set_rx_csum(struct net_device *dev, u32 data); 51 52 static const struct ethtool_ops bat_ethtool_ops = { 53 .get_settings = bat_get_settings, 54 .get_drvinfo = bat_get_drvinfo, 55 .get_msglevel = bat_get_msglevel, 56 .set_msglevel = bat_set_msglevel, 57 .get_link = bat_get_link, 58 .get_rx_csum = bat_get_rx_csum, 59 .set_rx_csum = bat_set_rx_csum 60 }; 61 62 int my_skb_head_push(struct sk_buff *skb, unsigned int len) 63 { 64 int result; 65 66 /** 67 * TODO: We must check if we can release all references to non-payload 68 * data using skb_header_release in our skbs to allow skb_cow_header to 69 * work optimally. This means that those skbs are not allowed to read 70 * or write any data which is before the current position of skb->data 71 * after that call and thus allow other skbs with the same data buffer 72 * to write freely in that area. 73 */ 74 result = skb_cow_head(skb, len); 75 if (result < 0) 76 return result; 77 78 skb_push(skb, len); 79 return 0; 80 } 81 82 static void softif_neigh_free_ref(struct kref *refcount) 83 { 84 struct softif_neigh *softif_neigh; 85 86 softif_neigh = container_of(refcount, struct softif_neigh, refcount); 87 kfree(softif_neigh); 88 } 89 90 static void softif_neigh_free_rcu(struct rcu_head *rcu) 91 { 92 struct softif_neigh *softif_neigh; 93 94 softif_neigh = container_of(rcu, struct softif_neigh, rcu); 95 kref_put(&softif_neigh->refcount, softif_neigh_free_ref); 96 } 97 98 void softif_neigh_purge(struct bat_priv *bat_priv) 99 { 100 struct softif_neigh *softif_neigh, *softif_neigh_tmp; 101 struct hlist_node *node, *node_tmp; 102 103 spin_lock_bh(&bat_priv->softif_neigh_lock); 104 105 hlist_for_each_entry_safe(softif_neigh, node, node_tmp, 106 &bat_priv->softif_neigh_list, list) { 107 108 if ((!time_after(jiffies, softif_neigh->last_seen + 109 msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && 110 (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) 111 continue; 112 113 hlist_del_rcu(&softif_neigh->list); 114 115 if (bat_priv->softif_neigh == softif_neigh) { 116 bat_dbg(DBG_ROUTES, bat_priv, 117 "Current mesh exit point '%pM' vanished " 118 "(vid: %d).\n", 119 softif_neigh->addr, softif_neigh->vid); 120 softif_neigh_tmp = bat_priv->softif_neigh; 121 bat_priv->softif_neigh = NULL; 122 kref_put(&softif_neigh_tmp->refcount, 123 softif_neigh_free_ref); 124 } 125 126 call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); 127 } 128 129 spin_unlock_bh(&bat_priv->softif_neigh_lock); 130 } 131 132 static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, 133 uint8_t *addr, short vid) 134 { 135 struct softif_neigh *softif_neigh; 136 struct hlist_node *node; 137 138 rcu_read_lock(); 139 hlist_for_each_entry_rcu(softif_neigh, node, 140 &bat_priv->softif_neigh_list, list) { 141 if (memcmp(softif_neigh->addr, addr, ETH_ALEN) != 0) 142 continue; 143 144 if (softif_neigh->vid != vid) 145 continue; 146 147 softif_neigh->last_seen = jiffies; 148 goto found; 149 } 150 151 softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); 152 if (!softif_neigh) 153 goto out; 154 155 memcpy(softif_neigh->addr, addr, ETH_ALEN); 156 softif_neigh->vid = vid; 157 softif_neigh->last_seen = jiffies; 158 kref_init(&softif_neigh->refcount); 159 160 INIT_HLIST_NODE(&softif_neigh->list); 161 spin_lock_bh(&bat_priv->softif_neigh_lock); 162 hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); 163 spin_unlock_bh(&bat_priv->softif_neigh_lock); 164 165 found: 166 kref_get(&softif_neigh->refcount); 167 out: 168 rcu_read_unlock(); 169 return softif_neigh; 170 } 171 172 int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) 173 { 174 struct net_device *net_dev = (struct net_device *)seq->private; 175 struct bat_priv *bat_priv = netdev_priv(net_dev); 176 struct softif_neigh *softif_neigh; 177 struct hlist_node *node; 178 size_t buf_size, pos; 179 char *buff; 180 181 if (!bat_priv->primary_if) { 182 return seq_printf(seq, "BATMAN mesh %s disabled - " 183 "please specify interfaces to enable it\n", 184 net_dev->name); 185 } 186 187 seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); 188 189 buf_size = 1; 190 /* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */ 191 rcu_read_lock(); 192 hlist_for_each_entry_rcu(softif_neigh, node, 193 &bat_priv->softif_neigh_list, list) 194 buf_size += 30; 195 rcu_read_unlock(); 196 197 buff = kmalloc(buf_size, GFP_ATOMIC); 198 if (!buff) 199 return -ENOMEM; 200 201 buff[0] = '\0'; 202 pos = 0; 203 204 rcu_read_lock(); 205 hlist_for_each_entry_rcu(softif_neigh, node, 206 &bat_priv->softif_neigh_list, list) { 207 pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n", 208 bat_priv->softif_neigh == softif_neigh 209 ? "=>" : " ", softif_neigh->addr, 210 softif_neigh->vid); 211 } 212 rcu_read_unlock(); 213 214 seq_printf(seq, "%s", buff); 215 kfree(buff); 216 return 0; 217 } 218 219 static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, 220 short vid) 221 { 222 struct bat_priv *bat_priv = netdev_priv(dev); 223 struct ethhdr *ethhdr = (struct ethhdr *)skb->data; 224 struct batman_packet *batman_packet; 225 struct softif_neigh *softif_neigh, *softif_neigh_tmp; 226 227 if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) 228 batman_packet = (struct batman_packet *) 229 (skb->data + ETH_HLEN + VLAN_HLEN); 230 else 231 batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); 232 233 if (batman_packet->version != COMPAT_VERSION) 234 goto err; 235 236 if (batman_packet->packet_type != BAT_PACKET) 237 goto err; 238 239 if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) 240 goto err; 241 242 if (is_my_mac(batman_packet->orig)) 243 goto err; 244 245 softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); 246 247 if (!softif_neigh) 248 goto err; 249 250 if (bat_priv->softif_neigh == softif_neigh) 251 goto out; 252 253 /* we got a neighbor but its mac is 'bigger' than ours */ 254 if (memcmp(bat_priv->primary_if->net_dev->dev_addr, 255 softif_neigh->addr, ETH_ALEN) < 0) 256 goto out; 257 258 /* switch to new 'smallest neighbor' */ 259 if ((bat_priv->softif_neigh) && 260 (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, 261 ETH_ALEN) < 0)) { 262 bat_dbg(DBG_ROUTES, bat_priv, 263 "Changing mesh exit point from %pM (vid: %d) " 264 "to %pM (vid: %d).\n", 265 bat_priv->softif_neigh->addr, 266 bat_priv->softif_neigh->vid, 267 softif_neigh->addr, softif_neigh->vid); 268 softif_neigh_tmp = bat_priv->softif_neigh; 269 bat_priv->softif_neigh = softif_neigh; 270 kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref); 271 /* we need to hold the additional reference */ 272 goto err; 273 } 274 275 /* close own batX device and use softif_neigh as exit node */ 276 if ((!bat_priv->softif_neigh) && 277 (memcmp(softif_neigh->addr, 278 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { 279 bat_dbg(DBG_ROUTES, bat_priv, 280 "Setting mesh exit point to %pM (vid: %d).\n", 281 softif_neigh->addr, softif_neigh->vid); 282 bat_priv->softif_neigh = softif_neigh; 283 /* we need to hold the additional reference */ 284 goto err; 285 } 286 287 out: 288 kref_put(&softif_neigh->refcount, softif_neigh_free_ref); 289 err: 290 kfree_skb(skb); 291 return; 292 } 293 294 static int interface_open(struct net_device *dev) 295 { 296 netif_start_queue(dev); 297 return 0; 298 } 299 300 static int interface_release(struct net_device *dev) 301 { 302 netif_stop_queue(dev); 303 return 0; 304 } 305 306 static struct net_device_stats *interface_stats(struct net_device *dev) 307 { 308 struct bat_priv *bat_priv = netdev_priv(dev); 309 return &bat_priv->stats; 310 } 311 312 static int interface_set_mac_addr(struct net_device *dev, void *p) 313 { 314 struct bat_priv *bat_priv = netdev_priv(dev); 315 struct sockaddr *addr = p; 316 317 if (!is_valid_ether_addr(addr->sa_data)) 318 return -EADDRNOTAVAIL; 319 320 /* only modify hna-table if it has been initialised before */ 321 if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) { 322 hna_local_remove(bat_priv, dev->dev_addr, 323 "mac address changed"); 324 hna_local_add(dev, addr->sa_data); 325 } 326 327 memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); 328 return 0; 329 } 330 331 static int interface_change_mtu(struct net_device *dev, int new_mtu) 332 { 333 /* check ranges */ 334 if ((new_mtu < 68) || (new_mtu > hardif_min_mtu(dev))) 335 return -EINVAL; 336 337 dev->mtu = new_mtu; 338 339 return 0; 340 } 341 342 int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) 343 { 344 struct ethhdr *ethhdr = (struct ethhdr *)skb->data; 345 struct bat_priv *bat_priv = netdev_priv(soft_iface); 346 struct bcast_packet *bcast_packet; 347 struct vlan_ethhdr *vhdr; 348 int data_len = skb->len, ret; 349 short vid = -1; 350 bool do_bcast = false; 351 352 if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) 353 goto dropped; 354 355 soft_iface->trans_start = jiffies; 356 357 switch (ntohs(ethhdr->h_proto)) { 358 case ETH_P_8021Q: 359 vhdr = (struct vlan_ethhdr *)skb->data; 360 vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; 361 362 if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) 363 break; 364 365 /* fall through */ 366 case ETH_P_BATMAN: 367 softif_batman_recv(skb, soft_iface, vid); 368 goto end; 369 } 370 371 /** 372 * if we have a another chosen mesh exit node in range 373 * it will transport the packets to the mesh 374 */ 375 if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) 376 goto dropped; 377 378 /* TODO: check this for locks */ 379 hna_local_add(soft_iface, ethhdr->h_source); 380 381 if (is_multicast_ether_addr(ethhdr->h_dest)) { 382 ret = gw_is_target(bat_priv, skb); 383 384 if (ret < 0) 385 goto dropped; 386 387 if (ret == 0) 388 do_bcast = true; 389 } 390 391 /* ethernet packet should be broadcasted */ 392 if (do_bcast) { 393 if (!bat_priv->primary_if) 394 goto dropped; 395 396 if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) 397 goto dropped; 398 399 bcast_packet = (struct bcast_packet *)skb->data; 400 bcast_packet->version = COMPAT_VERSION; 401 bcast_packet->ttl = TTL; 402 403 /* batman packet type: broadcast */ 404 bcast_packet->packet_type = BAT_BCAST; 405 406 /* hw address of first interface is the orig mac because only 407 * this mac is known throughout the mesh */ 408 memcpy(bcast_packet->orig, 409 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); 410 411 /* set broadcast sequence number */ 412 bcast_packet->seqno = 413 htonl(atomic_inc_return(&bat_priv->bcast_seqno)); 414 415 add_bcast_packet_to_list(bat_priv, skb); 416 417 /* a copy is stored in the bcast list, therefore removing 418 * the original skb. */ 419 kfree_skb(skb); 420 421 /* unicast packet */ 422 } else { 423 ret = unicast_send_skb(skb, bat_priv); 424 if (ret != 0) 425 goto dropped_freed; 426 } 427 428 bat_priv->stats.tx_packets++; 429 bat_priv->stats.tx_bytes += data_len; 430 goto end; 431 432 dropped: 433 kfree_skb(skb); 434 dropped_freed: 435 bat_priv->stats.tx_dropped++; 436 end: 437 return NETDEV_TX_OK; 438 } 439 440 void interface_rx(struct net_device *soft_iface, 441 struct sk_buff *skb, struct batman_if *recv_if, 442 int hdr_size) 443 { 444 struct bat_priv *bat_priv = netdev_priv(soft_iface); 445 struct unicast_packet *unicast_packet; 446 struct ethhdr *ethhdr; 447 struct vlan_ethhdr *vhdr; 448 short vid = -1; 449 int ret; 450 451 /* check if enough space is available for pulling, and pull */ 452 if (!pskb_may_pull(skb, hdr_size)) 453 goto dropped; 454 455 skb_pull_rcsum(skb, hdr_size); 456 skb_reset_mac_header(skb); 457 458 ethhdr = (struct ethhdr *)skb_mac_header(skb); 459 460 switch (ntohs(ethhdr->h_proto)) { 461 case ETH_P_8021Q: 462 vhdr = (struct vlan_ethhdr *)skb->data; 463 vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; 464 465 if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) 466 break; 467 468 /* fall through */ 469 case ETH_P_BATMAN: 470 goto dropped; 471 } 472 473 /** 474 * if we have a another chosen mesh exit node in range 475 * it will transport the packets to the non-mesh network 476 */ 477 if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { 478 skb_push(skb, hdr_size); 479 unicast_packet = (struct unicast_packet *)skb->data; 480 481 if ((unicast_packet->packet_type != BAT_UNICAST) && 482 (unicast_packet->packet_type != BAT_UNICAST_FRAG)) 483 goto dropped; 484 485 skb_reset_mac_header(skb); 486 487 memcpy(unicast_packet->dest, 488 bat_priv->softif_neigh->addr, ETH_ALEN); 489 ret = route_unicast_packet(skb, recv_if, hdr_size); 490 if (ret == NET_RX_DROP) 491 goto dropped; 492 493 goto out; 494 } 495 496 /* skb->dev & skb->pkt_type are set here */ 497 if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) 498 goto dropped; 499 skb->protocol = eth_type_trans(skb, soft_iface); 500 501 /* should not be neccesary anymore as we use skb_pull_rcsum() 502 * TODO: please verify this and remove this TODO 503 * -- Dec 21st 2009, Simon Wunderlich */ 504 505 /* skb->ip_summed = CHECKSUM_UNNECESSARY;*/ 506 507 bat_priv->stats.rx_packets++; 508 bat_priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr); 509 510 soft_iface->last_rx = jiffies; 511 512 netif_rx(skb); 513 return; 514 515 dropped: 516 kfree_skb(skb); 517 out: 518 return; 519 } 520 521 #ifdef HAVE_NET_DEVICE_OPS 522 static const struct net_device_ops bat_netdev_ops = { 523 .ndo_open = interface_open, 524 .ndo_stop = interface_release, 525 .ndo_get_stats = interface_stats, 526 .ndo_set_mac_address = interface_set_mac_addr, 527 .ndo_change_mtu = interface_change_mtu, 528 .ndo_start_xmit = interface_tx, 529 .ndo_validate_addr = eth_validate_addr 530 }; 531 #endif 532 533 static void interface_setup(struct net_device *dev) 534 { 535 struct bat_priv *priv = netdev_priv(dev); 536 char dev_addr[ETH_ALEN]; 537 538 ether_setup(dev); 539 540 #ifdef HAVE_NET_DEVICE_OPS 541 dev->netdev_ops = &bat_netdev_ops; 542 #else 543 dev->open = interface_open; 544 dev->stop = interface_release; 545 dev->get_stats = interface_stats; 546 dev->set_mac_address = interface_set_mac_addr; 547 dev->change_mtu = interface_change_mtu; 548 dev->hard_start_xmit = interface_tx; 549 #endif 550 dev->destructor = free_netdev; 551 552 /** 553 * can't call min_mtu, because the needed variables 554 * have not been initialized yet 555 */ 556 dev->mtu = ETH_DATA_LEN; 557 dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the 558 * skbuff for our header */ 559 560 /* generate random address */ 561 random_ether_addr(dev_addr); 562 memcpy(dev->dev_addr, dev_addr, ETH_ALEN); 563 564 SET_ETHTOOL_OPS(dev, &bat_ethtool_ops); 565 566 memset(priv, 0, sizeof(struct bat_priv)); 567 } 568 569 struct net_device *softif_create(char *name) 570 { 571 struct net_device *soft_iface; 572 struct bat_priv *bat_priv; 573 int ret; 574 575 soft_iface = alloc_netdev(sizeof(struct bat_priv) , name, 576 interface_setup); 577 578 if (!soft_iface) { 579 pr_err("Unable to allocate the batman interface: %s\n", name); 580 goto out; 581 } 582 583 ret = register_netdev(soft_iface); 584 if (ret < 0) { 585 pr_err("Unable to register the batman interface '%s': %i\n", 586 name, ret); 587 goto free_soft_iface; 588 } 589 590 bat_priv = netdev_priv(soft_iface); 591 592 atomic_set(&bat_priv->aggregated_ogms, 1); 593 atomic_set(&bat_priv->bonding, 0); 594 atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); 595 atomic_set(&bat_priv->gw_mode, GW_MODE_OFF); 596 atomic_set(&bat_priv->gw_sel_class, 20); 597 atomic_set(&bat_priv->gw_bandwidth, 41); 598 atomic_set(&bat_priv->orig_interval, 1000); 599 atomic_set(&bat_priv->hop_penalty, 10); 600 atomic_set(&bat_priv->log_level, 0); 601 atomic_set(&bat_priv->fragmentation, 1); 602 atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN); 603 atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN); 604 605 atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); 606 atomic_set(&bat_priv->bcast_seqno, 1); 607 atomic_set(&bat_priv->hna_local_changed, 0); 608 609 bat_priv->primary_if = NULL; 610 bat_priv->num_ifaces = 0; 611 bat_priv->softif_neigh = NULL; 612 613 ret = sysfs_add_meshif(soft_iface); 614 if (ret < 0) 615 goto unreg_soft_iface; 616 617 ret = debugfs_add_meshif(soft_iface); 618 if (ret < 0) 619 goto unreg_sysfs; 620 621 ret = mesh_init(soft_iface); 622 if (ret < 0) 623 goto unreg_debugfs; 624 625 return soft_iface; 626 627 unreg_debugfs: 628 debugfs_del_meshif(soft_iface); 629 unreg_sysfs: 630 sysfs_del_meshif(soft_iface); 631 unreg_soft_iface: 632 unregister_netdev(soft_iface); 633 return NULL; 634 635 free_soft_iface: 636 free_netdev(soft_iface); 637 out: 638 return NULL; 639 } 640 641 void softif_destroy(struct net_device *soft_iface) 642 { 643 debugfs_del_meshif(soft_iface); 644 sysfs_del_meshif(soft_iface); 645 mesh_free(soft_iface); 646 unregister_netdevice(soft_iface); 647 } 648 649 /* ethtool */ 650 static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 651 { 652 cmd->supported = 0; 653 cmd->advertising = 0; 654 cmd->speed = SPEED_10; 655 cmd->duplex = DUPLEX_FULL; 656 cmd->port = PORT_TP; 657 cmd->phy_address = 0; 658 cmd->transceiver = XCVR_INTERNAL; 659 cmd->autoneg = AUTONEG_DISABLE; 660 cmd->maxtxpkt = 0; 661 cmd->maxrxpkt = 0; 662 663 return 0; 664 } 665 666 static void bat_get_drvinfo(struct net_device *dev, 667 struct ethtool_drvinfo *info) 668 { 669 strcpy(info->driver, "B.A.T.M.A.N. advanced"); 670 strcpy(info->version, SOURCE_VERSION); 671 strcpy(info->fw_version, "N/A"); 672 strcpy(info->bus_info, "batman"); 673 } 674 675 static u32 bat_get_msglevel(struct net_device *dev) 676 { 677 return -EOPNOTSUPP; 678 } 679 680 static void bat_set_msglevel(struct net_device *dev, u32 value) 681 { 682 } 683 684 static u32 bat_get_link(struct net_device *dev) 685 { 686 return 1; 687 } 688 689 static u32 bat_get_rx_csum(struct net_device *dev) 690 { 691 return 0; 692 } 693 694 static int bat_set_rx_csum(struct net_device *dev, u32 data) 695 { 696 return -EOPNOTSUPP; 697 } 698